JSON represents objects, arrays, strings, numbers, booleans and null. JSONL stores one JSON value per physical line, making records streamable. Decoding JSON does not validate an application schema: a list is legal JSON but may not be a legal evaluation record.
Successful JSON decoding is only the first check, not evidence that the record is valid for this evaluator.
import json
row = json.loads('{"id":"case-1","score":0.5}')
print(row["id"], row["score"])
print(json.dumps(row, sort_keys=True, separators=(",", ":")))Keep the parser separate from command-line I/O. A CLI parses arguments, opens text files with an explicit encoding, delegates to library functions, and chooses exit status. Library functions accept iterables and return data; they should not print progress into a machine-readable output stream.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--seed", type=int, default=0)
args = parser.parse_args(["--seed", "7"])
print(args.seed)Our schema has exactly id and score. IDs are unique nonempty strings;
scores are finite real JSON numbers in [0,1], with bool excluded. Reject a
duplicate ID instead of counting a retry twice. Ignore blank physical lines,
but include them when reporting 1-based line numbers. Never silently skip a
malformed row; that can preferentially remove difficult examples.
Count original physical lines, including blanks, so the reported error points to the actual file location.
Stable exports specify key order and separators. allow_nan=False rejects
nonstandard NaN/infinity in serialized artifacts. The build returns canonical
row dictionaries in encounter order; sorted key serialization belongs in the
CLI or reporting layer. The final lab joins this boundary to a full local run.