diff --git a/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/final-fix-report.md b/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/final-fix-report.md new file mode 100644 index 0000000..e775652 --- /dev/null +++ b/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/final-fix-report.md @@ -0,0 +1,33 @@ +# Final cross-feature fix wave report + +Base: `9ace0fb` +Code commit: `9ae498a` + +## Addressed blockers + +- Staged assembly now aggregates every ordered page read, uses first-nonempty header evidence, preserves every extracted line, persists line links and the complete canonical check list, and marks a candidate ready only when PO/site/supplier/item/check gates are satisfied. +- Added a two-page continuation regression proving that distinct lines on both pages survive aggregation. +- Manual assembly split/join now clears derived document identity, supplier/PO relations, items, checks, match evidence, candidate identity, and posting relation for every affected nonterminal candidate. New candidates start `needs_review`; posted/dismissed candidates remain protected. +- Added optional `global_page` to canonical pages, assigned during staged normalisation, with a batch-wide unique index. Posting and page proxy lookup use it. Legacy rows are remapped only when source ordinal/page identities are contiguous and unique; mixed or gapped rows fail closed. +- Added a missing-middle-page posting regression: persisted global pages 1 and 3 with candidate `[3]` selects page 3. + +## Verification evidence + +Commands run from the worktree: + +```text +npx vitest run src/lib/dn-pipeline/run-staged.test.ts src/lib/dn-pipeline/page-store.test.ts src/lib/dn-pipeline/normalise-source.test.ts src/lib/dn-pipeline/promote.test.ts src/lib/dn-pipeline/readiness.test.ts src/lib/dn-pipeline/assemble.test.ts "src/app/api/dn-batches/[id]/assembly/route.test.ts" "src/app/api/dn-batches/[id]/notes/[noteId]/post/route.test.ts" + 8 files passed, 89 tests passed +npm run typecheck + passed +python3 scripts/pb-add-dn-staged-ingestion.py --self-test + self-test: index replacement and idempotence passed +python3 scripts/pb-add-dn-staged-ingestion.py --dry-run + offline preview completed; no schema changes written +git diff --check + passed +``` + +## Residual risk + +The migration remains unapplied and `DN_STAGED_INGESTION_ENABLED` remains unchanged. Existing rows without `global_page` and with a source-page gap require manual repair/re-extraction; the posting path intentionally refuses to infer their identity. diff --git a/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/progress.md b/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/progress.md index 2fb1438..acdb98e 100644 --- a/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/progress.md +++ b/.superpowers/sdd/2026-09-18-hybrid-delivery-note-ingestion/progress.md @@ -167,3 +167,10 @@ Task 12: fix round 1/5 complete (7 addressed; code commit 2914eef; focused tests Task 12: fix round 1/5 migration follow-up complete (code commit 310219d; configured dry-run now passes before new collections exist) Task 12: fix round 2/5 complete (code commit 11bc1a4; 2 findings addressed; focused tests/typecheck/diff check passed) Task 12: fix round 3/5 complete (code commit eed128e; delivery-note audit identity bound; focused posting tests/typecheck/diff check passed) + +Final cross-feature fix wave: dispatched to /root/luna_final_fixes at base 9ace0fb +Final cross-feature fix wave: code complete (4 blockers addressed; commit 9ae498a) +Final cross-feature fix wave: focused verification passed — 8 files, 89 tests; npm run typecheck; migration --self-test; configured/offline migration --dry-run; git diff --check +Ruling: staged candidates must persist the aggregate page evidence, line links, and complete canonical checks before they can be ready_to_post — cost if wrong: more candidates enter review, but no incomplete candidate can pass the posting gate. +Ruling: global_page is an additive stable identity and legacy page remapping is allowed only when source ordinals/pages are contiguous and unambiguous — cost if wrong: old ambiguous rows require manual repair instead of risking the wrong scan page. +Ruling: manual split/join invalidates all derived candidate commercial/entity/match/check fields and requires recomputation — cost if wrong: an operator must wait for the staged runner, but stale PO links cannot be posted after page reassignment.