You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/guardrails:setup apply install-git-hooks scope=shared (guardrails 0.55.4, lib/git-hooks/install.mjs copy --scope shared) produces copies that fail a consuming repository's own CI, so every repository adopting the shared entries needs the same manual fix-up. Seen on melodic-software/standards#852:
Executable bit. The installer stages the copies as mode 100644. Seven of them carry a shebang (check-lib.sh, cli-flag-verify.sh, resolve-convention-pattern.sh, run-guards.sh, skill-reference-verify.sh, stale-path-verify.sh, verify-cli-flag.sh), and standards' check-repo-hygiene rejects that: has a shebang but git index mode is 100644; run: git update-index --chmod=+x.
Lint of vendored copies. The repository's ShellCheck lanes (lefthook pre-commit and the ci-workflows shellcheck action) lint .githooks/guardrails/ and fail on the copies (SC2218 and others under that repo's .shellcheckrc). The pilot added .githooks/guardrails/** to the pre-commit exclude and .githooks/guardrails/ to the action's exclude; nothing in plan tells the operator to do this.
Cost of the first commit.guardrails-pre-commit-content scanned the ~10.7k vendored lines for 70 s on the install commit (0.15 s on a normal commit afterwards).
Expected
copy stages shebang files as 100755 (or plan returns a decision to).
plan returns a decision naming the repository's linters that will see .githooks/guardrails/ (or the copies pass ShellCheck under a default rc), so the exclusion is part of the install, not discovered in CI.
pre-commit-content skips its own plugin-owned copies.
Related
Rolling the shared entries out across the melodic-software repositories; each would hit 1 and 2.
Proposed work class: work-class: scoped
Basis: automated intake triage; the lanes App applied this class.
Size: Medium
Complexity: Medium
Uncertainty: Known
Flags: none
Blocked by: none
Decision recorded. (agent; not an owner decision) #12402 builds findings 1 and 8, which the 2026-10-31 record left unbuilt: a shared install now stages and writes every shebang copy as 100755/0755, and a rerun repairs a wrong exec bit. Basis: copy still writes copies for plain and husky shared installs (plugins/guardrails/lib/git-hooks/install.mjs:919-928 at 13617b6; plugins/guardrails/git-hooks/pre-commit-content.test.sh:363 installs plain shared), and the fix is internal to the installer with no new mechanism. The PR uses Refs:; the five acceptance criteria of the 2026-10-31 record and finding 2 stay open here.
I read this as a defect in guardrails' shared git-hooks install. The latest recorded decision settles the open questions: the exec-bit fix is in progress in #12402, and the remaining acceptance criteria and finding 2 (plan naming linters) are still open work. No person's decision is pending. I found no duplicate among open issues.
Not admitted to the issue lane: its done-when asks for what an unattended lane run cannot perform: item 14 (a comment instead of a file change: "A comment on this issue records findings 1-3, 8-11 and the machine-path comme..."); recommended split: keep the other items here as the admissible issue and move these to a child issue for the host queue (host-run); it carries host-run. Admission takes the issue once each of those is met, when intake triages it again (.github/actions/resolve-config/admission-rules.json).
A third failure from the same copies: the repo's check-machine-paths CI step flags the example paths in comments of .githooks/guardrails/machine-path-patterns.sh:41 and hardcoded-path-patterns.sh:37 (they self-match, like a pattern source). The pilot added ':(exclude).githooks/guardrails/**' to that step in standards#852. plan should name this exclusion too, or the comments should use placeholders.
reference-verify.sh silently skips files over the per-argument limit. It builds each payload with jq -n --arg c "$text" (lines ~123 and ~131 of the 0.55.4 copy). A file whose content passes the Linux per-argument limit (128 KiB) fails with Argument list too long before jq starts, the payload is empty, no finding is produced, and the hook exits 0, so all three reference checks are skipped for that file. Found by the Codex review on the pilot, reproduced on the 238,555-byte hook-utils.sh. Fix: feed the content through stdin or a temp file (jq --rawfile), in both the Write and Edit branches, and fail on a payload-construction error.
No repo-side exemption for a pattern source. In the observation replay of standards' last 100 commits, the only pre-commit-content finding was components/cloud-environment/pages-publish (a scanner whose pattern bodies document /home/<x> and /Users/<x> forms): it self-matches, as the plugin's own pattern libraries do (path_exempt lists them). path_exempt is hard-coded in the copy, so a consumer cannot add its own pattern source without editing a copy. A tracked exemption list read from the repo would cover it.
More from the rollout in this repository (#9462), guardrails 0.55.4:
cli-flag-verify reads flags inside a quoted prompt. The reference-verify replay of origin/main~200..origin/main reported claude on-demand --scheduled (not in 'claude on-demand --help') for plugins/machine-health/CHANGELOG.md and plugins/machine-health/skills/setup/SKILL.md. The text is claude -p "/machine-health:audit on-demand --scheduled": --scheduled is a skill argument inside the -p prompt string, not a CLI flag. The finding's line number is the file's first changed line (first_line in reference-verify.sh), not the line holding the flag (6 and 2 here, against 29 and 345), so the reader has to search for it.
Item 4 seen live on the install push. The push that adds the copies sends .githooks/guardrails/hook-utils.sh (238,555 bytes) whole, as a new file; reference-verify.sh printed line 125: .../jq: Argument list too long and the job still passed. Every repository's install push skips that file this way.
On-disk mode.copy writes seven shebang copies 0644 on disk as well as in the index; after git update-index --chmod=+x they show as mode changes in git status until chmod +x, and scripts/check-affected.sh here skips every check while they do.
Consumer lint mirrors. This repository's local scripts/check-affected.sh ShellCheck list does not read the workflow's exclude:, so the pre-push job blocks any push that changes the copies; and scripts/affected-tests.sh reports the copies as UNMAPPED. Both are repo-side follow-ups here, noted for the plan decision that names linters (item 2).
Item 2 follow-up from the dotfiles rollout (dotfiles#1293): a consumer that runs ShellCheck through the ci-workflowspr-run-checks.yml reusable cannot exclude the copies. The reusable's Lint shell scripts step passes no inputs to the shellcheck composite (at ab83b01, v0.39.3, and on ci-workflows main as of 2026-10-23), so .githooks/guardrails/ is linted and fails on SC2218 (run-guards.sh:569, error level), SC2329 (run-guards.sh:744) and SC1091. The repo-side workaround the pilot used (the composite's own exclude:) only reaches a direct call of the composite. Fix options: make the copies ShellCheck-clean under a strict rc (removes the need for any exclusion), or add a shellcheck-exclude input to the reusable.
Host run. Fixed the file modes install.mjs copy --scope shared gives its copies (findings 1 and 8), at the canonical lib/git-hooks/install.mjs, and regenerated the ten plugin copies.
What ran:
Edited lib/git-hooks/install.mjs: a support copy (the check lib or an asset) that starts with #! is written 0755 and staged 100755. Any other copy is written 0644 and staged 100644 (--chmod=-x). When a copy's exec bit is wrong, a rerun rewrites the copy and reports refreshed. Stable copies made by configHook follow the same rule.
scripts/sync-shared-copies.sh regenerated the copies, and --check passes: all 567 copies match.
New contract test in lib/git-hooks/install.test.mjs. It fails on the old installer and passes on the new one. The whole file passes: 73 pass, 4 skipped for git below 2.54.
Scratch-repo probe of the real guardrails plugin (all four entries, shared, plain): 14 shebang files are all 100755 and executable on disk, every other file is 100644, 0 violations. The seven files the issue named are among them.
scripts/check-affected.sh --tests on the committed head: 13 passed, 3 skipped.
Remaining on this issue: the five acceptance criteria in the 2026-10-31 decision, and finding 2 (plan naming the linters that will see the copies). No consumer repository needs a change for this fix.
Activity
github-actions commentedon Oct 23, 2026
Proposed work class: work-class: scoped
Basis: automated intake triage; the lanes App applied this class.
Size: Medium
Complexity: Medium
Uncertainty: Known
Flags: none
Blocked by: none
I read this as a defect in guardrails' shared git-hooks install. The latest recorded decision settles the open questions: the exec-bit fix is in progress in #12402, and the remaining acceptance criteria and finding 2 (plan naming linters) are still open work. No person's decision is pending. I found no duplicate among open issues.
Automated triage, applied by the lanes App.
melodic-automation-lanes commentedon Oct 23, 2026
Not admitted to the issue lane: its done-when asks for what an unattended lane run cannot perform: item 14 (a comment instead of a file change: "A comment on this issue records findings 1-3, 8-11 and the machine-path comme..."); recommended split: keep the other items here as the admissible issue and move these to a child issue for the host queue (
host-run); it carries host-run. Admission takes the issue once each of those is met, when intake triages it again (.github/actions/resolve-config/admission-rules.json).kyle-sexton commentedon Oct 23, 2026
A third failure from the same copies: the repo's
check-machine-pathsCI step flags the example paths in comments of.githooks/guardrails/machine-path-patterns.sh:41andhardcoded-path-patterns.sh:37(they self-match, like a pattern source). The pilot added':(exclude).githooks/guardrails/**'to that step in standards#852.planshould name this exclusion too, or the comments should use placeholders.kyle-sexton commentedon Oct 23, 2026
Two more from the standards#852 pilot:
reference-verify.shsilently skips files over the per-argument limit. It builds each payload withjq -n --arg c "$text"(lines ~123 and ~131 of the 0.55.4 copy). A file whose content passes the Linux per-argument limit (128 KiB) fails withArgument list too longbefore jq starts, the payload is empty, no finding is produced, and the hook exits 0, so all three reference checks are skipped for that file. Found by the Codex review on the pilot, reproduced on the 238,555-bytehook-utils.sh. Fix: feed the content through stdin or a temp file (jq --rawfile), in both the Write and Edit branches, and fail on a payload-construction error.pre-commit-contentfinding wascomponents/cloud-environment/pages-publish(a scanner whose pattern bodies document/home/<x>and/Users/<x>forms): it self-matches, as the plugin's own pattern libraries do (path_exemptlists them).path_exemptis hard-coded in the copy, so a consumer cannot add its own pattern source without editing a copy. A tracked exemption list read from the repo would cover it.chore(git-hooks): install the guardrails git hooks as shared lefthook…
kyle-sexton commentedon Oct 23, 2026
More from the rollout in this repository (#9462), guardrails 0.55.4:
cli-flag-verifyreads flags inside a quoted prompt. Thereference-verifyreplay oforigin/main~200..origin/mainreportedclaude on-demand --scheduled (not in 'claude on-demand --help')forplugins/machine-health/CHANGELOG.mdandplugins/machine-health/skills/setup/SKILL.md. The text isclaude -p "/machine-health:audit on-demand --scheduled":--scheduledis a skill argument inside the-pprompt string, not a CLI flag. The finding's line number is the file's first changed line (first_lineinreference-verify.sh), not the line holding the flag (6 and 2 here, against 29 and 345), so the reader has to search for it..githooks/guardrails/hook-utils.sh(238,555 bytes) whole, as a new file;reference-verify.shprintedline 125: .../jq: Argument list too longand the job still passed. Every repository's install push skips that file this way.copywrites seven shebang copies0644on disk as well as in the index; aftergit update-index --chmod=+xthey show as mode changes ingit statusuntilchmod +x, andscripts/check-affected.shhere skips every check while they do.scripts/check-affected.shShellCheck list does not read the workflow'sexclude:, so the pre-push job blocks any push that changes the copies; andscripts/affected-tests.shreports the copies as UNMAPPED. Both are repo-side follow-ups here, noted for theplandecision that names linters (item 2).kyle-sexton commentedon Oct 23, 2026
Item 2 follow-up from the dotfiles rollout (dotfiles#1293): a consumer that runs ShellCheck through the
ci-workflowspr-run-checks.ymlreusable cannot exclude the copies. The reusable'sLint shell scriptsstep passes no inputs to the shellcheck composite (atab83b01, v0.39.3, and on ci-workflows main as of 2026-10-23), so.githooks/guardrails/is linted and fails on SC2218 (run-guards.sh:569, error level), SC2329 (run-guards.sh:744) and SC1091. The repo-side workaround the pilot used (the composite's ownexclude:) only reaches a direct call of the composite. Fix options: make the copies ShellCheck-clean under a strict rc (removes the need for any exclusion), or add ashellcheck-excludeinput to the reusable.49 remaining items
kyle-sexton commentedon Nov 2, 2026
Host run. Fixed the file modes
install.mjs copy --scope sharedgives its copies (findings 1 and 8), at the canonicallib/git-hooks/install.mjs, and regenerated the ten plugin copies.What ran:
lib/git-hooks/install.mjs: a support copy (the check lib or an asset) that starts with#!is written0755and staged100755. Any other copy is written0644and staged100644(--chmod=-x). When a copy's exec bit is wrong, a rerun rewrites the copy and reportsrefreshed. Stable copies made byconfigHookfollow the same rule.scripts/sync-shared-copies.shregenerated the copies, and--checkpasses: all 567 copies match.lib/git-hooks/install.test.mjs. It fails on the old installer and passes on the new one. The whole file passes: 73 pass, 4 skipped for git below 2.54.100755and executable on disk, every other file is100644, 0 violations. The seven files the issue named are among them.scripts/check-affected.sh --testson the committed head: 13 passed, 3 skipped.PR: #12402 (
Refs: #9426).Remaining on this issue: the five acceptance criteria in the 2026-10-31 decision, and finding 2 (
plannaming the linters that will see the copies). No consumer repository needs a change for this fix.Target labels: add none; remove host-run.
kyle-sexton commentedon Nov 3, 2026
kyle-sexton commentedon Nov 3, 2026
fix(guardrails): keep secret scanning on listed paths and fail on ver…
fix(guardrails): unpipe a grep -q, assert the blocking fix line, prun…