feat(guards): third-party data and cross-session pre-commit gates - #67
Merged
Merged
Conversation
added 6 commits
October 3, 2026 06:07
KNOWN_ISSUES.md held 448 lines against a 300-line limit (rule R1), which blocked every commit on main. 224 of those lines were not board entries: 29 blocks injected verbatim from AGENT_DIARY.md by AutoDocUpdater during a full reindex, each carrying "Источник: AGENT_DIARY.md" and "Статус: автоматически синхронизировано". A board that mirrors the diary holds every issue twice and cannot be trimmed without losing information. The diary stays the source; the board keeps the 24 hand-authored sections. Live board is now 224 lines. scripts/archive_autosync_entries.py does this by marker rather than by date, so the classification does not rot as the file ages, and a second run finds nothing to move and changes nothing. Nothing is deleted — the blocks are appended to docs/archive/KNOWN_ISSUES_2026_10_AUTO_SYNC.md, per §4.8 R4.
pip-audit failed on both test jobs with vulnerabilities that appeared after the
last green main run on 2026-09-29, so this is a time-dependent failure rather
than a regression from any recent change:
urllib3 2.7.0 PYSEC-2026-4175 / -4176 / -4177 -> 2.8.0
PyJWT 2.13.0 13 advisories, highest fix 2.15.0 -> 2.15.0
Both are transitive: neither is imported as an API. PyJWT appears in the codebase
only as a token pattern in src/core/redact.py, and the line above the pin claimed
a verified RS256 roundtrip against pyjwt 2.13.0 — that claim is re-verified here
rather than assumed, and the comment is updated to the version actually tested.
Verified after the bump, not before:
- pip-audit -r requirements-lock.txt --no-deps --disable-pip -> "No known
vulnerabilities found", rc=0
- RS256 roundtrip with cryptography 50.0.0, and `import mcp` -> ok
- pytest tests/ -> 1989 passed, 6 skipped, 98 deselected
- scripts/smoke_e2e.py -> SMOKE E2E: PASSED, which exercises the real embed
(llama.cpp), the real rerank (BGE-M3) and a real index search, i.e. the
network stack urllib3 actually backs
…y guard as UNPROVEN CI reported `NEGATIVE CONTROLS: FAILED (broken=0, unproven=1)` with `dead_guard_classifier` marked UNPROVEN — green locally, red on every runner. Root cause: tests/test_negative_controls_runner.py proved the digest pin by editing the REAL fixture scripts/negative_controls/fixtures/dead_guard.py and restoring it in `finally`. Under `pytest -n auto` another worker read that fixture's digest inside the window between the write and the restore, computed a different digest, and classified a healthy guard as UNPROVEN. The digest guard was never wrong; the race was between two tests, and it presented as a guard defect. Every digest matched locally and in a clean checkout, which is why this survived local verification — the trigger is worker count, not content. The test now copies the fixture into a scratch directory it creates and removes, and never touches the tracked file. It asserts a PROVEN control before mutating, so the property under test is still "a byte change flips PROVEN to UNPROVEN". Adds tests/test_no_tracked_file_mutation.py so the class cannot come back. It is a test rather than a script because a script nobody runs is not a gate, and its first version collected zero tests under pytest while reading as coverage. That guard's selftest earned its place immediately: it caught a real second instance in tests/test_planted_break_gate.py, which wrote experiments/planted_break/results.json from two xdist workers with no atomicity. That write is now temp-file + os.replace, the artifact is gitignored, and the one exemption is recorded with its reason. Verified: 1991 passed, 6 skipped, two consecutive runs of the exact CI command with -n auto.
check_third_party_data: R1 personal email, R2 exported-profile signature, R3 bulk dump (advisory). Vendored dependency metadata is allowlisted as legitimate attribution. --selftest proves positive 2/2 and negative 2/2 so a matcher that cannot fail cannot pass; --all over 1897 tracked files reports blocking=0. check_parallel_sessions: lists foreign worktrees with branches and uncommitted files, blocks when a staged file is also modified in another tree, advisory otherwise. Wired into .githooks/pre-commit; AGENTS.md documents both. Three defects were found while verifying them. Each is reproduced by a test. 1. GIT_DIR leak. git exports GIT_DIR into the hook environment and _git() inherited it, so 'git -C <other worktree> status' kept reading the CURRENT repository. The gate inspected the wrong tree: with GIT_DIR set it reported three pre-commit-stage files as modified in D:/Project/wt-pr-v3 and exited 1 while that worktree was clean. Bidirectional - it also let real cross-tree conflicts through. Fix drops GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/ GIT_COMMON_DIR from the child environment. 2. The third-party gate could not be tested at all. Its R1 fixture held a real person's address (pascal.cescato@gmail.com), so committing the detector would have published a third party's email - exactly what the rule forbids. Test fixtures used gmail.com addresses and tripped R1 on synthetic data. Both now use the RFC 2606 reserved domain personal.invalid, which can never be registered, and personal_domains is injectable so R1 is still proven to fire. 3. R2 counted 11 profile markers in the detector itself, because PROFILE_MARKERS lives in that file. R2 is skipped for exactly two paths; R1 still applies to them, so a dump cannot be hidden there.
gate_zero_full_suite() picked pythonw.exe on Windows to avoid a console flash. pythonw has no console, so every test that spawns a subprocess (git, lock helpers, discriminators) dies inside subprocess with OSError [WinError 50]. Measured on the same tree and commit: 'python -m pytest tests/' gives 2006 passed and 0 failed, 'pythonw.exe -m pytest tests/' gives 72 failed and 6 errors, every failure WinError 50 from subprocess. CREATE_NO_WINDOW already suppresses the console window, so pythonw bought nothing and cost the entire gate.
…gates Adds the session's own notes on the parallel-session incidents, the third-party data audit and the verification gate work. KNOWN_ISSUES.md was 366 lines against a 300-line limit, so check_known_issues failed and blocked every commit. Rotated 79 lines of closed entries per the monthly-archival rule: only sections whose own header carries Fixed/Closed/ REFUTED, no Open and no P1 moved. Closed entries from 2026-09 went to docs/archive/KNOWN_ISSUES_2026_09.md, the 2026-10-03 one to a new KNOWN_ISSUES_2026_10.md. Live file is 289 lines; open items untouched. While rotating, found two pre-existing defects NOT caused by this change and deliberately left alone: docs/archive/KNOWN_ISSUES_2026_09.md holds the 'Exp E13' section four times over roughly 700 lines in two encodings, and the live file carries CP1251-read-as-UTF-8 mojibake in the 2026-09-19 onward headers. Both belong to the registry owner.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
added 2 commits
October 3, 2026 14:35
…ISSUES origin/main carried a parallel session's work: protocol commands, tools/verification (13 files, working gate), tools/knowledge registries, claims-audit and portability experiments. Conflicts in AGENT_DIARY.md, KNOWN_ISSUES.md, WISDOM.md and docs/archive/KNOWN_ISSUES_2026_09.md were resolved by union, not ours/theirs. A section-level union silently dropped 6 substantive WISDOM.md lines, so merge_registry_union.py merges line-wise inside shared headings and verifies zero loss on both sides from the raw git stages. KNOWN_ISSUES.md exceeded the 300-line cap after the union (367); rotate_known_issues.py moves only entries with an explicit closed marker in their own heading. A first rule of 'no word Open' would have archived open work whose heading simply had no status.
The runner resolved bash via shutil.which only. From an agent shell Git's bin dir is often absent from PATH, so the WSL shim System32\\bash.exe won the lookup and the resolver returned None, reporting drift_gate as BROKEN even though GitBash was installed. That made the pre-commit chain unusable outside the author's own shell. Now also probes the standard Git install roots and the root implied by the git on PATH. drift_gate goes BROKEN -> PROVEN, and the whole hook passes: ALL PROVEN (3).
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.
Adds two pre-commit gates that block the failure modes this repo already hit, and fixes three defects found while verifying them.
Gates
*\check_third_party_data* - R1 personal email, R2 exported-profile signature, R3 bulk dump (advisory). Vendored dependency metadata is allowlisted as legitimate attribution. Verified: --selftest\ positive 2/2 and negative 2/2 (the control can fail), --all\ over 1897 tracked files reports blocking=0 advisory=0.
*\check_parallel_sessions* - lists foreign worktrees with branches and uncommitted files, blocks when a staged file is also modified in another tree, advisory otherwise.
Defects found during verification
\GIT_DIR\ leak (gate was reading the wrong repository). git exports \GIT_DIR\ into the hook environment; _git()\ inherited it, so \git -C status\ kept reading the current repo. The gate reported three pre-commit-stage files as modified in a worktree that was clean, and exited 1. The error is bidirectional - it also let real cross-tree conflicts through. Reproduced before and after the fix.
The third-party gate could not be tested at all. Its R1 fixture contained a real person's address, so committing the detector would have published a third party's email - exactly what the rule forbids. Fixtures now use the RFC 2606 reserved domain \personal.invalid, which can never be registered.
R2 counted 11 profile markers in the detector itself, because \PROFILE_MARKERS\ lives in that file. R2 is skipped for exactly two paths; R1 still applies to them.
**\gate-zero\ ran pytest under \pythonw.exe**, which has no console, so every test spawning a subprocess failed with \OSError [WinError 50]. Same tree, same commit: \python -m pytest tests/\ → 2006 passed; \pythonw.exe -m pytest tests/\ → 72 failed + 6 errors. This is what produced the intermittent \INTERNALERROR\ seen on earlier commits.
Registry
\KNOWN_ISSUES.md\ was 366 lines against a 300-line limit, which blocked every commit. Rotated 79 lines of closed entries per the archival rule - only sections whose own header carries Fixed/Closed/REFUTED; no Open and no P1 moved. Live file is 289 lines.
Two pre-existing defects were found and deliberately not touched: \docs/archive/KNOWN_ISSUES_2026_09.md\ contains the \Exp E13\ section four times over ~700 lines in two encodings, and the live file has CP1251-read-as-UTF-8 mojibake in the 2026-09-19 onward headers.
Verification
\python -m pytest tests/\ → 2006 passed, 6 skipped. Gate-zero green. All gates green.