You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The environment's setup-script field no longer matches the canonical text in .claude/README.md. It is down to 264 bytes — per Running initialization script {"script_length":264} in /tmp/env-manager.log — which is just the settings.json heredoc. Everything the canonical script does after writing that file is gone.
Filed as the follow-up to #84, which makes a session survive one of these but does not remove the need to fix the field.
Observed in a four-repo session, 2026-08-01
canonical step
state
consequence
write $HOME/.claude/settings.json
✅ done
dispatcher runs; repo hooks fan out correctly
node $BOOT/register-mcp.mjs
❌ missing
~/.claude.json had mcpServers: null — no MCP tools at all
cp $BOOT/stop-hook-git-check.sh
❌ missing
the stock Stop hook is installed; infra#112 is live again
A session asked "what should we work on next?", found no next tool, and ranked the org's work by hand from list_issues / list_pull_requests — the one move front-desk-scheduler's CLAUDE.md forbids in its opening paragraph. The answer looked exactly like a Front Desk answer. Nothing in the session said the tool was missing.
Note how little of the machinery was actually broken: the dispatcher ran, every repo's hook ran, deno / dolt / node_modules were all present, and the MCP server started cleanly when invoked by hand. One absent line in a field no reviewer and no gate can read.
The stop-hook-git-check.sh regression is the same shape and has been quieter — the stock hook scopes its check to origin/<branch>..HEAD, so it warns "Unverified" after every squash merge and advises an --amend that would rewrite already-merged history. That is exactly the infra#112 bug the repo copy exists to fix.
Fix
Restore the field to the script in .claude/README.md under Install. That file is explicitly the canonical text for this purpose: "If the two drift, this file is what the field should be returned to."
The part that stays open after that
Nothing detects this. It is the third recurrence of one failure mode:
infra#122 — logic in an unreviewable place, no drift gate
this one — the field itself, which no test can read
#84 narrows it: the dispatcher now re-runs register-mcp.mjs and warns when it had to, so that line going missing is self-healing and loud. The other two steps have no such backstop, and the general problem — a bootstrap field that can silently lose lines — is unsolved.
Have the dispatcher emit one line naming which canonical steps it can detect were skipped, so drift shows up in the session log rather than in a hand investigation.
Reduce the field to a single exec of one versioned script, so there is less surface to lose. It cannot go to zero — something has to name the entry point — but a one-line field either works or fails loudly, with no partial state.
Option 3 is the real fix and the biggest change; 1 and 2 are worth doing regardless, since they hold the line for whatever the field looks like.
The environment's setup-script field no longer matches the canonical text in
.claude/README.md. It is down to 264 bytes — perRunning initialization script {"script_length":264}in/tmp/env-manager.log— which is just thesettings.jsonheredoc. Everything the canonical script does after writing that file is gone.Filed as the follow-up to #84, which makes a session survive one of these but does not remove the need to fix the field.
Observed in a four-repo session, 2026-08-01
$HOME/.claude/settings.jsonnode $BOOT/register-mcp.mjs~/.claude.jsonhadmcpServers: null— no MCP tools at allcp $BOOT/stop-hook-git-check.shCLAUDE_SESSION_ROOT=$ROOTon the hook commandVerified:
What it cost
A session asked "what should we work on next?", found no
nexttool, and ranked the org's work by hand fromlist_issues/list_pull_requests— the one move front-desk-scheduler'sCLAUDE.mdforbids in its opening paragraph. The answer looked exactly like a Front Desk answer. Nothing in the session said the tool was missing.Note how little of the machinery was actually broken: the dispatcher ran, every repo's hook ran,
deno/dolt/node_moduleswere all present, and the MCP server started cleanly when invoked by hand. One absent line in a field no reviewer and no gate can read.The
stop-hook-git-check.shregression is the same shape and has been quieter — the stock hook scopes its check toorigin/<branch>..HEAD, so it warns "Unverified" after every squash merge and advises an--amendthat would rewrite already-merged history. That is exactly the infra#112 bug the repo copy exists to fix.Fix
Restore the field to the script in
.claude/README.mdunder Install. That file is explicitly the canonical text for this purpose: "If the two drift, this file is what the field should be returned to."The part that stays open after that
Nothing detects this. It is the third recurrence of one failure mode:
bootstrap-pin.test.mjs#84 narrows it: the dispatcher now re-runs
register-mcp.mjsand warns when it had to, so that line going missing is self-healing and loud. The other two steps have no such backstop, and the general problem — a bootstrap field that can silently lose lines — is unsolved.Worth considering, roughly in order of cost:
stop-hook-git-check.shagainst the repo copy and re-copy on mismatch, the way session-start: register MCP servers from the dispatcher when the setup script did not #84 does for MCP. Cheap, and closes the second row of the table.execof one versioned script, so there is less surface to lose. It cannot go to zero — something has to name the entry point — but a one-line field either works or fails loudly, with no partial state.Option 3 is the real fix and the biggest change; 1 and 2 are worth doing regardless, since they hold the line for whatever the field looks like.