A manual memory_consolidate MCP call wrote the page directly through the
consolidator and never touched session_consolidation_jobs, so a session
whose automatic SessionEnd job had reached the terminal `failed` state
(which claim_next never re-picks) kept showing `failed` even though the
operator had just consolidated it — a two-sources-of-truth inconsistency.
Add a writer method reconcile_session_consolidation_completed(session_id)
that flips a `failed`/`pending`/`superseded` row for the session to
`completed`. It deliberately never touches a `running` row: that is an
active worker lease, and stomping it would violate invariants #2/#16, so
the automatic path's claim-guarded complete/fail stays the only lease
transition. The memory_consolidate handler calls it best-effort after a
successful, non-dry consolidate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MDbhmszrjG9s5MrPrTuNtm