Playbook: Concurrent SOPS Write — Shared-Checkout Filesystem Race
Created: 2026-08-03
Incident: A w3_app MongoDB password rotation committed a foreign, non-authenticating value
because a concurrent agent session was writing the same tracked file at the same time — taking
v32-prod (W3 production) into a MongoDB auth-failure loop for several minutes.
Issue: #5242
Related incidents: #5224,
#5223,
#5225 (GH_TOKEN concurrent-rotation race, same window)
Trigger
A credential/shared-file write (typically a sops write to secrets/*.env.sops, but any write to
a tracked file works) is executed directly in a shared checkout — the primary
C:\code_2026\p24-infra / /opt/p24-infra working directory that other Claude Code sessions or
background Agent() calls are simultaneously operating in — instead of an isolated
tmp/wt-{issue} worktree mandated by CLAUDE.md §Agent Workflow — Worktree Branch Isolation.
Symptoms
git checkout mainfails withfatal: 'main' is already used by worktree at .claude/worktrees/agent-….git/config: Permission deniedduringgit pull/git checkout -b(concurrent.gitaccess)- A
sops --decryptread returns a value that matches neither password this session generated — a transient snapshot of another process’s in-flight write to the same file - Your own freshly-rotated secret does not authenticate after distribution, because the commit captured a stale/foreign snapshot rather than your value
- Follow-up “resync” commits are needed to converge on the correct value (and the first resync can itself chase the wrong, race-observed value)
Root cause
Git’s concurrency protections cover the object store and ref updates — they do not cover
uncommitted working-tree file writes. When two sessions share one physical checkout, a plain
filesystem write to secrets/foo.env.sops in session A can interleave with a sops read/write in
session B: the reader sees a half-written or foreign snapshot, and whichever git add runs next
stages whatever bytes are on disk at that instant.
This is a distinct failure mode from
shared-checkout-worktree-isolation.md (#3230). That
incident was a git-branch race (a commit landing on another session’s checked-out branch), and
its hook guard blocks git commit / branch-switch in the primary checkout. Neither the git-branch
race nor its hook guard touches the filesystem-level race described here — a SOPS write is not a
git commit, so the #3230 guard never fires on it.
Immediate recovery
- Stop distributing. A value that fails to authenticate must not be pushed further.
- Get the correct value out-of-band. Read the intended password from a stable scratchpad copy
(never re-derive it from the racing
secrets/file). Reference the key name only — never print the value (CLAUDE.md §Secrets). - Re-converge the SOPS file from that known-good value in a single isolated worktree, run the canary decrypt, then redistribute (SOPS → GH Secrets → live envs → containers).
- Follow
static-api-key-incident-rotation.mdif any value was exposed in the process.
Prevention — pre-flight guard (added for #5242)
Before any write to a shared tracked file (above all secrets/*.env.sops), run the read-only
guard and abort the write if it reports UNSAFE:
scripts/check-worktree-write-safety.sh secrets/pinbox24-w3.env.sops || {
echo "Unsafe — move into an isolated worktree before writing"; exit 1;
}The guard exits non-zero when the current directory is a concurrent-write hazard:
- you are in the primary checkout while ≥1 linked worktree is active, or
- the same branch is checked out by 2+ worktrees (the “already used by worktree” condition).
It reads only git worktree list / git rev-parse — it never touches, decrypts, or prints any
secret, so it is safe for any role (including sys-admin/sys-security read-only roles) to run.
A non-zero exit is its designed verdict, not a system error, so it deliberately does not fire the
Discord/GH error path.
The safe workflow it points you to
# 1. Isolated worktree for this credential op
git worktree add tmp/wt-{issue} -b {branch} origin/main
cd tmp/wt-{issue}
# 2. Confirm the directory is race-free, then do the SOPS write here
../../scripts/check-worktree-write-safety.sh secrets/{file}.env.sops
# ... sops write, canary decrypt, git add, git commit ...
# 3. Clean up after merge — remove, guarantee the dir is gone, then prune (#6006)
cd ../.. && git worktree remove --force tmp/wt-{issue} && rm -rf tmp/wt-{issue} && git worktree prune -vA leftover worktree dir silently falls through to the parent repo — see
worktree-remove-fallthrough-guard.md.
Dispatch-path audit (#5242 items #1, #3, #4)
Follow-up items 4 asked why a credential-write-capable session was dispatched into the shared checkout, and whether any other dispatch path can do the same. Findings:
- Queue dispatch (bms-4 / vps-i1) — already isolated.
scripts/spawn-worker.shclones every job (includingp24-infraitself and everysecret-managerjob) into a per-issue working directory/tmp/worker-{issue}-{repo-slug}andcds into it before launching the agent. This closed an earlier shared-/opt/p24-infrabranch race (#1689). A queue-dispatched credential rotation therefore already runs in its own filesystem-isolated clone — it was not the #5242 vector. - Local orchestration commands — already isolated.
issues-review,is-check-nofuture-no-human,process-issues-remote,fix-fast,bug, andauto-issue-pipelineall spawn their workers into dedicatedgit worktree addcheckouts. request-secrets— this was the gap (item #3), now closed..claude/commands/request-secrets.mdspawned the backgroundsecret-manageragent with a hardcodedWorking directory: C:\code_2026\p24-infra— the shared primary checkout — with no worktree isolation and no pre-flight guard. A rotation dispatched through it (or run manually in the same shared checkout, as in the incident) could race a concurrent session’s in-flight SOPS write. Answer to item #1: the task landed in the shared dir because the dispatch command told it to. The command now requires the agent to create and enter an isolated worktree and runcheck-worktree-write-safety.shbefore any SOPS write (v1.2.0).- Cross-reference (item #4). The
GH_TOKENconcurrent-rotation race (#5225, PR #5235) in the same window is the same class: two rotation-capable sessions writing the same shared checkout without isolation. The worktree-isolation rule enforced here (and the guard from PR #5244) is the shared mitigation.
Limitations
- The guard is advisory and opt-in — nothing auto-invokes it yet. It is a fail-fast check the
writer (human or agent) is expected to call. The
request-secretsdispatch command (v1.2.0) now instructs the spawned agent to run it before any SOPS write, but wiring it into thesecret-managerrole’s own SOPS-write path (so it fires regardless of dispatch route) is still asecret-managerfollow-up (see #5242 deferred items). - Like the #3230 hook, it only reasons about worktrees of the local repo on this machine; it cannot see other machines/CI runners operating on a clone.
- It detects the conditions for a race, not an in-progress write — its value is preventing the write from starting in an unsafe directory at all.
Related
shared-checkout-worktree-isolation.md— the sibling #3230 git-branch race and itspre-bash-safetyhook guardstale-agent-worktree-cleanup.md— cleaning up leftover.claude/worktrees/agent-*checkoutscross-repo-worker-isolation.mdsecret-manager.md— secret-manager operating manualCLAUDE.md§Agent Workflow — Worktree Branch Isolation- Issues #5242, #5224, #5223, #5225