fix(gjc-runtime): make psmux authority host-independent and fence continuation dispatch - #3607
Conversation
…-independent Restacks the Windows psmux authority work onto current dev, dropping the storage lineage dev already absorbed via squash, and repairs every darwin-only failure in the slice. Five separate platform sources decided psmux behavior independently; four ignored the authority test seam entirely, so Windows-authority paths were unreachable on POSIX and eleven tmux-sessions tests failed there: - psmuxAuthorityEnvironments gated persisted-authority discovery on raw process.platform, aborting before any later guard could run. - resolveGjcTmuxProviderContext and createGjcTmuxSession each recomputed the platform instead of consulting the seam. - teamProviderAuthority read process.platform directly; GjcTeamConfig now carries the platform so startGjcTeam's value reaches it. Continuation dispatch had two real defects: the ack-loop deadline used raw Date.now() while every other timestamp in the file routes through the seamed clock, and the reservation site threw where the revalidation site records a skipped outcome, so one worker's short lease aborted an entire monitor pass. tmux-sessions: 35/35 on darwin (was 24/35). team-runtime: 115/117, with zero psmux-only failures - both remaining names also fail at dev, and this slice fixes three that dev fails.
psmux rewrote the darwin lifecycle spawn/cleanup path (completeNonLinuxLifecycleSpawn, cleanupDirectLifecycleAttempt), which regressed POSIX: dev is 60 pass / 0 fail on notifications-lifecycle-control-runtime, psmux was 51 / 9. psmux is a Windows-only provider and POSIX uses tmux, so the darwin path must stay dev's. Reverting the file to dev keeps every psmux suite green (tmux-sessions 35/0, psmux-detect 39/0, launch-tmux 137/0, tmux-gc 9/0) and preserves the win32 lifecycle content, which dev already carries from the earlier merged psmux-authority slices.
…the managed sync lock
…uation revalidation
…g continuation revalidation" This reverts commit ebc3ca196801cd6b50b726c51d22ed3ba704e9ce.
…ng continuation revalidation" This reverts commit 56f68822097d04d335126c7542f19e9dd720748e.
… the managed sync lock The Windows psmux authority publish previously acquired `acquireManagedLockSync` from managed-session storage. Dev removed that symbol when it reverted Yeachan-Heo#3489, so the import broke on merge and the whole slice failed at module load. Reviewers asked for the sync lock to return only alongside a real consumer and a shared async/sync release contract, which belongs to the resident storage branch rather than here. So this slice now enforces the property it actually needs on its own: a retained lock descriptor for the exact authority name blocks publication unless its owner process is definitely gone. Expiry alone is not permission, because a paused writer with an expired lease is still live and stealing the name would let two writers publish one generation-scoped authority. `publishManagedFileNoReplaceSync` already supplies create-without-clobber exclusion for the payload itself, so no lease helper is required.
…arker Repairs the two blockers the reviewer identified on the previous head. 1. A public authority-changing operation dispatched no continuation argv. The continuation reservation is written under the task lock, that lock is released, and only then does dispatch revalidate eligibility. A concurrent claim-releasing operation could land in that window, so revalidation observed no current claim and the incident was journalled skipped with nothing dispatched. Revalidation plus send-keys now runs inside the same team mutation fence every other public authority-changing operation takes, and the fence is released before the ACK wait because the ACK is published by a separate receiver process that must acquire the same cross-process fence. Worker GC prune now takes that fence too, since it deletes claim records. 2. Replacement settled before pane-launch ACK. The fake tmux rewrite dropped the three-field tmux-last-split marker its shell predecessor published on every split. The memory-guard replacement test waits on that marker before publishing the generation-bound startup ACK, so the ACK never arrived, relaunch hit its startup deadline, and the guard reported retrying. The marker is restored. The same test also aborted its marker waiter before its own advisory-host early return, which masked the advisory outcome on non-Linux hosts; the ordering is fixed.
The fence-hold restructure moved the send-keys argv construction into a closure, which dropped the outer non-null narrowing of `worker.pane_id`. Assert it the same way the adjacent `executeTeamTmuxMutation` calls already do, so the frozen argv stays `readonly string[]`.
Yeachan-Heo
left a comment
There was a problem hiding this comment.
APPROVE / MERGE_READY — terminal hostile review of exact head 41d882204c41b2e2fe1c9daf35ceeff159ae2eee.
P0: 0. P1: 0.
This successor is a bounded 13-addition/5-deletion repair over closed #3604. It captures worker.pane_id only after fenced eligibility revalidation, returns the existing typed worker_pane_missing skipped outcome if absent, binds one proven string to both send operations and both tmux mutation calls, and preserves fence release before the cross-process ACK wait. The predecessor review already established that continuation revalidation + dispatch are fenced, GC prune shares the fence, receiver ACK re-enters through task mutation, memory-guard split-marker causality is restored, and there is no dependency on the reverted synchronous managed lock.
Exact-head CI run 30576724409 is terminal green: 31/31 checks completed success/skipped, including check:@gajae-code/coding-agent, ts-build, the complete team-runtime.test.ts shard, launch/tmux/psmux/GC tests, evidence producer, and aggregate. No workflow was rerun or cancelled.
I also compared this 24-file psmux surface with active sole-owner #3596 exact head 6ed344d85b38d2609e54e77d37791c69ebb2ce5d: exact file overlap is empty. Current dev's independently owned ultragoal shard-5 red is unrelated and is not attributed to or absorbed by this PR. The branch is mergeable/clean and does not obscure #3596's Windows session-storage authority.
MERGE_READY.
—
[repo owner's gaebal-gajae (clawdbot) 🦞]
Hello, and thank you for the precise review on #3604. You identified exactly one blocker, and this successor repairs it in the way you asked.
What #3604 established
Your review confirmed the team-runtime shard passed on #3604's exact head, so both P1 defects from #3595 are genuinely repaired:
release claimdispatched no continuation argv. The reservation is written under the task lock, that lock is released, and only then does dispatch revalidate eligibility. A concurrent claim-releasing operation lands in that window, revalidation sees no current claim, and the incident is journalledskippedwith nothing dispatched. This is the fence-hold restructure the earlier PR body deferred. Revalidation plussend-keysnow runs insidewithGjcTeamMutationFence, the same fence every public authority-changing operation takes, andpruneTeamWorkerGcRecordnow takes it too. The fence is released before the ACK wait, because the ACK is published by a separate receiver process that must acquire the same cross-process fence — holding it across the wait would deadlock the very ACK being awaited. The existing test asserting continuation waits outside the mutation fence still passes.Replacement settled before pane-launch ACK. The cause was in the test's own fake tmux. The rewritten fake dropped the 3-field
tmux-last-splitmarker its shell predecessor wrote on every split. The replacement test waits on that marker before publishing the generation-bound startup ACK, so the ACK never arrived, relaunch hit its startup deadline, and the guard reportedretrying. The marker is restored. The test also aborted its ACK waiter before its own non-linux early return, which made advisory-only hosts fail on a correct advisory result; the platform check now runs first.The single repair in this successor
src/gjc-runtime/team-runtime.ts:4534—readonly (string | undefined)[]passed to areadonly string[]seam, becauseworker.pane_idstays optional after runtime eligibility validation.Repaired as you specified: the pane id is captured and narrowed to a proven non-empty local inside the fenced revalidation result, before argv is built. Both send operations use that proven
string, so they provably address the identical pane, and the frozen argv isreadonly string[]. A missing pane id is an eligibility gap rather than a dispatch error, so it returns the same typedskippedoutcome the other ineligible paths return. The four!assertions are gone rather than moved. The fence release before the ACK wait is unchanged.Verification on this exact head
tsc -p packages/coding-agent/tsconfig.json --noEmit— clean (exit 0). This is the check that was red on fix(gjc-runtime): fence continuation dispatch and repair the memory-guard split marker #3604.bun test packages/coding-agent/test/gjc-runtime/team-runtime.test.ts— 117 pass / 0 fail, 879 assertions. The full shard is green, including the case that was previously slow on my host.dd26a0787so exact-head CI runs against the current tip.Scope
No dependency on the reverted #3489:
acquireManagedLockSyncandManagedStorageLockSyncappear nowhere in this branch.persistGjcTmuxProviderAuthoritySyncis defined by this branch itself. Nothing here touches session storage or the managed lock record, so it stays clear of #3596's lane.I have not merged this, and I have not modified or rerun anything outside my own fork branch. Thank you again for the specific, reproducible guidance — the pointer to the fence-hold restructure and the exact tsc line both made this straightforward to fix.