fix(hooks): state-line-guard ratchets against current size, not a flat gate
Advisor review caught this before the v0.23.0 tag landed: the guard compared the projected line count only against the fixed 60-line max, never against the file's current size, so trimming an already-oversized STATE.md (e.g. 156 -> 100 lines, still over 60 but smaller) was denied exactly like growing it would be. Verified against the real tree: 23 of the machine's STATE.md files are already over 60 lines today, one at 1405. Shipped as a flat gate, this hook would have made most of them un-editable except by a single write landing at <=60 in one shot -- backwards for a guard meant to make trimming possible. Fixed with a ratchet: deny only when the projection is over the max AND larger than the file's current line count (0 for a file that doesn't exist yet), for both Write and Edit. A compliant file still cannot grow past the limit and a new file still cannot be created oversized, but an oversized file can now be edited toward compliance one write at a time. state-line-guard-selftest.sh: 16 -> 21 checks (new section 8: shrink allows, same-size allows, grow-while-oversized still denies, new-oversized still denies). Suite total: 191 + 152 + 69 + 21 = 433. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186kZGKddxfA9N84HqMLbb2
This commit is contained in:
parent
f39c0df929
commit
c1dabf109d
5 changed files with 154 additions and 10 deletions
27
CLAUDE.md
27
CLAUDE.md
|
|
@ -75,7 +75,7 @@ marketplace plugin. Three components, one boundary:
|
|||
otherwise only the first, mirroring what the real Edit tool does. Getting
|
||||
`replace_all` wrong in either direction is not a hypothetical: a hook that
|
||||
only ever replaced the first occurrence would silently pass a bulk edit that
|
||||
balloons the file, so `state-line-guard-selftest.sh` (16 checks) pins a
|
||||
balloons the file, so `state-line-guard-selftest.sh` (21 checks) pins a
|
||||
fixture where only counting every `replace_all` occurrence produces the
|
||||
correct denial. Anything the hook cannot project with confidence — a
|
||||
missing file, an `old_string` that is not present, fields of the wrong
|
||||
|
|
@ -83,6 +83,29 @@ marketplace plugin. Three components, one boundary:
|
|||
here would; the guard only ever touches files named exactly `STATE.md`, at
|
||||
any depth, matching the same basename rule the global session-start hook's
|
||||
nearest-STATE-wins search already uses.
|
||||
|
||||
**It is a RATCHET against the file's current size, not a flat gate at 60 —
|
||||
found by advisor review before the tag landed, not by the selftest, which
|
||||
had no fixture for it.** The first cut compared the projected line count
|
||||
only against `MAX_LINES`, never against what the file already was, so
|
||||
trimming an oversized STATE.md from, say, 156 to 100 lines — still over 60,
|
||||
but strictly smaller — was denied exactly like growing it would have been.
|
||||
Verified empirically against the real tree (2026-08-14):
|
||||
`wc -l ~/repos/*/STATE.md ~/repos/*/*/STATE.md | awk '$1 > 60'` found 23
|
||||
files already over 60 lines, one at 1405. Shipped as a flat gate, this hook
|
||||
would have made most of the machine's STATE.md files un-editable except by
|
||||
a single write landing at `<=60` in one shot — backwards for a guard whose
|
||||
whole point is making the trim the /insights finding asked for actually
|
||||
possible. The fix reads the file's current line count for BOTH tool types
|
||||
(previously only `Edit` read the file at all) and denies only when the
|
||||
projection is over `MAX_LINES` **and** larger than that current count: a
|
||||
compliant file still cannot grow past the limit, a brand-new file still
|
||||
cannot be created oversized (current defaults to 0), but an already-oversized
|
||||
file can always be edited toward compliance, one write at a time, without
|
||||
ever making it worse. Section 8 of the selftest pins all four cases:
|
||||
shrink-while-still-over-limit allows, same-size-rewrite allows, grow-an-
|
||||
already-oversized-file still denies, and create-new-oversized-file still
|
||||
denies.
|
||||
- **Board (`scripts/board.sh`):** cross-repo attention board. Reads STATE.md
|
||||
next-step blocks + board lines, `git status`, and mailbox pending counts, and
|
||||
prints one line per repo. Read-only by construction: it writes to no repo, no
|
||||
|
|
@ -395,7 +418,7 @@ obligations in another repo.
|
|||
`bash scripts/coord-selftest.sh` must exit 0 (191/191),
|
||||
`bash scripts/board-selftest.sh` must exit 0 (152/152),
|
||||
`bash scripts/route-selftest.sh` must exit 0 (69/69) and
|
||||
`bash scripts/state-line-guard-selftest.sh` must exit 0 (16/16).
|
||||
`bash scripts/state-line-guard-selftest.sh` must exit 0 (21/21).
|
||||
- English for all code, docs, and commit messages (public repo). Norwegian
|
||||
trigger aliases in the skill description are deliberate.
|
||||
- Conventional Commits: `type(scope): description`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue