docs: source ADR-0029 claims and sync ADRs and hook docs with behaviour

- cite the VS Code prompt-file deprecation and the verbatim apm quote
- add ADR-0029 boundary-clause enforcement and Consequences
- mark superseded ADR-0019 passages; record neutral lock advice, source
  fork and reloadSkills, amend for the hook hardening
- move the ADR-0025 amendment out of the Decision list
- amend ADR-0022 for create keeping 0.1.0
- fix hooks.md merge and event claims, README guard caveat, gates.md Vale
  globs, and pin the research registry URL

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkT7RSDwDbmrM9T34b6sTi
This commit is contained in:
2026-09-29 08:00:39 +00:00
parent 4a4b598955
commit 641ebcac0e
12 changed files with 171 additions and 76 deletions

View File

@@ -787,8 +787,10 @@ Wiring Vale as a deterministic prefilter for `factory-audit`'s Description dimen
issue #84) is repo-specific, not part of the generic `lint` plugin, so it does not live in
`plugins/lint/` — and per ADR-0014 it no longer lives at the repo root either. It lives **once**,
under `plugins/kyberforge/.apm/skills/factory-audit/assets/vale/`, carrying both the `Kyberforge`
and `KyberforgeCopilot` styles and a single `.vale.ini` with all three glob sections:
`[**/SKILL.md]`, `[**/agents/*.md]`, `[**/*.agent.md]`.
and `KyberforgeCopilot` styles and a single `.vale.ini` with five glob sections:
`[**/SKILL.md]`, `[**/agents/*.md]`, `[**/*.instructions.md]`, `[**/*.prompt.md]` and
`[**/*.agent.md]`. The instructions and prompt sections arrived with `factory-audit`'s primitive
modes (ADR-0025, amendment 2026-09-28).
ADR-0014 split this into two skill-scoped copies because a plugin's cache-install copies only each
skill's own files and `skill-audit` could not reach across the skill boundary into `agent-audit`'s
@@ -816,7 +818,8 @@ Its `StylesPath` and `BasedOnStyles` checks were **not** diffs. They were per-fi
invoked `vale --config` on one representative path per file shape. It was the only assertion
anywhere that catches a `.vale.ini` glob typo (`[**/SKILL.md]` → `[**/SKILLS.md]`), the failure mode
where every other check stays clean while Vale lints zero files. One config does not make that
impossible: a typo in any one of the three sections still 0-file-skips that shape.
impossible: a typo in any one section still 0-file-skips that shape. The table has since grown
to eight rows: one each for the instructions and prompt sections added later.
**Case 0** runs before any Vale-dependent case and needs no Vale binary. It asserts that the shipped
`.vale.ini` exists and is readable, sets a `StylesPath` that resolves to a directory, and names only
@@ -826,8 +829,9 @@ cases back.
The probes now live in `tests/test-vale-wrap.sh` (cases 28–30), rehomed against the merged config:
one representative path per file shape, each asserted to produce a Vale scan of more than zero files
*and* a Kyberforge alert (case 28). Case 28 also checks that each probe path is in scope of a
published vale hook, and that every `.vale.ini` section has a probe row. Its Part B drops
*and* a Kyberforge alert (case 28). Case 28 also checks that every `.vale.ini` section has an
isolating probe row. It no longer holds each probe path to a hook's `files:` scope: that half read
the retired `.pre-commit-hooks.yaml`, and case 32 owns the local hooks' scope. Its Part B drops
`Kyberforge` from each section's `BasedOnStyles` in a copy and requires that section's probes to
fail as "style not loaded". Case 29 is a mutation case: it typos each section in a copy of the
assets and requires that section's isolating probes to drop to zero. Case 30 asserts that
@@ -931,17 +935,17 @@ authors. Without the binary the hooks fail with a bare "command not found" and n
**Two hooks, not one combined hook — for a different reason than ADR-0014 gave.** The original
reason was mechanical: with a config per skill, a single hook could point at only one copy and would
silently 0-file-skip the other file shape (see
[A 0-file Vale run is NOT RUN](#a-0-file-vale-run-is-not-run)). One `.vale.ini` carrying all three
sections removes that constraint. The split stays anyway because the `files:` regexes still have to
[A 0-file Vale run is NOT RUN](#a-0-file-vale-run-is-not-run)). One `.vale.ini` carrying every
section removes that constraint. The split stays anyway because the `files:` regexes still have to
differ — each hook hands Vale only the file shape it is scoped to. Both hooks name the same
plugin-bundled `factory-audit/scripts/vale-wrap.sh` through `repo: local`; there is no second root
copy.
### The `.vale.ini` globs do no scoping
The `.vale.ini`'s section globs are **path-agnostic** — `[**/SKILL.md]`, `[**/agents/*.md]` and
`[**/*.agent.md]` — and constrain filename *shape*, not
location: Vale's `*` crosses `/`. A `SKILL.md` outside `plugins/` (a project-scope
The `.vale.ini`'s section globs are **path-agnostic** — `[**/SKILL.md]`, `[**/agents/*.md]`,
`[**/*.instructions.md]`, `[**/*.prompt.md]` and `[**/*.agent.md]` — and constrain filename *shape*,
not location: Vale's `*` crosses `/`. A `SKILL.md` outside `plugins/` (a project-scope
`.claude/skills/foo/SKILL.md`, say) still matches `[**/SKILL.md]` and gets linted normally.
All scoping therefore comes from the pre-commit hooks' own `files:` regexes, which pin this repo's
@@ -951,8 +955,16 @@ invocation — in this repo or in any repo that installs it, whatever that repo'
Narrowing a `.vale.ini` glob to a `plugins/`-shaped path to "tighten" it breaks the consumer case:
`factory-audit` run against a project-scope `.claude/skills/` tree would lint nothing.
`check-vale-style-sync`'s probe set was built to catch exactly that; it moved to
`tests/test-vale-wrap.sh` with the hook's deletion, and two of the six probes exist specifically to
pin this location independence — see [One copy, one config](#one-copy-one-config).
`tests/test-vale-wrap.sh` with the hook's deletion. Its table (`PROBE_TABLE28`) now has eight rows,
one or more per section, and the two `.claude/`-prefixed rows exist specifically to pin this
location independence — see [One copy, one config](#one-copy-one-config).
**No pre-commit Vale hook covers `*.instructions.md` or `*.prompt.md` yet.** The `.vale.ini`
sections exist so that `factory-audit`'s own Vale call lints those files when it is handed one, in
any repo. This repo's two prefilter hooks select only `SKILL.md` and `.agent.md` files, and the repo
has no instruction or prompt file for a third hook to select. Case 32 requires every Vale hook's
`files:` regex to match at least one tracked file, so a hook added now would fail it. Add the hook
in the change that lands the first `.apm/instructions/` or `.apm/prompts/` file.
### The blind spot: `references/` is unlinted, for two independent reasons
@@ -1051,9 +1063,9 @@ clean.
### Pre-push
`vale` is still a **pre-push** dependency, but no longer through a hook of its own.
`check-vale-style-sync` — the hook that ran the six glob probes, and whose
`check-vale-style-sync` — the hook that ran the original six glob probes, and whose
`CHECK_VALE_STYLE_SYNC_ALLOW_MISSING_VALE=1` opt-out downgraded them audibly rather than skipping the
hook — is deleted with the second Vale copy (ADR-0025). The six glob probes survive it inside
hook — is deleted with the second Vale copy (ADR-0025). The glob probes survive it inside
`test-vale-wrap.sh`, so `run-tests --strict` is now the gate that runs them. That is also what keeps
`vale` a pre-push requirement: `test-vale-wrap.sh` exits 77 without the binary once its static cases
pass, and a skip fails the push.