feat(kyberforge): make Research doc name one Research registry #139

Merged
Defame1297 merged 10 commits from feat/121-research-doc-grammar into main 2026-09-21 19:52:19 +00:00
Collaborator

Closes #121

Why

validate-provenance.sh assumed Research doc: names a research sources.md whose ## H2 headings are the source slugs. The corpus did something else: 29 entries pointed at topic docs and 6 values were not a single path. Checks 7 and 8 therefore reported 36 INFOs and nothing ever failed, and nothing ran the validator over the real corpus, so a stricter tier would have been inert.

Decisions and rejected alternatives are in docs/adr/0028-research-doc-names-the-research-registry.md.

What changed

  • Grammar. Research doc: names exactly one Research registry (new term in CONTEXT.md). An entry with no registry writes none plus one - **Basis:** <path> bullet per path. Each Basis path is existence-checked unless annotated (removed in <sha>). Brace expansion, comma lists and semicolon pairs are rejected.
  • Validator. Check 7 FAILs when a resolved registry lacks the slug, when the value is a topic doc, or when it is a list. An unresolvable path stays INFO, so auditing a deployed copy elsewhere is not failed on something it cannot judge. The Research doc and Basis parsers accept the inline, bullet and header-plus-bullets spellings.
  • Check 8 is retired. It required every extracted registry slug to appear in each skill's sources.md. One registry serves many skills (git/sources.md backs seven), so that is unsatisfiable. It only looked satisfiable while topic-doc pointers kept it dormant.
  • Migration. The 9 git skills, gitea-releases, agentsmd-audit and provider-adapter-author moved to the new grammar. Old topic-doc links are kept as (digest: ...) annotations.
  • Gate. scripts/check-provenance-corpus.sh is a new pre-push hook that runs the validator over every skill with a references/sources.md. Documented in docs/spec/gates.md.
  • Version bumps for the 16 changed skills, as ADR-0022 requires.

For the reviewer

  • The house-vale-3-15-2-repro entry is deleted from vale-config and vale-run, along with its source_keys citations. It claimed six behaviours were reproduced "against purpose-built fixtures in this repo". The entry was added in d1afdbe with no test or fixture files, and none exists in history (the only vale test ever deleted, in 4de5b6b, guards an unrelated E100). The behavioural rules stay; only the unbacked provenance claim goes. Content note: configuration-reference.md still says its rows were "reproduced against Vale 3.15.2", which now has no provenance entry behind it. I left that wording alone and it needs a decision, either softening it or committing real reproduction fixtures.
  • The (removed in <sha>) annotation is unverified. It can be written on any bullet to skip the existence check. Accepted for the three bullets that use it; the sha is not resolved with git cat-file.
  • Two files were touched beyond the obvious scope: tests/test-adr0020-contract.sh pins the list of repo-authored hooks and needed one entry for the new hook, and skill-author/references/contract.md told authors to put the org-convention note in Research doc:, which now contradicts the grammar.
  • The validator diff (lib-provenance-skill.sh, about 360 lines) was written by a subagent and checked by its tests and the corpus sweep, not read line by line by the author. It deserves a careful read.
  • .claude/skills/ is gitignored apm install output and will show the old copies until apm install regenerates it.

Verification

  • factory-audit bats: 272/272 pass. tests/run-tests.sh --strict: 20 suites, 0 failed, 0 skipped.
  • scripts/check-provenance-corpus.sh: 27 skills checked, passes with no allowlist.
  • All pre-push hooks passed on push, including apm audit --ci, apm pack --check-clean, the new corpus gate and the version-bump gate.
  • Vale 3.15.2 through the repo's vale-wrap.sh: 0 errors, 0 warnings, 0 suggestions across the 16 changed SKILL.md files. That is the only surface the repo's Vale hook covers (SKILL.md and agent files). The ADR, references/ and sources.md files are outside any configured Vale scope, so they are unlinted, not clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB

Closes #121 ## Why `validate-provenance.sh` assumed `Research doc:` names a research `sources.md` whose `## H2` headings are the source slugs. The corpus did something else: 29 entries pointed at topic docs and 6 values were not a single path. Checks 7 and 8 therefore reported 36 INFOs and nothing ever failed, and nothing ran the validator over the real corpus, so a stricter tier would have been inert. Decisions and rejected alternatives are in `docs/adr/0028-research-doc-names-the-research-registry.md`. ## What changed - **Grammar.** `Research doc:` names exactly one **Research registry** (new term in `CONTEXT.md`). An entry with no registry writes `none` plus one `- **Basis:** <path>` bullet per path. Each Basis path is existence-checked unless annotated `(removed in <sha>)`. Brace expansion, comma lists and semicolon pairs are rejected. - **Validator.** Check 7 FAILs when a resolved registry lacks the slug, when the value is a topic doc, or when it is a list. An unresolvable path stays INFO, so auditing a deployed copy elsewhere is not failed on something it cannot judge. The Research doc and Basis parsers accept the inline, bullet and header-plus-bullets spellings. - **Check 8 is retired.** It required every `extracted` registry slug to appear in each skill's `sources.md`. One registry serves many skills (`git/sources.md` backs seven), so that is unsatisfiable. It only looked satisfiable while topic-doc pointers kept it dormant. - **Migration.** The 9 git skills, `gitea-releases`, `agentsmd-audit` and `provider-adapter-author` moved to the new grammar. Old topic-doc links are kept as `(digest: ...)` annotations. - **Gate.** `scripts/check-provenance-corpus.sh` is a new pre-push hook that runs the validator over every skill with a `references/sources.md`. Documented in `docs/spec/gates.md`. - **Version bumps** for the 16 changed skills, as ADR-0022 requires. ## For the reviewer - **The `house-vale-3-15-2-repro` entry is deleted** from `vale-config` and `vale-run`, along with its `source_keys` citations. It claimed six behaviours were reproduced "against purpose-built fixtures in this repo". The entry was added in `d1afdbe` with no test or fixture files, and none exists in history (the only vale test ever deleted, in `4de5b6b`, guards an unrelated `E100`). The behavioural rules stay; only the unbacked provenance claim goes. Content note: `configuration-reference.md` still says its rows were "reproduced against Vale 3.15.2", which now has no provenance entry behind it. I left that wording alone and it needs a decision, either softening it or committing real reproduction fixtures. - **The `(removed in <sha>)` annotation is unverified.** It can be written on any bullet to skip the existence check. Accepted for the three bullets that use it; the sha is not resolved with `git cat-file`. - **Two files were touched beyond the obvious scope:** `tests/test-adr0020-contract.sh` pins the list of repo-authored hooks and needed one entry for the new hook, and `skill-author/references/contract.md` told authors to put the org-convention note in `Research doc:`, which now contradicts the grammar. - **The validator diff (`lib-provenance-skill.sh`, about 360 lines) was written by a subagent and checked by its tests and the corpus sweep, not read line by line by the author.** It deserves a careful read. - `.claude/skills/` is gitignored `apm install` output and will show the old copies until `apm install` regenerates it. ## Verification - `factory-audit` bats: 272/272 pass. `tests/run-tests.sh --strict`: 20 suites, 0 failed, 0 skipped. - `scripts/check-provenance-corpus.sh`: 27 skills checked, passes with no allowlist. - All pre-push hooks passed on push, including `apm audit --ci`, `apm pack --check-clean`, the new corpus gate and the version-bump gate. - Vale 3.15.2 through the repo's `vale-wrap.sh`: 0 errors, 0 warnings, 0 suggestions across the 16 changed `SKILL.md` files. That is the only surface the repo's Vale hook covers (`SKILL.md` and agent files). The ADR, `references/` and `sources.md` files are outside any configured Vale scope, so they are unlinted, not clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Claude added the Kind/Enhancement
Priority
Medium
3
labels 2026-09-21 17:38:12 +00:00
Claude added 5 commits 2026-09-21 17:38:12 +00:00
validate-provenance.sh assumed `Research doc:` names a research
sources.md whose H2 headings are the source slugs, but 29 corpus entries
named topic docs and 6 values were not a single path, so checks 7 and 8
reported INFO for 36 entries and nothing ever failed.

`Research doc:` now takes exactly one path. An entry with no registry
writes `none` plus one `- **Basis:** <path>` bullet per path; each Basis
path is existence-checked unless annotated `(removed in <sha>)`.

- Check 7 FAILs when a resolved registry lacks the slug, when the value
  is a topic doc, or when it is a list. An unresolvable path stays INFO.
- Check 8 is retired: one registry serves many skills, so requiring
  every registry slug in each skill's sources.md is unsatisfiable.
- The Research doc and Basis parsers accept the inline, bullet and
  header-plus-bullets spellings, so a differently spelled field is no
  longer read as absent.

Refs: #121
ADR: 0028
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Repoint every `Research doc:` at the plugin's Research registry
(git/sources.md, pre-commit/sources.md, gitea/sources.md,
agentsmd/sources.md), keeping the old topic-doc link as a parenthetical
`(digest: ...)` annotation. Brace expansions and the gitea-releases
semicolon pair collapse to one path.

Entries with no registry (org-commit-conventions, org-git-conventions,
governance-secrets-hard-prohibition, adr-0002-0003-two-tier-claude-md)
now declare `none` plus `Basis:` bullets. The two git entries cite
core/instructions/git.md and commits.md as `(removed in 5deed07)`.

Remove the house-vale-3-15-2-repro entry and its source_keys citations
from vale-config and vale-run. It claimed six behaviours were reproduced
against purpose-built fixtures in this repo, but the entry was added in
d1afdbe with no test or fixture files, and none exists in history. The
behavioural rules stay; only the unbacked provenance claim goes.

Refs: #121
ADR: 0028
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Nothing ran validate-provenance.sh across the real corpus, so the 36
INFOs it reported for Research doc mismatches were found only by a
manual loop, and a FAIL tier would have been inert. Add
scripts/check-provenance-corpus.sh, which runs the validator over every
plugins/*/.apm/skills/*/ that has references/sources.md.

Exit 1 when any skill FAILs, naming them; INFO lines are printed but do
not fail; exit 2 when the gate cannot run (missing validator, validator
exit 2, or no skills found). Registered as a pre-push hook shaped like
check-scope-walkup-sync, documented in docs/spec/gates.md, and pinned in
test-adr0020-contract.sh's list of repo-authored hooks.

Refs: #121
ADR: 0028
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
ADR-0028 records the grammar decided for #121 and the alternatives
rejected at each step: what `Research doc:` refers to, how an entry with
no registry declares that (`none` plus `Basis:`), the FAIL and INFO
tiers, the corpus-wide sweep gate, parser parity, retiring check 8, the
`(removed in <sha>)` escape for Basis paths, and removing the lint entry
that had no verifiable basis.

Add the Research registry term to CONTEXT.md, since "registry" had no
definition and "research doc" was being used for both the registry and
the topic docs it digests.

Refs: #121
ADR: 0028
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Raise the PATCH version of each skill whose references/sources.md,
references, or validator changed in the Research registry migration, as
ADR-0022 requires. factory-audit and skill-author changed behaviour and
docs; the rest changed provenance metadata only.

Refs: #121
ADR: 0022
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Claude added this to the Skills & Agents milestone 2026-09-21 17:38:19 +00:00
Defame1297 added 4 commits 2026-09-21 19:45:16 +00:00
Review of PR 139 found list-rejection and confinement holes that let the
exact malformed entries the grammar forbids pass check 7.

- Reject comma, space-separated and backticked path lists, so
  `a/sources.md (x), b/topic.md` no longer exits 0 unchecked.
- FAIL absolute paths and any path whose realpath leaves the repo, for
  both `Research doc:` and `Basis:`.
- Anchor `(removed in <sha>)` to the end of the value with a 7-40 hex
  sha. The sha is format-checked only, not resolved with git cat-file.
- Read `* ` bullets and `- **X**` bullets correctly under a `**Basis:**`
  header, and strip backticks from Basis paths.
- Stop the semicolon rule firing on annotation prose, and stop `none`
  matching `none/foo.md`.
- Update the stale field messages to the new grammar and report an empty
  field as empty, not missing.
- Skip a removed Basis silently when there is no repo root.

Adds 40 tests. Each guarded line was mutated in place and every mutant
is caught.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
The gate took its root from `git rev-parse --show-toplevel || pwd`, so
running it by absolute path from another directory found no skills and
exited 2. Derive the root from the script's own location; the optional
argument still overrides it.

The real-corpus test accepted exit 0 or 1, so it only caught a crash.
It now asserts exit 0. New cases cover a foreign cwd, a skill without
references/sources.md being skipped, several failing skills all being
reported, and an errored skill alongside a failing one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
- ADR-0004: add the "Amended by ADR-0028" note, following the ADR-0025
  convention.
- ADR-0028: correct Q5 (parse_status is gone), the skill count (38, not
  39), and the question order. Q7 records the anchored, format-only sha
  check. Q8 records the decision to commit real Vale fixtures. A new
  consequence covers path confinement and list rejection.
- CONTEXT.md: the `_Avoid_` entry means the bare noun, not the field.
- gates.md: correct the authored-hook counts after the corpus gate.
- create.md: a `none` entry backed by a reproduction must name committed
  fixtures in `Basis:`; use the `(digest: <full path>)` form.
- gitea-releases: use the `(digest: <full path>)` form.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
The `house-vale-3-15-2-repro` provenance entry claimed behaviours were
reproduced against purpose-built fixtures, but no fixtures existed, so
the earlier commit in this PR removed it. Commit the fixtures.

tests/test-vale-3-15-2-behaviours.sh builds its fixtures in a temp dir
and runs the real Vale. It exits 77 (skipped) when vale is missing or is
not 3.15.2. It asserts the six vale-config behaviours and the vale-run
ones (unmapped .mdx, `vale off` variants, the spelling ignore file, and
the ls-* commands never naming a rule).

Restore the entry in both sources.md files as `Research doc: none` with
`Basis:` naming the test, and re-add its source_keys. Two behaviours are
not asserted: the native-MDX suppression column (needs mdx2vast) and the
`vale sync` row that adds to Packages (needs the network). The wording in
configuration-reference.md and troubleshooting.md now says so.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Author
Collaborator

Review pass: findings and fixes

Four parallel read-only reviewers covered the validator, the tests, the corpus gate and docs, and the migrated corpus. None found a blocker. Two majors were in the validator; both are fixed, along with the minors and test gaps. Pushed as four commits (2bde9a6..45d8f19). The pre-push hooks all passed.

Fixed

Validator (2c4b6d2)

  • Major: Research doc: a/sources.md (x), b/topic.md exited 0 with the second path never checked. Comma, space-separated and backticked lists now FAIL.
  • Major: absolute and ..-escaping paths were not confined to the repo (Basis: /etc/passwd passed). Both fields now FAIL on any path whose realpath leaves the repo.
  • (removed in <sha>) is anchored at the end of the value with a 7-40 hex sha. The sha is format-checked only, not resolved with git cat-file.
  • * bullets, - **X** bullets and backticked Basis paths are read correctly. The semicolon rule no longer fires on annotation prose. none/foo.md is no longer read as none. The stale field messages now describe the new grammar.
  • 40 new tests. Each guarded line was mutated in place, and all 24 mutants are caught. Five survived the first round and got their own tests.

Corpus gate (c008da1)

  • It now runs from any cwd. It previously exited 2 when run by absolute path elsewhere.
  • The real-corpus test asserts exit 0 instead of accepting 0 or 1.
  • New cases: a skill without sources.md is skipped, several failures are all reported, and an errored skill alongside a failing one.

Docs (58a3f40)

  • ADR-0004 has the "Amended by ADR-0028" note.
  • ADR-0028: corrected Q5, the skill count (38) and the question order; Q7 and Q8 record the decisions below.
  • Also updated: the CONTEXT.md _Avoid_ entry, the gates.md hook counts, the create.md none example, and the (digest: <full path>) form in gitea-releases.

Vale (45d8f19)

  • The house-vale-3-15-2-repro claim is now backed by a committed test, tests/test-vale-3-15-2-behaviours.sh. It runs the real Vale 3.15.2 (41 assertions) and is restored as Research doc: none plus Basis:.
  • The six vale-config behaviours all reproduced.

Decisions made

  • Vale claim: commit real fixtures, not softened wording.
  • (removed in <sha>): anchor only, no history lookup.

Known limits

  • Two Vale behaviours are not asserted: the native-MDX suppression column (needs mdx2vast) and the vale sync row that adds to Packages (needs the network). The wording in configuration-reference.md and troubleshooting.md says so.
  • The new Vale test skips with exit 77 when Vale is missing or not 3.15.2. --strict turns that skip into a failure at pre-push.
  • The corpus gate reports an INFO that the house-vale-3-15-2-repro description changed since af008b6. The gate cannot judge whether the claim still holds, so someone should re-read it by hand.
  • factory-audit is a patch bump despite a new FAIL tier and a Basis: field. That is defensible under ADR-0022.

Not changed

  • The gate silently skips the 11 skills without a references/sources.md. That matches the documented "covered once it grows one" behaviour.
  • A Basis value like docs/x.md — reason (bare dash, no parentheses) now FAILs on whitespace, and - **docs/x.md** keeps its **. No corpus entry hits either.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB

## Review pass: findings and fixes Four parallel read-only reviewers covered the validator, the tests, the corpus gate and docs, and the migrated corpus. None found a blocker. Two majors were in the validator; both are fixed, along with the minors and test gaps. Pushed as four commits (`2bde9a6..45d8f19`). The pre-push hooks all passed. ### Fixed **Validator (`2c4b6d2`)** - **Major:** `Research doc: a/sources.md (x), b/topic.md` exited 0 with the second path never checked. Comma, space-separated and backticked lists now FAIL. - **Major:** absolute and `..`-escaping paths were not confined to the repo (`Basis: /etc/passwd` passed). Both fields now FAIL on any path whose realpath leaves the repo. - `(removed in <sha>)` is anchored at the end of the value with a 7-40 hex sha. The sha is format-checked only, not resolved with `git cat-file`. - `* ` bullets, `- **X**` bullets and backticked Basis paths are read correctly. The semicolon rule no longer fires on annotation prose. `none/foo.md` is no longer read as `none`. The stale field messages now describe the new grammar. - 40 new tests. Each guarded line was mutated in place, and all 24 mutants are caught. Five survived the first round and got their own tests. **Corpus gate (`c008da1`)** - It now runs from any cwd. It previously exited 2 when run by absolute path elsewhere. - The real-corpus test asserts exit 0 instead of accepting 0 or 1. - New cases: a skill without `sources.md` is skipped, several failures are all reported, and an errored skill alongside a failing one. **Docs (`58a3f40`)** - ADR-0004 has the "Amended by ADR-0028" note. - ADR-0028: corrected Q5, the skill count (38) and the question order; Q7 and Q8 record the decisions below. - Also updated: the `CONTEXT.md` `_Avoid_` entry, the `gates.md` hook counts, the `create.md` `none` example, and the `(digest: <full path>)` form in `gitea-releases`. **Vale (`45d8f19`)** - The `house-vale-3-15-2-repro` claim is now backed by a committed test, `tests/test-vale-3-15-2-behaviours.sh`. It runs the real Vale 3.15.2 (41 assertions) and is restored as `Research doc: none` plus `Basis:`. - The six `vale-config` behaviours all reproduced. ### Decisions made - **Vale claim:** commit real fixtures, not softened wording. - **`(removed in <sha>)`:** anchor only, no history lookup. ### Known limits - Two Vale behaviours are not asserted: the native-MDX suppression column (needs `mdx2vast`) and the `vale sync` row that adds to `Packages` (needs the network). The wording in `configuration-reference.md` and `troubleshooting.md` says so. - The new Vale test skips with exit 77 when Vale is missing or not 3.15.2. `--strict` turns that skip into a failure at pre-push. - The corpus gate reports an INFO that the `house-vale-3-15-2-repro` description changed since `af008b6`. The gate cannot judge whether the claim still holds, so someone should re-read it by hand. - `factory-audit` is a patch bump despite a new FAIL tier and a `Basis:` field. That is defensible under ADR-0022. ### Not changed - The gate silently skips the 11 skills without a `references/sources.md`. That matches the documented "covered once it grows one" behaviour. - A Basis value like `docs/x.md — reason` (bare dash, no parentheses) now FAILs on whitespace, and `- **docs/x.md**` keeps its `**`. No corpus entry hits either. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01EGHFJextYtVQseaHPDDhxB
Defame1297 approved these changes 2026-09-21 19:51:58 +00:00
Defame1297 added 1 commit 2026-09-21 19:52:02 +00:00
Defame1297 merged commit 3ea057794c into main 2026-09-21 19:52:19 +00:00
Defame1297 deleted branch feat/121-research-doc-grammar 2026-09-21 19:52:19 +00:00
Sign in to join this conversation.