vale: the Kyberforge style is scoped to SKILL.md, so every references/ file is unlinted #117

Closed
opened 2026-08-30 16:50:22 +00:00 by Claude · 2 comments
Collaborator

Found during the #99 ADR-0020 retrofit, wave 4 (forge).

What happens

plugins/kyberforge/.apm/skills/skill-audit/assets/vale/.vale.ini:3 scopes the Kyberforge style to [**/SKILL.md]. Every other file in a skill package — every references/ file, every README.md — is outside the glob.

Running the audit's own wrapper on one of them does not report an error. It reports no files:

$ bash .../skill-audit/scripts/vale-wrap.sh <a references/ file>
✔ 0 errors, 0 warnings and 0 suggestions in 0 files.

in 0 files is the only thing distinguishing "clean" from "not run", and it is easy to read past. Two separate wave-4 agents ran it on a non-SKILL.md file and had to reason their way to noticing the gate had not executed.

Why it matters more than it looks

This interacts badly with ADR-0020 itself. The contract's central remedy is move prose out of the body into references/ — that is what the dispatch rule mandates and what every retrofit in #99 did. So the gate's coverage shrinks in exactly the direction the contract pushes content.

forge's wave-4 retrofit moved roughly 900 words out of SKILL.md into three new references/ files. The moved prose contains a real violation:

  • references/apm-routes.md:12 opened **There is** no other candidate for these two rows.
  • Kyberforge.SentenceOpenerThereIs is level: error, raw pattern ^There\s(is|are)\b.
  • Copied verbatim into a file named SKILL.md, that text produces Kyberforge.SentenceOpenerThereIs at 12:1, graded error.

Same words, same style, same repo — an error in one filename and invisible in another. It was fixed by hand in the retrofit because a human-directed audit caught it by grep, not because any gate fired.

Scope

Corpus-wide, not forge-specific. Every references/ file across all 39 skills has been unlinted since the style was written, and the retrofit has just moved a large volume of prose into that space.

Suggested fix

Widen the scope. The obvious form is a second section in .vale.ini covering [**/references/*.md], but the rules need reviewing before they are switched on there — some Kyberforge rules may be calibrated to description/body prose and produce noise on reference material, which is presumably why the narrow scope was chosen. Whatever the decision, the wrapper should distinguish "0 alerts in 1 file" from "0 files matched" and say so loudly; a check that reports success because it measured nothing is the failure mode this repo has hit before.

Note skill-size-check does not cover the Vale half either, so pre-commit run --all-files is currently the only way to exercise both.

Files

  • plugins/kyberforge/.apm/skills/skill-audit/assets/vale/.vale.ini:3 — the scope
  • plugins/kyberforge/.apm/skills/skill-audit/scripts/vale-wrap.sh — where the "0 files" ambiguity surfaces
  • plugins/kyberforge/.apm/skills/skill-audit/assets/vale/styles/Kyberforge/SentenceOpenerThereIs.yml — the rule demonstrated above

Found during #99 wave 4. Same family as #110 (a gate that silently fails to fire) and the vale-wrap.sh folded-scalar workaround, which exists because text.frontmatter.description does not match folded YAML — a third instance of Vale scoping not matching what the repo assumes it covers.

Found during the #99 ADR-0020 retrofit, wave 4 (`forge`). ## What happens `plugins/kyberforge/.apm/skills/skill-audit/assets/vale/.vale.ini:3` scopes the `Kyberforge` style to `[**/SKILL.md]`. Every other file in a skill package — every `references/` file, every `README.md` — is outside the glob. Running the audit's own wrapper on one of them does not report an error. It reports **no files**: ``` $ bash .../skill-audit/scripts/vale-wrap.sh <a references/ file> ✔ 0 errors, 0 warnings and 0 suggestions in 0 files. ``` `in 0 files` is the only thing distinguishing "clean" from "not run", and it is easy to read past. Two separate wave-4 agents ran it on a non-`SKILL.md` file and had to reason their way to noticing the gate had not executed. ## Why it matters more than it looks This interacts badly with ADR-0020 itself. The contract's central remedy is **move prose out of the body into `references/`** — that is what the dispatch rule mandates and what every retrofit in #99 did. So the gate's coverage shrinks in exactly the direction the contract pushes content. `forge`'s wave-4 retrofit moved roughly 900 words out of `SKILL.md` into three new `references/` files. The moved prose contains a real violation: - `references/apm-routes.md:12` opened `**There is** no other candidate for these two rows`. - `Kyberforge.SentenceOpenerThereIs` is `level: error`, raw pattern `^There\s(is|are)\b`. - Copied verbatim into a file named `SKILL.md`, that text produces `Kyberforge.SentenceOpenerThereIs` at 12:1, graded **error**. Same words, same style, same repo — an error in one filename and invisible in another. It was fixed by hand in the retrofit because a human-directed audit caught it by grep, not because any gate fired. ## Scope Corpus-wide, not `forge`-specific. Every `references/` file across all 39 skills has been unlinted since the style was written, and the retrofit has just moved a large volume of prose into that space. ## Suggested fix Widen the scope. The obvious form is a second section in `.vale.ini` covering `[**/references/*.md]`, but the rules need reviewing before they are switched on there — some `Kyberforge` rules may be calibrated to description/body prose and produce noise on reference material, which is presumably why the narrow scope was chosen. Whatever the decision, the wrapper should distinguish **"0 alerts in 1 file"** from **"0 files matched"** and say so loudly; a check that reports success because it measured nothing is the failure mode this repo has hit before. Note `skill-size-check` does not cover the Vale half either, so `pre-commit run --all-files` is currently the only way to exercise both. ## Files - `plugins/kyberforge/.apm/skills/skill-audit/assets/vale/.vale.ini:3` — the scope - `plugins/kyberforge/.apm/skills/skill-audit/scripts/vale-wrap.sh` — where the "0 files" ambiguity surfaces - `plugins/kyberforge/.apm/skills/skill-audit/assets/vale/styles/Kyberforge/SentenceOpenerThereIs.yml` — the rule demonstrated above ## Related Found during #99 wave 4. Same family as #110 (a gate that silently fails to fire) and the `vale-wrap.sh` folded-scalar workaround, which exists because `text.frontmatter.description` does not match folded YAML — a third instance of Vale scoping not matching what the repo assumes it covers.
Claude added the Kind/Bug
Priority
Medium
3
Reviewed
Confirmed
1
labels 2026-08-30 16:50:57 +00:00
Claude added this to the Skills & Agents milestone 2026-08-30 16:51:01 +00:00
Author
Collaborator

Still open, still correct — and there is a second independent cause this issue does not record

Nothing on refactor/adr0020-skill-retrofit fixes this. assets/vale/.vale.ini still reads:

StylesPath = styles

[**/SKILL.md]
BasedOnStyles = Kyberforge

The part that matters for whoever picks this up

The suggested fix — widening the .vale.ini glob with a [**/references/*.md] section — would appear not to work, because the scope is only half the reason a references/ file is never linted. The other half is the hook:

- id: vale-audit-prefilter-skill
  entry: plugins/kyberforge/.apm/skills/skill-audit/scripts/vale-wrap.sh
  files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$'

pre-commit selects the file set before Vale is reached. A references/ file is never handed to vale-wrap.sh at all, whatever .vale.ini says. Closing either cause alone changes nothing observable — widen the glob and the hook still passes no reference files; widen the hook and the style still does not apply to them. Both have to move in the same change, or the fix will look like it failed and get reverted.

Evidence for the issue: the branch fixed by hand what the blind spot was hiding

Measured main against the branch across the gitea plugin's references/ files:

main branch
There is/There are sentence openers 5 0
Untagged opening code fences 36 0

The five openers are exactly Kyberforge.SentenceOpenerThereIs, level: error — they sat in gitea-issues/references/enrichments.md, gitea-issues/references/issues.md (x2), gitea-prs/references/pull-requests.md and gitea-labels-milestones/references/labels.md. Copied verbatim into a file named SKILL.md every one of them is a graded error; in the file they actually live in, all five were invisible.

They were found and fixed by a human-directed audit pass, not by any gate — the same way forge's apm-routes.md:12 was found in wave 4. That is 41 real violations in one plugin's reference files, which is a measurement of the blind spot's size, not a substitute for closing it.

The blind spot also survived a corpus-wide retrofit that moved a large volume of prose into precisely this space, so the coverage gap is now wider than when this issue was filed.

## Still open, still correct — and there is a **second independent cause** this issue does not record Nothing on `refactor/adr0020-skill-retrofit` fixes this. `assets/vale/.vale.ini` still reads: ```ini StylesPath = styles [**/SKILL.md] BasedOnStyles = Kyberforge ``` ### The part that matters for whoever picks this up The suggested fix — widening the `.vale.ini` glob with a `[**/references/*.md]` section — **would appear not to work**, because the scope is only half the reason a `references/` file is never linted. The other half is the hook: ```yaml - id: vale-audit-prefilter-skill entry: plugins/kyberforge/.apm/skills/skill-audit/scripts/vale-wrap.sh files: '^plugins/[^/]+/\.apm/skills/[^/]+/SKILL\.md$' ``` pre-commit selects the file set before Vale is reached. A `references/` file is never handed to `vale-wrap.sh` at all, whatever `.vale.ini` says. Closing either cause alone changes nothing observable — widen the glob and the hook still passes no reference files; widen the hook and the style still does not apply to them. Both have to move in the same change, or the fix will look like it failed and get reverted. ### Evidence for the issue: the branch fixed by hand what the blind spot was hiding Measured `main` against the branch across the `gitea` plugin's `references/` files: | | `main` | branch | |---|---|---| | `There is`/`There are` sentence openers | 5 | 0 | | Untagged opening code fences | 36 | 0 | The five openers are exactly `Kyberforge.SentenceOpenerThereIs`, `level: error` — they sat in `gitea-issues/references/enrichments.md`, `gitea-issues/references/issues.md` (x2), `gitea-prs/references/pull-requests.md` and `gitea-labels-milestones/references/labels.md`. Copied verbatim into a file named `SKILL.md` every one of them is a graded error; in the file they actually live in, all five were invisible. They were found and fixed by a human-directed audit pass, not by any gate — the same way `forge`'s `apm-routes.md:12` was found in wave 4. That is 41 real violations in one plugin's reference files, which is a measurement of the blind spot's size, not a substitute for closing it. The blind spot also survived a corpus-wide retrofit that moved a large volume of prose into precisely this space, so the coverage gap is now wider than when this issue was filed.
Owner

Wont fix, vale will more likely be deleted than expanded

Wont fix, vale will more likely be deleted than expanded
Defame1297 added
Reviewed
Won't Fix
3
and removed
Reviewed
Confirmed
1
labels 2026-09-03 06:16:12 +00:00
Sign in to join this conversation.