test(parity): prove the gitignored-delete gate (AN-1) on Codex (#408) - #664
Closed
harshitagrawal2O wants to merge 1 commit into
Closed
Conversation
…manCore#408) The parity matrix showed AN-1 proven on Claude Code and the MCP proxy but unproven on Codex, so the guarantee rested on "same spine, should hold" rather than on evidence. Codex reaches the rule through its own adapter and its own captured payload shape, which is exactly the gap a parity cell exists to close. Adds the Codex twin of test_hosthook_claude_pre.py's test_unrecoverable_gitignored_delete_requires_auth, driven by the captured pre_bash.json fixture: `rm data/app.db` must not abstain, must resolve to deny (no approval channel is reachable from a test process, the fail-closed contract), must be an [AUTH] step-up rather than an objective block, and must not echo the operand in the host-visible reason. Mutation-checked: with `_rm_targets_unrecoverable_data` stubbed to return False the test goes red (the delete abstains entirely), so it detects the guarantee being removed rather than passing incidentally. Reverted before commit. Matrix regenerated with `python -m tools.parity.generate_parity`; the cell flips to a linked ✅. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fu351
added a commit
that referenced
this pull request
Sep 9, 2026
fu351
added a commit
that referenced
this pull request
Sep 9, 2026
Collaborator
|
Merged via a landing branch, thanks @harshitagrawal2O! Asserting the AUTH tier in the reason rather than only the deny is what stops an unrelated hard block from proving this cell by accident, and redacting the basename separately from the full operand is one check more than the Claude Code sibling does. Two mechanical things on the landing branch: docs/PARITY.md regenerated on top of current main (the drift row landed after you branched) and a changelog.d/664.docs.md fragment, nothing else touched. #406 (level-3) is the same pattern on the proxy if you want another parity cell, no rush with #653 and #663 open. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Slice
What this PR does
Flips "Deleting unrecoverable gitignored data is gated (AN-1)" from ◻ to ✅ on Codex in the parity matrix.
The guarantee was proven on Claude Code and the MCP proxy but not on Codex, so on that host it rested on "same spine, should hold". Codex reaches the rule through its own adapter (
to_normalize_input, gate-by-default rather than allowlist-abstain) and its own captured payload shape, which is exactly the distance a parity cell exists to measure — the shared spine is the reason it probably holds, not evidence that it does.Adds the Codex twin of
test_hosthook_claude_pre.py'stest_unrecoverable_gitignored_delete_requires_auth, driven by the capturedpre_bash.jsonfixture.rm data/app.db— a local database file, gitignored by convention and unrecoverable by git, which is precisely what AN-1's lexical operand gate (_UNRECOVERABLE_DELETE_GLOBS) exists to catch — must:deny, because no approval channel is reachable from a test process — the fail-closed contract,[AUTH]step-up, not an objective block, so the cell proves the gate rather than some unrelated hard block catching the same string,Mutation-checked
The bar the issue sets for a ✅. With
_rm_targets_unrecoverable_datastubbed toreturn False, the new test goes red:So it detects the guarantee being removed, rather than passing because something else in the chain happens to deny. Reverted before commit (
git checkout --, working tree confirmed clean apart from the test file).Tests added (run in CI)
tests/unit/test_hosthook_codex.py—test_unrecoverable_gitignored_delete_requires_auth, marked@pytest.mark.guarantee("gitignored-delete-gate", host="codex").docs/PARITY.mdregenerated withpython -m tools.parity.generate_parity;--checkpasses.Changelog
changelog.d/<PR>.<type>.mdfragment added, or this change is invisible to users — test-only, no user-visible behaviour change. Perchangelog.d/README.md("Skip the fragment entirely for changes no user can see"), no fragment. The matrix itself is the user-visible artifact and it is regenerated in this PR.Public-release safety (doberman-core only)
Security checklist
[AUTH]in the reason)Edge cases covered / Deviations from plan / Risks introduced
permissionDecision == "deny"would still pass if some unrelated hard block caughtrm data/app.db, which would mark the cell ✅ on the wrong evidence. Asserting[AUTH]pins it to the step-up path AN-1 actually produces.data/app.dbwould miss a reason that leakedapp.dbalone.apply_patchdeletes are a separate surface and are not claimed here.Related: #198 extends this same area with a directory-level gate (PR #653). This PR proves the existing lexical file gate and is independent of it.
🤖 Generated with Claude Code