ci: gate every plugin hooks.json on a top-level description - #3764
Conversation
The plugins reference gives hooks.json an optional top-level description, the one place a plugin labels its hooks as a set. The 2026-09-04 audit found it absent in 20 of 20 plugins; #3727 and #3750 added it to every file, and nothing read the field, so nothing would notice a new plugin shipping without it or a rewrite dropping it. scripts/check-hooks-description.sh fails a hooks.json whose description is absent, not a string, blank or multi-line, fails closed on a file that does not parse, and skips a plugin with no hooks. Its suite covers each shape, a CRLF checkout, and the live tree; the lint lane runs the suite first, then the gate, and reports it into ci-status alongside the sibling hook gates. Closes #3752 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DaWEB8Daq1xAXy2Xj1Pme
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 2m 36s —— View job Review complete
No blocking findings. This is a clean, well-scoped gate addition. What I checked
Not independently verifiedI could not execute shell scripts in this environment (this lane's tool grant is |
|
Claude finished @kyle-sexton's task in 57s —— View job Security review
No security issues found. This PR adds a CI lint gate ( Checked and ruled out:
This is a self-contained CI/lint addition with no security-relevant surface — skipping deeper review per the skip gate. |
|
Last security-reviewed head: |
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1c31d299d6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A hooks.json whose first document is well-formed but carries trailing garbage made jq print a verdict and then exit non-zero; the gate read only the word and cleared a file Claude Code cannot load. The status is now checked separately from the output, and more than one verdict word (two concatenated documents) is a failure too. Two fixtures pin both shapes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DaWEB8Daq1xAXy2Xj1Pme
#3773 put `if: needs.changes.outputs.run_shell == 'true'` on every detector self-test step in the lint lane, so a diff that changes no shell file skips the proof that the detector still works while the detector itself keeps running. This branch's new self-test pair was written before that landed and merged in clean, leaving the one ungated self-test step in the job. Nothing enforces the shape: check-lane-coverage.sh reads job-to-aggregate reachability, not step conditions, so the inconsistency would have shipped green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DaWEB8Daq1xAXy2Xj1Pme
Closes #3752
Summary
The plugins reference gives
hooks/hooks.jsonan optional top-leveldescription, the one place a plugin labels its hooks as a set. The issue counted it absent in 19 of 20 plugins, but #3727 landed a description in every file after the issue was filed, so the descriptions half is already onmain. What was still missing is the gate that stops the count drifting back, and this PR adds it. No plugin file changes and no version bumps.Fix
scripts/check-hooks-description.sh: scansplugins/*/hooks/hooks.json, skips a plugin with no hooks, and fails a file whose top-leveldescriptionis absent, not a string, blank, or multi-line. A file that does not parse fails closed. Basis and recheck trigger are in the script header.scripts/check-hooks-description.test.sh: one fixture per shape (missing, blank, whitespace, number, null, multi-line, unparsable), a CRLF-terminated file, a hook-less plugin, a mixed tree naming every failing file with the summary count, and the live tree..github/workflows/ci.yml: the lint lane runs the suite, then the gate, and reports it intoci-statusbeside the sibling hook gates.Verification
bash scripts/check-hooks-description.test.sh: PASS=12 FAIL=0.scripts/check-hooks-description.shon the live tree: every hooks.json (20) carries a one-line description.scripts/affected-tests.sh --run(the ci.yml change selects the wholescripts/*.test.shset): 149 shell suites passed or were skipped, exit 0.scripts/check-lane-coverage.sh --check,scripts/check-discriminating-test-skips.sh, shellcheck, shfmt, typos: clean.Related
🤖 Generated with Claude Code
https://claude.ai/code/session_019DaWEB8Daq1xAXy2Xj1Pme
Generated by Claude Code