fix: reconcile interrupted shutdown delivery without replay

Merged
JC
3d ago
+2555-111

[!TIP]
PR walkthrough: Open the visual walkthrough

Graceful shutdown could leave a journal failure without terminal evidence while SQL recorded an unknown outcome, blocking a restored native conversation. Recovery now reconciles matching interrupted work and admission fences without replaying the old prompt or inventing completion.

Changes

  • Mark the original child as stopping before adapter teardown, preserve deterministic provider failures, and drain terminal updates before closing the journal writer.
  • Preserve historical journal labels and SQL uncertainty while retiring authenticated interrupted work. Read stopped-journal submission metadata separately from proof that work was retired.
  • Use the same guarded reconciliation during restart, explicit Resume and admission to an already loaded native conversation. Require evidence that the original owner is dead; preserve independent live or unknown owners.
  • Resolve matching missing, stale or incomplete recovery metadata and blocks atomically. Complete a matching prepared restore checkpoint and clear only the matching legacy composer error.
  • Repair existing canonical initial and continuation prompts without inventing a user-message association. Preserve their actual dispatch-attempt identity, reject deleted or changed canonical rows, and persist an honest unknown outcome for proven interrupted dispatch.
  • Add real child shutdown, cross-store state-matrix, repeated recovery, retained-journal and transactional SQLite/PostgreSQL regressions. Keep original native conversations, hashes and event cursors intact.

Validation

Focused Go race checks cover producer shutdown, journal retirement, the 49-state-pair matrix, native lifecycle and SQL/orchestrator recovery. The four recovery regressions reported by CI now pass with race detection. Affected-package lint reported one nested-block warning; the correction and journal lint pass. CI also exposed empty reconstructed outcomes and internal prompts requiring nonexistent user-message rows. Both are fixed with passing focused SQL/orchestrator regressions; browser coverage now asserts restore without continuation replay. The remaining active-turn restart failure exposed initial prompts using execution IDs as dispatch attempts. That correlation is now preserved, with passing race regressions and a changed-attempt rejection control. A CI-exposed sidebar test substring collision now uses exact option names. Final head 1365fa26e3 passed all 55 CI checks, with zero unresolved review threads. Merged as bc0d3b9047.

Specification catalog and lint passed. Public recovery guidance is updated. All E2E and PostgreSQL validation run in CI; no local browser or E2E tests were run.

Checklist

  • One logical recovery change with regression coverage.
  • Public documentation impact checked and guidance updated.
  • Final-head CI and review-thread disposition complete.