Milestone 3 of 8
Classify valid, missing, and rejected rows
Apply the fixed first-failure order and give every source row one status with preserved evidence.
The parser now preserves every source row. This milestone gives each row one clear status without hiding the reason for an exclusion.
Milestone goal
Classify parsed rows as valid, missing, or rejected under one fixed
first-failure order. Preserve the raw fields and source line in every result.
Classification interface
Implement a function such as:
Each returned record must retain:
source_line, record_id, sensor, observation, reading_raw, unit,
status, reason, reason_detail
For a valid row, also include a finite numeric reading value. For a missing
or rejected row, keep reading_raw and leave the parsed reading absent or
None; do not invent a replacement.
Apply the rules in order
Use this order for each parsed row:
- Row and column structure. A structurally incomplete record is rejected
as
malformed_row. - Record identity. An empty ID is
empty_record_id. A repeated ID isduplicate_record_idwhen it is not the first occurrence. The first occurrence continues through the remaining rules. - Sensor. Any value other than
northorsouthisunknown_sensor. - Observation. The value must parse as an integer in
0..19; otherwise useinvalid_observation. - Unit. The value must be exactly
deg_c; otherwise useunit_mismatch. - Reading. A blank value is
missing_reading. A non-numeric, non-finite, or out-of-range value is rejected asinvalid_readingorreading_out_of_range, as appropriate.
The first failed rule wins. A blank reading becomes missing only when all
earlier rules pass. A row with an unknown sensor and blank reading is
rejected, not missing.
Every non-valid record must carry a stable machine-readable reason and a
short reason_detail that names the failed rule. Use the same reason name for
the same failure across fixtures.
Deliverables
Produce:
- the classifier in
src/pipeline.pyor a small module it imports; - a classified record collection that still contains every source row;
- one table in the report showing at least one
valid, onemissing, and onerejectedrow with source line and reason; - the stable reason vocabulary used by the implementation.
Checks
Use the public fixture and boundary cases to verify:
- every input row produces exactly one classified record;
- the first duplicate is allowed to continue and a later duplicate is rejected;
- a blank reading is
missingonly after earlier fields pass; - an invalid numeric value and an out-of-range value retain different reasons;
- an unknown sensor and a unit mismatch are not silently corrected;
- when two rules fail, the earlier rule is the saved reason;
- source lines, raw fields, and IDs remain unchanged.
The checks can verify status and reason strings. They cannot prove that a reader understands why the first-failure order matters, so explain one multi-defect example in your report.
Review
Read the classified public fixture from top to bottom. Ask whether a reader
could reconstruct the decision for each excluded row from source_line, raw
fields, status, and reason_detail. If not, the record does not yet carry
enough evidence.
Next step
The next milestone writes three durable CSV partitions. It must serialize the classification without changing statuses, raw fields, IDs, or source lines.
HintFirst failure is a policy
HintMissing is not invalid
How to check your work
The supplied fixture includes a compact reason vocabulary and a deterministic first-failure implementation. Compare the public rows and boundary cases after your own classifier has produced evidence.