Skip to content

fix: release prepared-replacement terminal cutover leases - #286

Merged
James3014 merged 1 commit into
mainfrom
fix/prepared-replacement-terminal-lease-cleanup
Sep 26, 2026
Merged

James3014 merged 1 commit into
mainfrom
fix/prepared-replacement-terminal-lease-cleanup

Conversation

@James3014

Copy link
Copy Markdown
Owner

Fixes a terminal-hygiene gap exposed while deploying Wave 2.

#279 added the exact coordination-bound active PREPARED replacement closure path. A cutover completed by that path is legitimately terminal with:

  • closed cutover state;
  • exact replacement identity;
  • positive workspace/agent reconciliation;
  • terminal durable cutover operation/hash;
  • finished, unpinned lease.

However, releaseClosedCutoverLeaseLocal() still only accepted the older drain + restart + finish shape. That left the completed #242 cutover lease blocking every successor cutover.

This repair does not widen cutover execution authority. Terminal lease cleanup now accepts either:

  1. the existing normal drain/restart completion; or
  2. the fix: reconcile active prepared replacement cutover (#242) #279 prepared-replacement completion.

For the prepared-replacement shape it additionally requires the terminal operation's lifecycleAction to prove:

  • action = finish;
  • exact cutover id;
  • replacement server instance differs from predecessor;
  • source/build/capability exactly equal the approved target;
  • exact approved workspace/agent pair;
  • reconciliation receipt was closed by that same replacement instance.

All existing revoked-root-carrier, terminal record hash, operation terminality, finished/unpinned lease, CAS version, replay, and no-state-rewrite guards remain.

Exact Candidate:

  • base: cb33bb7c6f200141b9797c56efdaf2964c726dcf
  • candidate: ae334e6f11cc3ca1aee1463255ca25df222cb999
  • tree: 6ff5c1345c7a10705984783b5217c913f4379035
  • changed paths: src/carrier-binding.ts, src/carrier-binding.test.ts
  • no deletions / no scope escape

Verification on exact bytes:

  • RED reproduced the production failure: Terminal lease release requires one normally completed cutover generation
  • focused normal + prepared-replacement terminal hygiene: 3/3 PASS
  • full carrier-binding.test.ts: 45/45 PASS
  • npm run typecheck: PASS
  • npm run build: PASS
  • git diff --check: PASS

This is required to clear the stale terminal #242 lease through the supported host-local hygiene seam; no direct database mutation is used.

@James3014
James3014 merged commit 4a94932 into main Sep 26, 2026
13 checks passed

Copy link
Copy Markdown
Owner Author

During the #240 M5 recovery/deployment, one additional terminal-hygiene edge case was reproduced.

A cutover that had:

  • prior drainEvidence,
  • no typed restartRequest because the exact replacement was loaded through an Owner-local launchd reload,
  • exact expected replacement source/build/capability identity,
  • positive durable workspace/agent reconciliation,
  • closed cutover + finished operation,

was rejected by releaseClosedCutoverLeaseLocal() with:

Terminal lease release requires one supported terminal cutover generation

The current #286 guard recognizes normal typed-restart completion and prepared-replacement completion, but not this exact “drained + externally reloaded exact replacement + positive reconciliation” terminal generation.

A bounded local recovery patch added that exact generation while preserving the same replacement identity / finish-pair checks; carrier-binding.test.ts passed 46/46, typecheck PASS, diff-check PASS. It was used only to release the already-completed lease; that hotfix was not merged to main.

This does not block the final #240 typed-restart path, but the edge case remains a tracked gap for any future external exact-reload recovery.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant