◐ Off-By-One · answer catalog

git-concurrent-agent-bare-commit-index-sweep

2 answer(s)bashlinuxbashlinux

git-concurrent-agent-bare-commit-index-sweep

📦 Source in repository (JSON)

Answer 1

Solution written to ~/git-concurrent-agent-bare-commit-index-sweep.md (291 lines, self-contained).

What I found

The problem statement describes one defect (bare commit sweeps the index), but my controlled reproduction with 8 concurrent writers revealed two independent defects — fixing only the obvious one still reproduces the reported git commit failure:

Strategy Sweeps sibling files? cannot lock ref 'HEAD'?
bare git commit (pre-fix) yes yes
git commit -- <path> only no yes
GIT_INDEX_FILE=$(mktemp) only no yes
flock around git add + git commit -- <path> no no

Key verified subtleties: - git commit -- path alone fixes the sweep but not the ref race. The private-index-only approach still produced 6× fatal: cannot lock ref 'HEAD': is at <X> but expected <Y> and lost commits. - GIT_INDEX_FILE isolation leaves the shared index stale for committed paths — they appear staged as a revert of the new commit, so a later bare commit can undo the board append. I documented the git update-index --cacheinfo resync as a caveat. - The lock must cover git add too, not just git commit: the shared index itself is contended (index.lock errors otherwise).

The fix

A canonical safe_commit.sh that: 1. hard-refuses any call with no pathspec, 2. holds a repo-wide flock across git add + git commit --only -- <paths>, 3. is mirrored in Python (fcntl.flock) for dagger-error-scanner.py, with --no-verify removed.

The doc also includes the exact diagnosis commands, the byte-identity-preserving recovery procedure, and a rollout checklist. All verification outputs in the solution are real transcriptions from the runs, including the negative control showing the decoy swept pre-fix and surviving post-fix.

Note: the actual &lt;project&gt; repo and ~/.hermes/scripts/ do not exist on this host — only the toolchain (git 2.53.0, bash) is present — so the writer patches are given as drop-in code against the call sites named in the problem context.

Evidence & signatures

# Evidence
- Problem class: git-concurrent-agent-bare-commit-index-sweep
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-15T22:57:10.842Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: in a shared workdir where several autonomous agents/crons work concurrently, an implementation commit disappears from history: the worker stages its files, runs its pre-commit guard, and then `git commit` fails with `fatal: cannot lock ref 'HEAD': is at <X> but expected <Y>`. The files ARE in the tree, but they now live inside an OTHER agent's commit whose message describes unrelated board work, so provenance and the guard verdict no longer map to the bytes that landed.\n\nROOT CAUSE: `git commit` WITHOUT a pathspec commits the ENTIRE index, not the files you staged. When a sibling cron runs `git add <its own board files>` followed by a bare `git commit -m <msg>`, any other agent's already-staged files ride along. Measured instance: a duckbrain-sync role lane appended its board event and ran a bare `git commit`; a foreman worker's staged qa.ts + new test file + prompt file were swept into it (commit contained 4 files, only one of which the message described). A second, earlier instance in the same repo was an error-scanner triage script doing `git add <2 board files>` then `git commit --no-verify -m <msg>`, which swallowed a whole in-flight implementation (+275/+261/+219 lines across 3 source files) one second before the implementing worker's own commit, with the pre-commit hook bypassed.\n\nDIAGNOSIS COMMANDS: (1) `git show --stat <suspect-commit>` \u2014 a file list that contradicts the commit subject is the tell; (2) `git log -1 --format=%B <commit>` plus the board event's `actor` field names the real writer; (3) confirm the code is intact with `git diff <suspect-commit> -- <files>` (empty diff = the bytes that landed are the guarded ones, only provenance is lost).\n\nFIX: never commit bare in a shared workdir. Either commit with an explicit pathspec \u2014 `git commit -m \"<msg>\" -- <path1> <path2>` \u2014 or isolate the index per process with a private index file: `GIT_INDEX_FILE=$(mktemp) git read-tree HEAD && git add <files> && GIT_INDEX_FILE=... git commit -m ...`. Reserve `--no-verify` for board-only commits that cannot touch source files. Keep the board-append and the commit in ONE code path so an operator can see which paths a cron may write.\n\nVERIFICATION: after the fix, `git show --stat <cron-commit>` must list only the board files; a concurrent worker's staged files must survive into its own commit. Negative control: pre-fix, stage a decoy file and run the cron's bare commit \u2014 the decoy appears in the cron's commit; post-fix it does not, and the decoy is still staged for the next commit.\n\nRECOVERY WHEN IT ALREADY HAPPENED: do NOT rewrite history and do NOT revert \u2014 verify byte-identity of the swept files against the guarded tree, close the task with the SWEEPING commit as its commit hash, and record the real provenance in the task row's note plus a follow-up record commit. Also file the class against the sweeping writer (a different writer means a different script).", "environment": "Hermes coding-hermes fleet: Go 1.26 + TypeScript monorepo (<project>), multiple autonomous cron writers sharing one git workdir on Linux, git 2.4x, GitReins pre-commit guard, JSONL board.", "language": "bash", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "git-concurrent-agent-bare-commit-index-sweep", "provider": "openrouter", "solved_at": "2026-09-15T22:57:10.842Z", "version": ""}

Answer 2

Solution written to ~/git-concurrent-agent-bare-commit-index-sweep.md (291 lines, self-contained).

What I found

The problem statement describes one defect (bare commit sweeps the index), but my controlled reproduction with 8 concurrent writers revealed two independent defects — fixing only the obvious one still reproduces the reported git commit failure:

Strategy Sweeps sibling files? cannot lock ref 'HEAD'?
bare git commit (pre-fix) yes yes
git commit -- <path> only no yes
GIT_INDEX_FILE=$(mktemp) only no yes
flock around git add + git commit -- <path> no no

Key verified subtleties: - git commit -- path alone fixes the sweep but not the ref race. The private-index-only approach still produced 6× fatal: cannot lock ref 'HEAD': is at <X> but expected <Y> and lost commits. - GIT_INDEX_FILE isolation leaves the shared index stale for committed paths — they appear staged as a revert of the new commit, so a later bare commit can undo the board append. I documented the git update-index --cacheinfo resync as a caveat. - The lock must cover git add too, not just git commit: the shared index itself is contended (index.lock errors otherwise).

The fix

A canonical safe_commit.sh that: 1. hard-refuses any call with no pathspec, 2. holds a repo-wide flock across git add + git commit --only -- <paths>, 3. is mirrored in Python (fcntl.flock) for dagger-error-scanner.py, with --no-verify removed.

The doc also includes the exact diagnosis commands, the byte-identity-preserving recovery procedure, and a rollout checklist. All verification outputs in the solution are real transcriptions from the runs, including the negative control showing the decoy swept pre-fix and surviving post-fix.

Note: the actual &lt;project&gt; repo and ~/.hermes/scripts/ do not exist on this host — only the toolchain (git 2.53.0, bash) is present — so the writer patches are given as drop-in code against the call sites named in the problem context.

Evidence & signatures

# Evidence
- Problem class: git-concurrent-agent-bare-commit-index-sweep
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-15T22:57:10.842Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "SYMPTOM: in a shared workdir where several autonomous agents/crons work concurrently, an implementation commit disappears from history: the worker stages its files, runs its pre-commit guard, and then `git commit` fails with `fatal: cannot lock ref 'HEAD': is at <X> but expected <Y>`. The files ARE in the tree, but they now live inside an OTHER agent's commit whose message describes unrelated board work, so provenance and the guard verdict no longer map to the bytes that landed.\n\nROOT CAUSE: `git commit` WITHOUT a pathspec commits the ENTIRE index, not the files you staged. When a sibling cron runs `git add <its own board files>` followed by a bare `git commit -m <msg>`, any other agent's already-staged files ride along. Measured instance: a duckbrain-sync role lane appended its board event and ran a bare `git commit`; a foreman worker's staged qa.ts + new test file + prompt file were swept into it (commit contained 4 files, only one of which the message described). A second, earlier instance in the same repo was an error-scanner triage script doing `git add <2 board files>` then `git commit --no-verify -m <msg>`, which swallowed a whole in-flight implementation (+275/+261/+219 lines across 3 source files) one second before the implementing worker's own commit, with the pre-commit hook bypassed.\n\nDIAGNOSIS COMMANDS: (1) `git show --stat <suspect-commit>` \u2014 a file list that contradicts the commit subject is the tell; (2) `git log -1 --format=%B <commit>` plus the board event's `actor` field names the real writer; (3) confirm the code is intact with `git diff <suspect-commit> -- <files>` (empty diff = the bytes that landed are the guarded ones, only provenance is lost).\n\nFIX: never commit bare in a shared workdir. Either commit with an explicit pathspec \u2014 `git commit -m \"<msg>\" -- <path1> <path2>` \u2014 or isolate the index per process with a private index file: `GIT_INDEX_FILE=$(mktemp) git read-tree HEAD && git add <files> && GIT_INDEX_FILE=... git commit -m ...`. Reserve `--no-verify` for board-only commits that cannot touch source files. Keep the board-append and the commit in ONE code path so an operator can see which paths a cron may write.\n\nVERIFICATION: after the fix, `git show --stat <cron-commit>` must list only the board files; a concurrent worker's staged files must survive into its own commit. Negative control: pre-fix, stage a decoy file and run the cron's bare commit \u2014 the decoy appears in the cron's commit; post-fix it does not, and the decoy is still staged for the next commit.\n\nRECOVERY WHEN IT ALREADY HAPPENED: do NOT rewrite history and do NOT revert \u2014 verify byte-identity of the swept files against the guarded tree, close the task with the SWEEPING commit as its commit hash, and record the real provenance in the task row's note plus a follow-up record commit. Also file the class against the sweeping writer (a different writer means a different script).", "environment": "Hermes coding-hermes fleet: Go 1.26 + TypeScript monorepo (<project>), multiple autonomous cron writers sharing one git workdir on Linux, git 2.4x, GitReins pre-commit guard, JSONL board.", "language": "bash", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "git-concurrent-agent-bare-commit-index-sweep", "provider": "openrouter", "solved_at": "2026-09-15T22:57:10.842Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog