Reviewed coordination promotion and recovery
September 22, 2026 ยท View on GitHub
A promotion moves a Goal's Todo/lease coordination authority from the legacy source to its selected canonical provider. Preview, writer fencing, provider commit, and acknowledgement are distinct steps. A successful preview is neither a grant nor evidence that cutover has happened.
The operator can now save the exact preview, execute that plan, and recover its original transaction without reconstructing intent from a later Markdown view. The TypeScript coordination boundary owns plan validation, qualification, fencing and receipt proof; Python only loads the file and transports the request.
Preview and execute
Use an explicitly enabled, bootstrapped and qualified runtime shadow. Its
qualification must cover real mutations and required event classes; an empty
shadow or a saved JSON file cannot substitute for that evidence. Existing v0
promotion still requires hard_lease. Provider selection and migration approval
remain separate from these commands.
loopx --format json coordination-shadow promote \
--goal-id example-goal \
--minimum-operations 3 \
--require-event-kind todo_update > reviewed-promotion.json
loopx --format json coordination-shadow promote \
--goal-id example-goal --reviewed-plan reviewed-promotion.json
loopx --format json coordination-shadow promote \
--goal-id example-goal --reviewed-plan reviewed-promotion.json --execute
Inspect ok, promotion.status, the plan's target provider, source revision,
projection digest and qualification policy before execution. The saved file may
be the entire successful CLI preview or its promotion.plan.reviewed_plan
envelope. Keep it in operator-owned local storage: it carries a runtime path and
Goal identity, so it is not a public collaboration artifact.
--reviewed-plan owns the operation id and qualification policy. Combining it
with --minimum-operations or --require-event-kind is an error. A normal
promote command without a saved plan retains its existing defaults.
Execution captures and qualifies the source again under the existing locks. If
the computed plan digest differs, it returns
local_authority_reviewed_plan_changed before engaging a writer fence. Review a
new preview after legitimate source changes; do not edit the old digest to force
acceptance. The digest detects changed intent; the durable fence and provider
state establish whether that intent may proceed.
Recover the original cutover
loopx --format json coordination-shadow recover-promotion \
--goal-id example-goal --reviewed-plan reviewed-promotion.json
loopx --format json coordination-shadow recover-promotion \
--goal-id example-goal --reviewed-plan reviewed-promotion.json --execute
Recovery resolves the registered Goal and runtime but does not read legacy Markdown or require the transient shadow opt-in. It requires the exact existing writer fence. It never creates a missing fence, selects another provider, or falls back to a legacy source.
| Durable state | Preview | With --execute |
|---|---|---|
| No matching writer fence | Reject | Reject |
| Matching fence, no canonical commit, exact qualified shadow retained | recovery_ready | Commit and read back |
| Original promotion committed, including a later canonical head | replayed | replayed; no business write |
| Different canonical initialization or inconsistent receipt lineage | Reject | Reject |
| Provider unavailable | Report provider failure | Report provider failure |
For an uncommitted recovery, the original shadow revision, projection, capture binding, complete transaction lineage, outbox settlement, operation count and event coverage must still qualify. Recovery validates these durable facts under the same maintenance guard used by canonical writers. It does not pretend to observe fresh source parity after the source has ceased to be authority.
A thrown commit acknowledgement can mean that the provider already committed. Both promotion paths therefore share one commit/readback implementation. It attempts the business commit once, then checks the persisted receipt and first transaction. The receipt body, operation id, cursor, provider revision and initial projection must agree. A matching proof reports success/recovery even if later work has advanced the head. A missing or conflicting proof remains a failure; an unavailable proof read is not silently treated as absence.
The returned promotion revision and cursor identify the original cutover, not
the current head. executed=false on a replay means this invocation performed no
business write. Inspect legacy_writer_fenced and reconciliation evidence when
an execution fails; do not infer that a failure left legacy writers usable.
Bounded capture proof transport
A long Goal can exceed the existing 2 MiB RPC response budget before promotion:
sequence recovery used to return a full head and full projections for retained
transactions. The outbox_read proof read model now keeps full lineage validation
inside TypeScript, while returning progress, receipts, projection digests and
partition markers. Sequence allocation requests no transaction rows; drain uses
the compact rows. Existing full diagnostic reads retain their default contract.
No transport limit, stored population or transaction validation is weakened.
A pending outbox still blocks promotion; use the existing bounded
authority-shadow drain --goal-id example-goal --budget-seconds 60 operation
and inspect its result before retrying preview.
Product and rollout boundary
This is an operator CLI administration journey. It adds no dashboard, Lark or managed-Turn automatic migration trigger, settings editor, capability grant or new provider selector. Those surfaces continue to consume canonical data through the existing routing/projection contracts after a separately authorized cutover.
File and SQLite use their existing local stores. PostgreSQL follows the same transaction/readback contract through its service-owned factory; a local CLI selector alone does not provide a PostgreSQL connection or tenant authority.
The claim-preserving migration work in PR #4870 is a complementary prerequisite
for Goals that need explicit preserve or a claim-preserving hard_lease
transition. The two changes overlap the promotion orchestration and must be
integrated and tested together; this saved-plan feature alone does not enable
that policy conversion on a v0-only checkout.
Default-on promotion, SQLite long-duration qualification, post-promotion export or rollback, and retirement of remaining Python callers retain their RFC gates. Recovery is a forward completion/readback operation, not rollback. Do not remove a live fence, reset canonical storage, or replace the source to make recovery pass. Before execution, abandoning a saved preview needs no runtime mutation.
Validation contract
Durable tests cover real File/SQLite CLI preview, saved-plan execution, source drift, policy override rejection, later canonical writes and recovery after legacy deletion. The provider conformance suite uses the shared production-scale fixture in legacy and native record shapes, preserving the complete Todo/lease population through File, SQLite and a real isolated PostgreSQL server.
Negative receipt tests independently corrupt the receipt index and first transaction. Interrupted-commit tests distinguish failure before commit from a lost acknowledgement after commit. These are synthetic fault injections, not a claim of arbitrary process-death or elapsed-soak coverage. Real local rehearsals must use read-only captured sources and disposable copies; never promote an active Goal merely to validate this refactor.