From f87143e7fc4d1be25494247864908beef7059a7e Mon Sep 17 00:00:00 2001 From: wshallwshall Date: Thu, 6 Aug 2026 12:03:19 -0500 Subject: [PATCH] docs(coord): the session record has no branch, and two rosters disagree about one A session was told a coordinator "might not be there" on the strength of the session-list MCP tool's `isRunning: false`, and separately the two rosters reported different branches for one checkout. Both readings were wrong the same way -- a field answering a question adjacent to the one asked -- and neither trap was written down anywhere a reader would look. MEASURED 2026-08-06. A session record holds exactly cwd, entrypoint, kind, name, nameSource, peerProtocol, pid, procStart, sessionId, startedAt, version. There is NO branch field. So any branch printed beside a session came from elsewhere, and the two sources answer different questions while both being labelled "branch": presence.ps1 / occupancy.ps1 the WORKTREE's branch, live from `git worktree list --porcelain`. Current. session-list MCP tool a SESSION attribute captured at registration. Does not follow a later `git switch`. For one checkout they reported two different names -- the live roster the branch that checkout had been switched onto, the session list the one it registered with. Neither was wrong. A disagreement is not evidence that either roster is broken, and a branch from the session list must never be quoted as a checkout's current branch. ALSO RECORDED, same family: `isRunning` means "currently EXECUTING A TURN", not "alive". An idle session between turns reads false while being perfectly reachable. It is not a liveness fence and must not be used as one -- Get-SessionLiveness is, subject to the rule already stated directly above it that ONLY THE POSITIVE ANSWER IS SAFE TO ACT ON. That rule is why the original inference was doubly wrong: it drew a negative conclusion from a signal that cannot support one, using a field that answers a different question. The concrete branch names are deliberately NOT quoted -- the leak gate refused the first attempt because a real worktree slug is an internal project name, and the lesson does not need them. Documentation only; no behaviour change. Both files parse, presence.ps1 still runs, 272 tests pass across the coord/presence/occupancy suites. --- scripts/coord/occupancy.ps1 | 5 +++++ scripts/coord/session-registry.ps1 | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/scripts/coord/occupancy.ps1 b/scripts/coord/occupancy.ps1 index 3b66f7f7..e3394f95 100644 --- a/scripts/coord/occupancy.ps1 +++ b/scripts/coord/occupancy.ps1 @@ -84,6 +84,11 @@ function ConvertTo-Norm([string]$p) { # Every worktree sharing one .git. Keyed on the worktree SET rather than a single path, because the # whole point is seeing siblings, not just yourself. +# The Branch this returns is the WORKTREE's, read live from git, and is therefore current at the moment +# of the call. It is NOT a session attribute: a session record carries no branch at all (see +# session-registry.ps1). The session-list MCP tool reports the branch a session STARTED on, which does +# not follow a later `git switch` -- so the two legitimately disagree for a checkout that has moved, and +# a disagreement is not evidence that either is broken. Use this one for "what is that checkout on now". function Get-RepoWorktrees([string]$RepoHint) { $gitArgs = @() if ($RepoHint) { $gitArgs = @("-C", $RepoHint) } diff --git a/scripts/coord/session-registry.ps1 b/scripts/coord/session-registry.ps1 index 69e4cacb..d5092d43 100644 --- a/scripts/coord/session-registry.ps1 +++ b/scripts/coord/session-registry.ps1 @@ -38,6 +38,31 @@ registry writes are event-driven, so nothing here can PROVE a session is gone -- only that it is present. A DEAD/STALE/not-found verdict must never by itself authorise a destructive action; combine it with an independent signal and let either one veto. + + THE RECORD CARRIES NO BRANCH, AND TWO ROSTERS DISAGREE ABOUT ONE. A session record holds exactly + `cwd, entrypoint, kind, name, nameSource, peerProtocol, pid, procStart, sessionId, startedAt, + version` -- there is no branch field and never has been. So any branch you see printed beside a + session came from somewhere else, and the two sources answer DIFFERENT QUESTIONS while both being + labelled "branch": + + presence.ps1 / occupancy.ps1 the WORKTREE's branch, read live from `git worktree list + --porcelain` (occupancy.ps1, the `branch ` porcelain line). Current + at the moment you asked. This is the one to trust for "what is that + checkout on NOW". + the session-list MCP tool a SESSION attribute captured when the session registered. It does + not track a later `git switch`, so it is the branch the session + STARTED on. + + Measured 2026-08-06: for ONE checkout the two rosters reported two DIFFERENT branch names -- the + live roster the branch that checkout had been switched onto, the session list the one it registered + with. Neither was wrong; they were answering different questions. NEVER quote a branch from the + session list as a checkout's current branch, and never treat a disagreement between the two as + evidence that either roster is broken. + + RELATED TRAP IN THE SAME FAMILY: the session list also exposes an `isRunning` flag. It means "this + session is currently EXECUTING A TURN", not "this session is alive" -- an idle session between turns + reads false while being perfectly reachable. It is not a liveness fence and must not be used as one; + that is what Get-SessionLiveness above is for, subject to the positive-answer-only rule. #> # Every config root that actually holds a session registry.