gate: an unchecked file is not a clean file - #296
Open
Conversation
4 tasks
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_d0f306f0-20dc-4761-af99-ba40311edccb) |
OwnerAuthor
This pull request is part of a Mergify stack:
|
A detector that opens a file has a third outcome besides hit and clean: input it could not read. A size cap that silently skips anything larger reports an unchecked file as clean, which is the opposite of what a guard is for. check_hook_test_coverage now requires any file-reading detector to have a test that pins its unreadable-input behavior. Fail open or fail closed stays the hook's own documented choice; leaving it untested does not. scope-lock was the one real gap the new rule found: its state file fails open and its transcript read fails closed, both now asserted. The evidence rules gain the general form, grounded in Saltzer and Schroeder's fail-safe defaults. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KU2pPKob4MJ1NqjsfTNyYJ Change-Id: Ifa24ac4d096e44be20c30733c5beea8d9218e578
EdbertChan
changed the base branch from
stack/EdbertChan/reflect/ui-input-guard-hook-freshness-20260908/wire-ui-input-guard-hook-freshness-inventories--09cebee8
to
mainSeptember 9, 2026 06:22
EdbertChanforce-pushed
the
stack/EdbertChan/reflect/ui-input-guard-hook-freshness-20260908/unchecked-file-clean-file--fa24ac4d
branch
from
September 9, 2026 06:22
c43becf to
4b02d65CompareEdbertChan
changed the base branch from
main
to
stack/EdbertChan/reflect/ui-input-guard-hook-freshness-20260908/catch-concession-user-found-miss--5b8f852aSeptember 9, 2026 06:22
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_14422852-611f-44c2-bda6-5e13feeb7f13) |
4 tasks
EdbertChan
commented
Sep 9, 2026
OwnerAuthor
Revision history
|
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 freeto 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.
Summary
A detector that opens a file has three possible outcomes, not two: it found the thing, it did not find the thing, or it could not read the input at all. Collapsing the third into the second is how a guard reports an unchecked file as clean.
That is not hypothetical. The first version of
ui-input-guardin this stack skipped any wrapper script over 64 KB and any path holding an unresolved shell variable, and returned "clean" for both. The user caught it in review with "why would you submit a rule or principle that would ignore files straight up".check_hook_test_coveragenow requires any file-reading detector to carry a test that pins its unreadable-input behavior. Fail open or fail closed remains the hook's own documented choice; leaving it untested does not.scope-lockwas the single real gap the new rule found across 23 hooks. Its two reads resolve in opposite directions on purpose: a corrupt state file means no lock is in force, while an unreadable transcript means no scope contract was recorded, so an existing lock is not released by a file that could not be read. Both are now asserted.Review Claim
A file-reading hook detector cannot land without a test pinning what it does with input it could not read.
Review Lane
behavior
Review Unit
tooling-policy
Safety Invariant
The gate only adds a third requirement alongside the existing positive and negative ones, and only for detectors whose source opens or sizes a file. An inline-only detector is unaffected, a missing or unreadable
detect.pymakes the new check answer no rather than raise, and the accepted test names include the fail-open vocabulary already in use, so no existing hook had to change its behavior to pass. Onescope-locktest file gained assertions; no detector logic changed.Slice Rationale
The general rule and its enforcement are separable from the hook that motivated them, and this slice is the one a future detector actually collides with.
Non-goals
Does not decide direction for anyone: the gate never asserts that a given hook must fail closed. Does not inspect what a test body proves, only that a test named for the unreadable case exists. Does not extend the same rule to skills or scripts outside
engine/hooks/.Test Plan
Test Plan
python3 -m unittest discover -s tests -p "test_check_hook_test_coverage.py"— 8 tests, OK (fires on a file-reading detector with no unreadable test, silent once one exists, silent for an inline-only detector, and asserts the real repo passes)python3 -m unittest discover -s engine/hooks/scope-lock/tests— 35 tests, OK (4 new)python3 scripts/check_hook_test_coverage.py— OK (23 hooks)python3 scripts/check_no_dated_provenance.py --base origin/main— okpython3 scripts/check_codify_has_code.py --base origin/main— okRevert Plan
Revert Plan
git revert <sha>🤖 Generated with Claude Code
https://claude.ai/code/session_01KU2pPKob4MJ1NqjsfTNyYJ