Summary
Report, not a proposal. Filed at a maintainer's request from evidence gathered while landing #3503; I am deliberately not proposing a mechanism.
#3503 burned four separate CI rounds on gate findings. Every one was in prose or a test fixture rather than logic, and every one was found only by pushing and waiting. None changed the behavior under review.
The four findings, with the commit that fixed each
| # |
Gate |
Finding |
Fixed in |
| 1 |
plugin-options-docs-gate |
The guardrails README options table is generated from .claude-plugin/plugin.json userConfig. I hand-edited the README row, which passes markdownlint and fails the gate. |
a188792 |
| 2 |
hygiene / machine-specific-paths |
A realistic Windows user path in a test fixture (C:\Users\dev\AppData\Local\Temp\note.txt). The prescribed <user> placeholder then tripped shell-portability-lint, because \< is a GNU word boundary. Only forward slashes plus the placeholder satisfy both. |
a188792 |
| 3 |
hygiene / typos |
unparseable (the gate wants unparsable), twice, in prose written to explain an earlier fix. |
55225d3 |
| 4 |
hygiene / machine-specific-paths |
/home/u/x.txt in a new regression fixture — a Linux user path. Fixed with /srv/app/notes.txt, which needs no user directory at all. |
pending |
Findings 2 and 4 are the same gate catching the same class twice, on two different platforms' user-path shapes, several rounds apart.
What I actually tried locally
Stated as attempts, not assumptions.
Ran locally, and they work: scripts/check-shell-portability.sh, shellcheck -x, scripts/check-changelog-parity.sh (all three modes), scripts/sync-plugin-options-docs.py --check, markdownlint-cli2, scripts/affected-tests.sh --explain/--run, and typos (on PATH via WinGet; _typos.toml is in the repo root; a bare typos run over the repo exits 0).
Could not find a local entry point: machine-specific-paths. There is no script for it anywhere in this repo — find . -name '*machine-specific*' returns nothing. It lives in the external melodic-software/ci-workflows composite action, so the only way I know to exercise it is to push.
The honest shape of the problem
My first instinct was that these gates lack local runners. Checking rather than assuming, that is wrong for three of the four: sync-plugin-options-docs.py --check and typos were both runnable on this machine the whole time. I did not run them because I did not know they corresponded to those gate names.
So the gap is discoverability, not absence — with one genuine exception:
- There appears to be no single documented entry point that runs the hygiene gate set locally. An author must already know that
plugin-options-docs-gate maps to sync-plugin-options-docs.py, and that the typos sub-step maps to a typos binary plus _typos.toml. Neither mapping is guessable from the failing check's name.
machine-specific-paths genuinely has no in-repo runner, and it is the gate that fired twice.
A maintainer should confirm both points — I may still have missed an entry point, the same way I missed two.
Explicitly not proposed
Whether this becomes a pre-commit hook, a make/script target, a documented mapping table, or nothing at all is a repo-tooling decision. I am not proposing a mechanism and have not implemented anything.
Related
Surfaced while landing #3503. Sibling follow-ups from the same work: #3502, #3504.
Summary
Report, not a proposal. Filed at a maintainer's request from evidence gathered while landing #3503; I am deliberately not proposing a mechanism.
#3503 burned four separate CI rounds on gate findings. Every one was in prose or a test fixture rather than logic, and every one was found only by pushing and waiting. None changed the behavior under review.
The four findings, with the commit that fixed each
plugin-options-docs-gate.claude-plugin/plugin.jsonuserConfig. I hand-edited the README row, which passes markdownlint and fails the gate.a188792hygiene/machine-specific-pathsC:\Users\dev\AppData\Local\Temp\note.txt). The prescribed<user>placeholder then trippedshell-portability-lint, because\<is a GNU word boundary. Only forward slashes plus the placeholder satisfy both.a188792hygiene/typosunparseable(the gate wantsunparsable), twice, in prose written to explain an earlier fix.55225d3hygiene/machine-specific-paths/home/u/x.txtin a new regression fixture — a Linux user path. Fixed with/srv/app/notes.txt, which needs no user directory at all.Findings 2 and 4 are the same gate catching the same class twice, on two different platforms' user-path shapes, several rounds apart.
What I actually tried locally
Stated as attempts, not assumptions.
Ran locally, and they work:
scripts/check-shell-portability.sh,shellcheck -x,scripts/check-changelog-parity.sh(all three modes),scripts/sync-plugin-options-docs.py --check,markdownlint-cli2,scripts/affected-tests.sh --explain/--run, andtypos(onPATHvia WinGet;_typos.tomlis in the repo root; a baretyposrun over the repo exits 0).Could not find a local entry point:
machine-specific-paths. There is no script for it anywhere in this repo —find . -name '*machine-specific*'returns nothing. It lives in the externalmelodic-software/ci-workflowscomposite action, so the only way I know to exercise it is to push.The honest shape of the problem
My first instinct was that these gates lack local runners. Checking rather than assuming, that is wrong for three of the four:
sync-plugin-options-docs.py --checkandtyposwere both runnable on this machine the whole time. I did not run them because I did not know they corresponded to those gate names.So the gap is discoverability, not absence — with one genuine exception:
plugin-options-docs-gatemaps tosync-plugin-options-docs.py, and that thetypossub-step maps to atyposbinary plus_typos.toml. Neither mapping is guessable from the failing check's name.machine-specific-pathsgenuinely has no in-repo runner, and it is the gate that fired twice.A maintainer should confirm both points — I may still have missed an entry point, the same way I missed two.
Explicitly not proposed
Whether this becomes a pre-commit hook, a make/script target, a documented mapping table, or nothing at all is a repo-tooling decision. I am not proposing a mechanism and have not implemented anything.
Related
Surfaced while landing #3503. Sibling follow-ups from the same work: #3502, #3504.