Milestone 2 of 8

Parse rows while preserving source identity

Read every row into a traceable raw record while keeping line numbers, cells, and structural failures visible.

The source contract names the fields. Now build a parser that carries those fields into Python without deciding yet whether a row is usable. Parsing and classification are separate because a malformed value is still evidence about the source.

Milestone goal

Read the supplied CSV into records that retain source line, raw field values, and record_id. Report structural failures explicitly and leave semantic validation for the next milestone.

Inputs and interface

Use data/raw_measurements.csv and the supplied constants in src/schema.py. Implement a small interface such as:

For every ordinary data row, return one record with this shape:

source_line is the one-based line location reported by the CSV reader. The raw mapping contains strings exactly as read, including "" for a blank reading. record_id is copied from the raw field only to make later traces easy to read; it is not yet accepted as valid.

Do not convert observation or reading here. Do not reject an unknown sensor, an invalid number, a unit mismatch, or a duplicate ID in the parser. Those are classification decisions.

Structural failures

Reject the file with a clear ValueError when the header is missing or differs from the supplied ordered header, or when the file cannot be opened as the declared UTF-8 CSV input. Without the expected header, field names cannot be assigned honestly.

A data row with a missing or extra column still needs a source status. Preserve its source line and raw cells in a structural-error record so the classifier can place it in rejected_records.csv with reason malformed_row. Do not silently pad, truncate, or reorder the cells, and do not stop before later rows have been represented.

Deliverables

Produce:

  • the parser in src/pipeline.py;
  • a saved raw-record preview or output/parsed_records.json containing every parsed row's source line, raw fields, and ID;
  • a short note in README.md or the milestone report describing the structural failure policy.

The exact internal function name may be reviewed with the workspace, but the record shape and preservation boundary are fixed.

Checks

Use the public fixture and at least one alternate small fixture to check that:

  • records remain in source order;
  • source lines are increasing and traceable;
  • raw numeric text is unchanged, including a blank reading;
  • every data row appears exactly once in the parsed result;
  • the exact header is required;
  • short and long rows retain their raw cells and become explicit structural records rather than disappearing or stopping the scan.

The parser may carry an unknown sensor or invalid numeric text forward. That is success at this boundary: the next milestone needs to see the evidence before it classifies the row.

Review

Inspect a row with a blank reading and a row with invalid numeric text. If the parser has already converted either value to None, 0, or nan, raw source evidence has been lost. Repair that boundary before continuing.

Next step

The classifier will consume these records and apply the first-failure order. It must not reopen the source file and create a second interpretation of the same row.

HintPreserve before interpreting
A raw field is useful even when its value is invalid. Store it first, then decide whether it can be converted.
HintLine numbers are evidence
Keep the source location with the record. A reason without a source line is difficult to audit in a file containing repeated values.

How to check your work

The supplied fixture shows one way to keep CSV parsing, structural errors, and raw records separate. Compare its behavior on the public fixture rather than copying its internal loops.

LLM PrimerParse rows while preserving source identityhttps://llmprimer.com/python/projects/inspect-and-validate-a-dataset/parse-rows-preserving-source-identity© 2026 LLM Primer