Unknown sow_line_id fails loudly (update-absow / mark-inspected)

Incident (2026-08-07): Kilroy called POST /whatsapp/inspection/update-absow with a portal UUID instead of the SOW line’s smartsuite_id. The response echoed absow_qty and looked successful, but nothing persisted: ss_read.get_record returned {} without raising, and supabase_write_service.update_sow_line matched zero rows and warn-skipped.

Fix (entirely-api 1c39d97):

  • services/field_inspection.py — new SowLineNotFoundError(LookupError); update_absow and mark_inspected raise it when get_record misses. routes/whatsapp.py maps it to HTTP 404 with a message that names the wrong-key shape (“pass the smartsuite_id, not a portal UUID”).
  • services/supabase_write_service.pyupdate_record gains missing_ok: bool = True (default keeps the legacy SmartSuite-era warn-and-skip for other tables); update_sow_line passes missing_ok=False, so a zero-row match raises RecordNotFoundError.
  • ABSoW proposal apply already catches per-line exceptions, so it now records the error instead of silently “applying”.
  • Tests: tests/test_sow_line_not_found.py (6 cases). Full suite 605 passed.

Verified live: replayed the UUID shape against the rebuilt API → 404 with the actionable detail; api/worker/scheduler all rebuilt per the §3 runbook.

Upstream source (traced 2026-08-07, same day)

Kilroy’s transcript (Hermes session 20260807_092129_da4db010, MAN-9162 on-site WTR confirmation) shows the UUIDs came from GET /portal/projects/{record_id}.sow_lines[].id. That route builds sow_lines from two branches: SS-linked lines exposed id = smartsuite_id, but the Supabase-supplement branch (reparse/enrichment-created lines, exactly what MAN-9162’s WTR lines are) exposed id = the UUID primary key. Same array, two key namespaces.

Fixes:

  • entirely-api 2d592f8 — supplement branch now exposes smartsuite_id or id (all prod sow_lines rows have smartsuite_id, 0 NULLs; portal-v2 only uses these ids for display, verified). Live-verified on MAN-9162: all five lines now return 24-char hex ids.
  • Kilroy skill unlikely-field/SKILL.md — ID-namespace warning added at the update-absow step (take IDs from /inspection/psow/, never portal endpoints or Supabase id).
  • Kilroy SOUL.md — two additions: the verify-don’t-guess standing rule Dustin requested mid-session (its in-session memory save had failed on a full memory file and was never retried), and a Supabase READ-ONLY rule (Kilroy cleared the false modified flags via direct raw_data updates, bypassing the write service).

Related: field-inspection, supabase-write-service, portal-projects