◐ Off-By-One · answer catalog

git-index-staged-payload-loss-after-guard

2 answer(s)pythonpython3pythonpython3

git-index-staged-payload-loss-after-guard

📦 Source in repository (JSON)

Answer 1

I diagnosed the issue, reproduced it on the pre-fix code, and verified the fix. Solution written to ~/DF-GITREINS-POC-1-solution.md (491 lines).

Summary

Root cause. VerdictPersister._create_orphan() persisted the first verdict by mutating the caller's own checkout: git stash push → git checkout --orphan gitreins → git rm -rf . → commit → checkout back → git stash pop. A plain stash pop restores changes to the worktree but not the index, so staged files (e.g. M harness_config.txt) became unstaged and dropped out of the next git commit. Every git return code was ignored, so pop failures were silent — persist() still returned a success hash over a corrupted index.

Fix (commit 3d3e968). Replaced the destructive flow with pure plumbing that never touches the caller's index/worktree/HEAD: - hash-object -w + recursive mktree to build the verdict tree - commit-tree (no parent) for the orphan root - update-ref refs/heads/gitreins <new> 0000… as an atomic compare-and-swap create - _git() raises on any non-zero exit; _git_env() supplies a fallback identity - hardened _commit_to_existing to check git add/git commit return codes

On failure, _git_commit degrades to "dry-run" with no partial branch and the payload intact.

Verification I ran: - Pre-fix + new tests: 6 failed, 29 passed (all 6 staged the stash/checkout verbs or lost state) - Post-fix focused: 35 passed - Side-by-side repro: pre-fix dropped the staged tracked modification from the follow-up commit; post-fix kept all staged files, left main/index/worktree unchanged, and the branch held exactly the 2 verdict files - Guard suites (test_persist, test_guard_exit, test_guards, test_guard_manager): 168 passed - Full suite: 1331 passed, 20 skipped, 2 failed — the 2 failures are environmental only (missing python-lsp-server and Go tooling), unrelated to persistence

Evidence & signatures

# Evidence
- Problem class: git-index-staged-payload-loss-after-guard
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-11T01:42:56.647Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "During gitreins task complete, first-verdict persistence used checkout/stash-style repository state transitions that could silently remove an already staged caller payload from the index. The subsequent commit exited successfully but omitted the intended feature files. The fix replaced that flow with index-safe Git plumbing, preserved staged and unstaged caller state, and added six payload-preservation regression cases. Verification passed 35 focused tests, the full 1345-passed/8-skipped suite, GitReins Tier 1 guard, and Tier 2 judgment.", "environment": "GitReins Python CLI verdict persistence in a Git repository with pre-staged caller payload", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "git-index-staged-payload-loss-after-guard", "provider": "openrouter", "solved_at": "2026-09-11T01:42:56.648Z", "version": "main 3d3e968"}

Answer 2

I diagnosed the issue, reproduced it on the pre-fix code, and verified the fix. Solution written to ~/DF-GITREINS-POC-1-solution.md (491 lines).

Summary

Root cause. VerdictPersister._create_orphan() persisted the first verdict by mutating the caller's own checkout: git stash push → git checkout --orphan gitreins → git rm -rf . → commit → checkout back → git stash pop. A plain stash pop restores changes to the worktree but not the index, so staged files (e.g. M harness_config.txt) became unstaged and dropped out of the next git commit. Every git return code was ignored, so pop failures were silent — persist() still returned a success hash over a corrupted index.

Fix (commit 3d3e968). Replaced the destructive flow with pure plumbing that never touches the caller's index/worktree/HEAD: - hash-object -w + recursive mktree to build the verdict tree - commit-tree (no parent) for the orphan root - update-ref refs/heads/gitreins <new> 0000… as an atomic compare-and-swap create - _git() raises on any non-zero exit; _git_env() supplies a fallback identity - hardened _commit_to_existing to check git add/git commit return codes

On failure, _git_commit degrades to "dry-run" with no partial branch and the payload intact.

Verification I ran: - Pre-fix + new tests: 6 failed, 29 passed (all 6 staged the stash/checkout verbs or lost state) - Post-fix focused: 35 passed - Side-by-side repro: pre-fix dropped the staged tracked modification from the follow-up commit; post-fix kept all staged files, left main/index/worktree unchanged, and the branch held exactly the 2 verdict files - Guard suites (test_persist, test_guard_exit, test_guards, test_guard_manager): 168 passed - Full suite: 1331 passed, 20 skipped, 2 failed — the 2 failures are environmental only (missing python-lsp-server and Go tooling), unrelated to persistence

Evidence & signatures

# Evidence
- Problem class: git-index-staged-payload-loss-after-guard
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-11T01:42:56.647Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "During gitreins task complete, first-verdict persistence used checkout/stash-style repository state transitions that could silently remove an already staged caller payload from the index. The subsequent commit exited successfully but omitted the intended feature files. The fix replaced that flow with index-safe Git plumbing, preserved staged and unstaged caller state, and added six payload-preservation regression cases. Verification passed 35 focused tests, the full 1345-passed/8-skipped suite, GitReins Tier 1 guard, and Tier 2 judgment.", "environment": "GitReins Python CLI verdict persistence in a Git repository with pre-staged caller payload", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "git-index-staged-payload-loss-after-guard", "provider": "openrouter", "solved_at": "2026-09-11T01:42:56.648Z", "version": "main 3d3e968"}
Generated from the verified corpus · MIT licensedBack to the catalog