v1.20.1 — the filter that was never read, and the check that would have said so - #20
Merged
Merged
Conversation
…ve said so
Claude Code 2.1.270 prints `agent-sync: hooks.json: unknown key "if" in
hooks.PreToolUse[1] ignored` at every session start. The key was there since
0.1.0. Read out of the binary's hook schema: a matcher group is `{matcher,
hooks}` and nothing else; `if` exists on a command handler only. So the filter
was declared and never evaluated — guard.sh has run on every Bash call in a
coordinated project for its whole life, narrowing to a commit with its own
parser. Nothing in behaviour changes with the key gone; the warning does.
Removed rather than moved: a handler-level `if` would be real, and a real
`Bash(git commit *)` skips `git -C <dir> commit`, `env X=1 git commit` and
`cd d && git commit` — the forms the parser covers. hooks.json's description,
guard.sh's header, references/hooks.md, the README hook table and the live
AS-09 row say the same thing; dated records keep their wording.
`check_hooks_manifest` refuses any key Claude Code does not know at either
level, with a self-test plant that puts the old `if` back and watches the
check fire (`claude plugin validate --strict` passes the defective file).
`fix-sy-07.01.py` derived "git commit is covered" from the group's `if`; it
now asserts the matchers, the description and the absence of `if`.
Gate: npm test EXIT=0 — PASS: agent-sync v1.20.1 — all checks green;
SELF-TEST PASS (61 fixtures); claim cell 24; SessionStart identity 6;
installer 11.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y8geRdSG7rAD3xcGTrZpoZ
sshlg
added a commit
to ssheleg/sshlg-skills
that referenced
this pull request
Sep 13, 2026
… runs here All three homes move together: skills.json, the submodule pointer (a0c9825, the squash-merge of ssheleg/agent-sync#20, tagged v1.20.1) and the README table; the CTX-04.06 staging receipt regenerated rather than edited, as #127 did. Registry read: `npm view @ssheleg/agent-sync version` → 1.20.1; `python3 test/check_pins.py` → every pin matches its release. task-pipeline's pin waits for #92 (validate at step ~207 of 465). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y8geRdSG7rAD3xcGTrZpoZ
sshlg
added a commit
to ssheleg/sshlg-skills
that referenced
this pull request
Sep 14, 2026
… it (#137) * Family audit 2026-09-13 — the hook key nobody read, and `injectors` cites the running version Claude Code 2.1.270 prints `agent-sync: hooks.json: unknown key "if" in hooks.PreToolUse[1] ignored` at every session start. Read out of the binary's hook schema: a matcher group is `{matcher, hooks}`; `if` exists on a handler only. The key filtered nothing since agent-sync 0.1.0, `claude plugin validate --strict` passes it, and the same shape sat in task-pipeline's exported template. Fixed in agent-sync v1.20.1 and task-pipeline v1.86.2 (in flight); the pins move here once both are on the registry. This commit: - `lib/injectors.js` consulted the plugin cache in directory order and cited agent-sync's hooks.json at 1.18.6 while 1.20.0 was running. It now reads the version `installed_plugins.json` names first, then newest semver (`orderVersions`, `installedVersion`; +5 fixtures, `injectors_test.js` 14 checks). Verified live against this machine's registry. - `docs/evidence/audits/2026-09-13-family-hooks/` — the audit (ten gates, four read-only auditors over 28 skills, 1,104 doc addresses) and a 13-task plan where every task carries a packet an unfamiliar agent can execute, plus the model-routing table (Fable high plans, Opus high/xhigh executes). - `docs/HANDOFF.md` points at that plan as the active one. - DOCMAP ratchet re-derived: fixtures 1014 → 1019. Gate: node test/run.js → PASS: 87 checks green; COUNTED 87 suites, 1019 fixtures, 9 pinned members. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y8geRdSG7rAD3xcGTrZpoZ * Pin agent-sync to v1.20.1 — the hook key is gone from the plugin that runs here All three homes move together: skills.json, the submodule pointer (a0c9825, the squash-merge of ssheleg/agent-sync#20, tagged v1.20.1) and the README table; the CTX-04.06 staging receipt regenerated rather than edited, as #127 did. Registry read: `npm view @ssheleg/agent-sync version` → 1.20.1; `python3 test/check_pins.py` → every pin matches its release. task-pipeline's pin waits for #92 (validate at step ~207 of 465). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y8geRdSG7rAD3xcGTrZpoZ * Guard: a pipe into `python3 -` beside a heredoc is one stdin with two passengers Measured on the operator's own agent, 2026-09-14: `heroku config:get DATABASE_URL -a app | python3 - <<'PY'`. The pipe and the heredoc both fed stdin, the pipe won, the interpreter parsed the connection string as source and SyntaxError printed the line it could not parse — password included. The agent was protecting the value from argv and did not see the channel was already taken by the program. New rule `secret-into-stdin-program`: any pipe into an interpreter that reads its code from stdin (`python3 -`, `python -`, `node -`, `ruby -`, `perl -`, `sh|bash|zsh -s`) with a heredoc beside it is refused, with the two fixes: put the program in a file (`… | python3 probe.py`), or hand the value over as a variable with the output scrubbed (project-observatory's `tools/use_secret.py pipe NAME -- python3 probe.py`). The producer's shape is not checked — the mistake is the same whoever is upstream. Two cases in test/secrets_test.js; 35 checks green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * DOCMAP ratchet: fixtures 1019 -> 1021 — the two stdin-program cases Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * DOCMAP: the Ratchets sentence follows its marker (fixtures=1021) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Pin seven members at the releases the 2026-09-13 audit produced All three homes move together for each: skills.json, the submodule pointer at the annotated tag, and the README table. Registry-confirmed before the pin — `python3 test/check_pins.py` reports `ok` for all seven and BEHIND for the two still in flight (super-ux 0.56.2, task-pipeline 1.87.0), which is the honest state rather than a pin to something nobody published. agent-sync 1.20.1 → 1.20.2 the operator reap reaches the git plane make-skill 0.28.0 → 0.29.0 HOOKS_SCHEMA, the check that closes the class sheleg-design 1.60.2 → 1.61.0 17 KB of doctrine becomes reachable seo-aeo-audit 0.26.0 → 0.26.1 B-27 closes; the estimator was the defect sheleg-dev 0.12.0 → 0.13.0 degradation in all seven bodies agent-stack 0.24.2 → 0.24.3 the budget is measured, not estimated telegram-dev 0.2.0 → 0.2.1 both invocation forms in the README The CTX-04.06 staging receipt was regenerated rather than edited. DOCMAP ratchet re-derived: fixtures 1019 → 1021. Gate: node test/run.js → PASS, 87 suites, 1021 fixtures, 9 pinned members. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pin super-ux at 0.56.2 Registry-confirmed: npm view super-ux version -> 0.56.2. All three homes move together; the CTX-04.06 staging receipt regenerated rather than edited. task-pipeline stays BEHIND until 1.87.0 publishes — an honest state, not a pin to something nobody served. Gate: node test/run.js -> PASS, 87 suites, 1021 fixtures, 9 pinned members. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pin task-pipeline at 1.87.0 — the plan-audit gate the operator asked for The ninth and last pin of this wave. All three homes move together; `check_pins.py` now reports `every pin matches its release` across the set. The CTX-04.06 staging receipt was regenerated rather than edited. v1.87.0 is stage 4's own gate: every live node's packet must answer the cold reader's eight questions, two nodes the GRAPH leaves unordered may not edit one file, priority is computed from what each node unblocks, and a recorded per-stage model map is checked. Plus the plan-then-execute profile, with its basis written down. Gate: node test/run.js -> PASS, 87 suites, 1021 fixtures, 9 pinned members. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Робот <r@e.com>
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.
What
Claude Code 2.1.270 prints
agent-sync: hooks.json: unknown key "if" in hooks.PreToolUse[1] ignoredat every session start. Read out of the 2.1.270 binary's hook schema: a matcher group is{matcher, hooks};ifexists on a command handler only. The key sat besidematchersince 0.1.0 — declared, never evaluated.guard.shhas always narrowed to a commit with its own parser, so behaviour does not change; the warning goes.Why removed, not moved
A handler-level
ifwould be real, and a realBash(git commit *)skipsgit -C <dir> commit,env X=1 git commitandcd d && git commit— the forms the parser exists to cover (2026-08-07 measurement).Change
hooks.json: key removed; description says why there is noifguard.shheader,references/hooks.md, README hook table, live AS-09 row: same statementtest/validate.pycheck_hooks_manifest: refuses any key outside the schema at either level; self-test planthooks.json key at the wrong level(the exact file that shipped 0.1.0→1.20.0) → detectedtest/audit_regressions/fix-sy-07.01.py: coverage from matchers + description, asserts noifat either levelVerification
npm testEXIT=0:PASS: agent-sync v1.20.1 — all checks green;SELF-TEST PASS(61 fixtures); claim cell 24; SessionStart identity 6; installer 11.Sibling: task-pipeline #92 moves the same key onto the handler in its exported template.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Y8geRdSG7rAD3xcGTrZpoZ