Planned-qty comparisons: quantity column, not raw_data
2026-07-30 (entirely-api a64031c) — sow_lines raw_data is a
creation-time snapshot; a 2026-07-30 audit found 16 live rows where
raw_data[SOW_QUANTITY] ≠ the quantity column (2026-04-28 qty batch +
intake-era rows updated columns only). Two consumers compared against raw:
- field_update_writer
_update_sow_line_from_field— modified-flag decision on field-reported as-builts - supabase_write_service
check_and_clear_sow_modified— auto-clear; had to move together with the writer, else stale raw would immediately undo a correctly-set flag
Both now read the denormalized quantity / as_built_qty columns with
raw_data fallback only when the column is NULL. SOW_MODIFIED still comes
from raw_data (no column exists). Regression tests:
tests/test_field_planned_qty_column.py (anchor: blkhse.541201 SUP-JOIST,
raw qty=1 vs column 12).
Rule: treat sow_lines raw_data as an immutable creation-time snapshot —
never compare or display from raw_data.title / raw_data[sbcvngks] when a
denormalized column exists. Related audit: all 60 raw-vs-column title
mismatches were stale raw, zero mislinks (report in
/home/claude/sow_title_audit_2026-07-30.md).