docs(lint): correct the Vale exit-code and glob-scoping claims
cli-reference.md said vale exits non-zero for any alert at or above
MinAlertLevel. The exit code keys on error-level alerts alone;
MinAlertLevel filters display only. LESSONS.md records this exact
misconception as costing two review rounds, and this research doc is
the cited provenance source for the skills that state it correctly.
CONTEXT.md claimed a SKILL.md outside plugins/ matches no glob section.
[**/SKILL.md] matches any path ending in SKILL.md — the sentence is a
stale leftover from the path-scoped globs at cbc33d9, and contradicted
its own paragraph two sentences earlier. The NOT-RUN 0-files guard it
justifies is correct and is unchanged; only the rationale was wrong.
CONTEXT.md also cited the local files: regex as the scoping mechanism,
where the shipped manifest deliberately stays layout-agnostic.
ADR-0014 records the entry[0]-only prefixing constraint as the reason
the self-locating design is required, and that no entry may grow a
repo-internal path argument.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCQ648fLSFXPHGZdQ8gn58
This commit is contained in:
@@ -55,11 +55,27 @@ define separate `-skill`/`-agent` hook IDs, each with a `files:` regex matching
|
||||
target copy's glob covers. (Confirmed empirically before deleting the root files: retargeting a
|
||||
single hook at agent-audit's copy silently scanned 0 SKILL.md files.)
|
||||
|
||||
**The hook `entry:` is the wrapper alone; the wrapper self-locates its config.** pre-commit
|
||||
prefixes only `entry[0]` with the hook-repo clone path (`cmd = (prefix.path(cmd[0]), *cmd[1:])`);
|
||||
every later argument is handed to the process untouched and so resolves against the *consuming*
|
||||
repo's root. A `--config plugins/kyberforge/skills/…/assets/vale/.vale.ini` in
|
||||
`.pre-commit-hooks.yaml` therefore named a path no consumer has, and every external run died with
|
||||
`E100 [--config] Runtime error`. The external-consumer contract this ADR exists to establish
|
||||
cannot be expressed as a `--config` argument at all — the config path has to be derived inside
|
||||
the process, from the script's own location. `vale-wrap.sh` accordingly defaults to its sibling
|
||||
`assets/vale/.vale.ini`, resolved from `${BASH_SOURCE[0]}`, whenever no `--config` is supplied;
|
||||
an explicit `--config` from any other caller still wins and still resolves against the caller's
|
||||
cwd, so both audit skills' Step 1 (`--config assets/vale/.vale.ini`) is unaffected. Both
|
||||
manifests now carry the identical argument-free `entry:`. Keeping them identical is part of the
|
||||
decision: the local `repo: local` hook resolved its `--config` correctly only because the
|
||||
consuming repo *was* this repo, and that one difference is why three review rounds exercised a
|
||||
code path no external consumer ever takes.
|
||||
|
||||
**Vale's `StylesPath` resolves relative to the `.vale.ini` file's own location**, confirmed
|
||||
against `docs.vale.sh/keys/stylespath` — so `--config <path-into-plugin>/.vale.ini` correctly
|
||||
finds that ini's sibling `styles/` regardless of the caller's cwd, with no extra path-juggling
|
||||
needed beyond what `vale-wrap.sh` already does for its cwd-relative `--config`/file-argument
|
||||
handling.
|
||||
against `docs.vale.sh/keys/stylespath` — so a config path into the plugin finds that ini's
|
||||
sibling `styles/` regardless of the caller's cwd, whether it arrives as an explicit `--config` or
|
||||
as the wrapper's self-located default. No extra path-juggling is needed beyond `vale-wrap.sh`'s
|
||||
cwd-relative `--config`/path-argument handling and that fallback.
|
||||
|
||||
**A sync-check catches drift between the two copies.** `scripts/check-vale-style-sync.sh` diffs
|
||||
`scripts/vale-wrap.sh` and `assets/vale/styles/Kyberforge/` between skill-audit and agent-audit
|
||||
@@ -91,8 +107,18 @@ doesn't wonder if it was overlooked.
|
||||
- Root `.vale.ini`, `styles/`, `scripts/vale-wrap.sh` are deleted. Two copies remain:
|
||||
`plugins/kyberforge/skills/agent-audit/assets/vale/` (canonical, superset) and
|
||||
`plugins/kyberforge/skills/skill-audit/assets/vale/` (subset, `Kyberforge` only).
|
||||
- `plugins/kyberforge`'s `plugin.json` and `.claude-plugin/plugin.json` both patch-bump to
|
||||
`1.2.5` for the shipped content change (per ADR-0006's version-parity invariant).
|
||||
- `plugins/kyberforge`'s `plugin.json` and `.claude-plugin/plugin.json` both patch-bump for every
|
||||
shipped content change (per ADR-0006's version-parity invariant): `1.2.5` for the relocation
|
||||
itself, `1.2.6` for the self-locating `vale-wrap.sh` that followed.
|
||||
- **`.pre-commit-hooks.yaml` entries are a bare script path and nothing else — a constraint, not a
|
||||
house style, and it binds every future hook here, not just the Vale two.** Since pre-commit
|
||||
rewrites only `entry[0]` into the hook-repo clone, no argument token in any entry can reference
|
||||
a file this repo ships: a relative path resolves against the *consuming* repo and hard-fails,
|
||||
and the absolute path is unknowable at author time. A hook that needs one of its own bundled
|
||||
files must have the script self-locate it from `$0`/`${BASH_SOURCE[0]}`, exactly as
|
||||
`vale-wrap.sh` now does for `.vale.ini`. Anything else rediscovers this as another `E100`.
|
||||
`.pre-commit-config.yaml` stays byte-identical to the shipped manifest on those `entry:` lines
|
||||
so the local gate keeps exercising the same resolution path a consumer does.
|
||||
- `tests/test-vale-wrap.sh` now exercises skill-audit's copy specifically — its fixtures are all
|
||||
`SKILL.md`-shaped, and only skill-audit's `.vale.ini` has the matching glob section.
|
||||
- The first `vX.Y.Z` tag is cut once this change and its tests pass, giving external
|
||||
@@ -117,3 +143,14 @@ doesn't wonder if it was overlooked.
|
||||
as a separate piece of infrastructure, not fixed here. `RELEASE_PATHS` is derived from
|
||||
`.pre-commit-hooks.yaml`'s own `entry:` lines rather than hand-maintained, so at least the set of
|
||||
paths it checks can't drift from the manifest on its own.
|
||||
- **Dropping `--config` moved the release gate's path derivation too.** `check-release-needed.sh`
|
||||
used to reach each hook's bundled assets through the `dirname` of its `--config` target. With
|
||||
no `--config` token left, that loop went dead and silently dropped both `assets/vale/` trees
|
||||
from release coverage — a Vale *rule* change could then land on `main` without demanding a tag,
|
||||
leaving consumers pinned to an old `rev:` running stale rules while the gate stayed green. The
|
||||
script now derives the bundle's `assets/` tree from `tokens[0]` instead (double-`dirname`,
|
||||
guarded on the candidate existing and on not resolving to `.`), which is the only derivation
|
||||
compatible with the argument-free `entry:` contract above.
|
||||
- **Accepted residual in the release gate:** deleting a hook's *entire* `assets/` tree is not
|
||||
flagged — the derived candidate path stops existing, so the guard drops it before it reaches
|
||||
the pathspec. Deleting individual files inside a surviving tree is flagged, and tested.
|
||||
|
||||
Reference in New Issue
Block a user