diff --git a/CONTEXT.md b/CONTEXT.md index 4a220bb..62ad8ec 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -86,7 +86,7 @@ A plugin's research `sources.md` (e.g. `plugins/git/docs/research/docs/git/sourc headings are the source slugs. A skill's `Research doc:` field names exactly one, and `factory-audit` resolves each entry's slug against it. An entry with no registry declares `Research doc: none` and names what it was actually drawn from in `Basis:`. -_Avoid_: research doc, sources file, topic doc (a topic doc is a digest of sources, not the registry) +_Avoid_: bare "research doc" (the noun; `Research doc:` is the field name), sources file, topic doc (a topic doc is a digest of sources, not the registry) ### Governance diff --git a/docs/adr/0004-skill-audit-info-finding-level.md b/docs/adr/0004-skill-audit-info-finding-level.md index e6610f0..eaea053 100644 --- a/docs/adr/0004-skill-audit-info-finding-level.md +++ b/docs/adr/0004-skill-audit-info-finding-level.md @@ -5,6 +5,9 @@ merged into `factory-audit`, which dispatches to a skill flow and an agent flow `skill-audit` below as `factory-audit`'s skill flow. The decision itself is unchanged — ADR-0025 carried every audit criterion, tier and finding level across as-is. +**Amended by ADR-0028 (2026-09-21).** INFO stays for a check that cannot run. A check that ran and +found a mismatch in `Research doc:` is now a FAIL, so INFO no longer covers it. + `skill-audit` shipped with two finding levels: FAIL (blocks shipping) and SUGGESTION (optional improvement). Provenance validation introduced observations that are worth surfacing but not actionable: a `references/*.md` file with no diff --git a/docs/adr/0028-research-doc-names-the-research-registry.md b/docs/adr/0028-research-doc-names-the-research-registry.md index 70557ea..5d89350 100644 --- a/docs/adr/0028-research-doc-names-the-research-registry.md +++ b/docs/adr/0028-research-doc-names-the-research-registry.md @@ -9,8 +9,8 @@ whose `## H2` headings are the source slugs. The corpus did something else: 29 o entries pointed at a research topic doc annotated `(whole-document reference)`, and 6 values were not a single path (comma-separated lists and shell brace expansion, plus a semicolon pair in `gitea-releases`). Checks 7 and 8 of `validate-provenance.sh` look the slug up as an H2 in the named -file, so 36 entries reported INFO and nothing failed. Measured by running the script over all 39 skill -directories, since nothing else runs it over the corpus. +file, so 36 entries reported INFO and nothing failed. Measured by running the script over all 38 skill +directories (27 with a `references/sources.md`, 11 without), since nothing else runs it over the corpus. We decided that `Research doc:` names exactly one **Research registry** (the term is in `CONTEXT.md`), as the spec always said. Slug-to-H2 lookup in the registry is the only provenance link @@ -56,6 +56,17 @@ pairs are rejected outright, since nothing expands them in a markdown field. - **(c) Everything FAIL (rejected).** Fails a correctly-provenanced skill audited from a deployed copy, which the file-structure exemption exists to prevent. +**Q4 — enforcement.** A corpus-wide sweep gate lands in the same change: a test or pre-push hook that +runs `validate-provenance.sh` over every `plugins/*/.apm/skills/*/` and fails on any FAIL. Deferring it +was rejected because without a caller the FAIL tier is inert; nothing but `check-scope-walkup-sync.sh` +(on fixtures) invokes the validator today. + +**Q5 — parser parity.** `parse_research_doc` accepts the bullet spelling (`- **Research doc:**`) as +`parse_contributing_files` already does, with a regression test. `parse_status` was removed from the +validator during this change, so it gets no test. Included because it is the same failure shape as +#111 and #118 (a parser returns "nothing found", the caller reads it as "nothing declared"), sits in +the same file, and `gitea-releases` already writes the unhyphenated form. + **Q6 — what happens to check 8.** Found unsatisfiable during the migration, after Q3 was decided. Check 8 requires every `extracted` slug in the research doc to appear in the skill's `sources.md`. That worked while entries pointed at topic docs, and was dormant. Under Q1(a) the named file is a @@ -77,8 +88,10 @@ check on every `Basis:` bullet would fail them. - **(a) A bullet annotated `(removed in )` skips the existence check (chosen).** The check stays for live paths, which is what catches a renamed ADR, and deletion becomes an explicit, auditable - annotation. Weakness: the annotation can be written on any bullet to avoid the check. Verifying the - sha with `git cat-file -e` would close that, and was left out as over-engineering for three bullets. + annotation. The annotation is anchored at the end of the value and the sha is 7-40 hex characters. + Weakness: the annotation can be written on any bullet to avoid the check. Verifying the sha with + `git cat-file -e` would close that; the user decided against it as over-engineering for three + bullets, so the sha is format-checked only, not verified. - **(b) `Basis:` becomes free prose with no existence check (rejected).** Gives up the one check that catches a renamed or moved ADR. - **(c) Drop those `Basis:` lines and keep `none` with a prose reason (rejected).** Loses the @@ -92,13 +105,15 @@ fixtures in this repo". No such fixture or test exists in the tree or in history in `d1afdbe` with no test files, and the only vale test ever deleted (`4de5b6b`) guards an unrelated `E100`. Under Q2 it FAILed for a missing `Basis:`. -- **(e) Remove the entry and its `source_keys` citations (chosen).** The stated basis was false, so - there is nothing honest to declare. The behavioural rules stay in the skills; only the provenance - claim goes. The gate needs no allowlist. +- **(e) Remove the entry and its `source_keys` citations (chosen, as the interim state).** The stated + basis was false, so there is nothing honest to declare. The behavioural rules stay in the skills; + only the provenance claim goes. The gate needs no allowlist. - **(a) `Basis: tests/test-vale-wrap.sh` (rejected).** Backs about one of six claims and overstates the rest. -- **(b) Commit reproduction fixtures (rejected for now).** The right fix if the behaviours matter, but - separate work from this issue. +- **(b) Commit reproduction fixtures (chosen, supersedes the interim removal).** The user decided to + commit real Vale reproduction fixtures under `plugins/lint` rather than soften the wording. The + `house-vale-3-15-2-repro` claim is restored only once it is backed by committed fixtures, and it + names them via `Basis:` (with `Research doc: none`). Until they land, the claim stays absent. - **(c) Allow `none` without `Basis:` for "house-verified" entries (rejected).** Reopens Q2 and gives an escape hatch for unverified claims. - **(d) Keep the entry and allowlist the two skills in the gate (rejected).** Keeps a false claim in @@ -107,16 +122,6 @@ in `d1afdbe` with no test files, and the only vale test ever deleted (`4de5b6b`) `configuration-reference.md` still says its rows were "reproduced against Vale 3.15.2"; that wording now has no provenance entry behind it and is left for a separate decision. -**Q4 — enforcement.** A corpus-wide sweep gate lands in the same change: a test or pre-push hook that -runs `validate-provenance.sh` over every `plugins/*/.apm/skills/*/` and fails on any FAIL. Deferring it -was rejected because without a caller the FAIL tier is inert; nothing but `check-scope-walkup-sync.sh` -(on fixtures) invokes the validator today. - -**Q5 — parser parity.** `parse_status` and `parse_research_doc` accept the bullet spelling -(`- **Status:**`) as `parse_contributing_files` already does, with a regression test. Included because -it is the same failure shape as #111 and #118 (a parser returns "nothing found", the caller reads it as -"nothing declared"), sits in the same file, and `gitea-releases` already writes the unhyphenated form. - ## Consequences - About 40 `references/sources.md` entries migrate: roughly 30 repoint from a topic doc to the registry, @@ -133,4 +138,6 @@ it is the same failure shape as #111 and #118 (a parser returns "nothing found", its mention from `skill-file-structure.md` and `create.md` where present. - The corpus-wide sweep is a new gate: register it in `docs/spec/gates.md` and `.pre-commit-config.yaml`. The corpus must be migrated in the same change or the suite goes red. +- The validator rejects an absolute path or one that escapes the repo with `..` in `Research doc:` and + `Basis:`, and rejects a `Research doc:` value with internal whitespace, backticks, or a comma list. - Reversing this means re-migrating the same entries, which is why it is recorded. diff --git a/docs/spec/gates.md b/docs/spec/gates.md index ad2a683..7af78c4 100644 --- a/docs/spec/gates.md +++ b/docs/spec/gates.md @@ -21,12 +21,12 @@ Install hooks via `pc-run`, wiring **all three stages**. This repo's `.pre-commi `default_install_hook_types`, so a plain install silently skips `commit-msg` (Conventional Commits) and `pre-push` (everything below). -The pre-push command reports **10** hooks, not 8. The extra two are pre-commit's own `meta` hooks, +The pre-push command reports **11** hooks, not 9. The extra two are pre-commit's own `meta` hooks, `check-hooks-apply` and `check-useless-excludes`: they declare no `stages:`, so they run at every stage including this one. Both are declared in this repo's `.pre-commit-config.yaml` like everything -else — what separates them is `repo: meta` (pre-commit's own built-ins) from `repo: local`. Eight +else — what separates them is `repo: meta` (pre-commit's own built-ins) from `repo: local`. Nine is the count of hooks this repo authors itself, and `--hook-stage pre-push --all-files` is a full -rehearsal of all eight. A PR merged through Gitea's merge button runs none of them: no local push +rehearsal of all nine. A PR merged through Gitea's merge button runs none of them: no local push happens at all. A real push has a gap of its own. When one `git push` carries several refs diff --git a/plugins/gitea/.apm/skills/gitea-releases/references/sources.md b/plugins/gitea/.apm/skills/gitea-releases/references/sources.md index 6b559d7..2886cbd 100644 --- a/plugins/gitea/.apm/skills/gitea-releases/references/sources.md +++ b/plugins/gitea/.apm/skills/gitea-releases/references/sources.md @@ -4,7 +4,7 @@ - **URL:** https://gitea.com/gitea/gitea-mcp - **Description:** Official gitea-mcp repository; operation/*.go source files documenting the MCP tools, their parameters, and CLI flags. Originally extracted at v1.3.0; the input parameter schemas in `references/call-signatures.md` were re-verified live via `ToolSearch` against the deployed server, **last verified at v1.7.0** as reported by `get_gitea_mcp_server_version`. -- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digested in gitea/api-reference.md, Releases and Tags section, and gitea/troubleshooting.md, `delete_release` numeric-id gotcha and `per_page` defaults) +- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digest: plugins/gitea/docs/research/docs/gitea/api-reference.md, Releases and Tags section; also plugins/gitea/docs/research/docs/gitea/troubleshooting.md, `delete_release` numeric-id gotcha and `per_page` defaults) **Contributing files:** - SKILL.md (Dispatch table, Gotchas) @@ -16,7 +16,7 @@ - **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go - **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for tags and releases. -- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digested in gitea/api-reference.md, Releases and Tags response shapes) +- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digest: plugins/gitea/docs/research/docs/gitea/api-reference.md, Releases and Tags response shapes) **Contributing files:** - references/call-signatures.md (release/tag object shapes) @@ -27,7 +27,7 @@ - **URL:** context7:/websites/gitea - **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — release and tag semantics, draft/prerelease behavior. -- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digested in gitea/workflow-conventions.md, Release and tag conventions section) +- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digest: plugins/gitea/docs/research/docs/gitea/workflow-conventions.md, Release and tag conventions section) **Contributing files:** - SKILL.md (Gotchas — draft/prerelease as explicit flags) @@ -39,7 +39,7 @@ - **URL:** context7:/git_gitea_com/gitea_tea - **Description:** Official `tea` CLI (reference Gitea client) docs on Context7 — practitioner release/tag command patterns, semver tag conventions, draft/prerelease flags, release-notes-from-file conventions. -- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digested in gitea/workflow-conventions.md, Release and tag conventions section) +- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md (digest: plugins/gitea/docs/research/docs/gitea/workflow-conventions.md, Release and tag conventions section) **Contributing files:** - references/conventions.md (semver tag naming, release-notes sourcing) diff --git a/plugins/kyberforge/.apm/skills/skill-author/references/create.md b/plugins/kyberforge/.apm/skills/skill-author/references/create.md index 2db4506..9dd569e 100644 --- a/plugins/kyberforge/.apm/skills/skill-author/references/create.md +++ b/plugins/kyberforge/.apm/skills/skill-author/references/create.md @@ -177,11 +177,11 @@ If a research `sources.md` is present in the conversation context: source slugs (e.g. `plugins/myplugin/docs/research/docs//sources.md`) — never a topic document, and never a list: no brace expansion, no comma- or semicolon-separated paths, no second `Research doc:` line. A pointer to the topic document that digested the source goes in - an annotation after the path, e.g. ` (digested in remotes.md)`, where it is not + an annotation after the path, e.g. ` (digest: )`, where it is not checked. `/factory-audit` fails a slug missing from the registry it names. - If the entry has no Research registry — an org convention, an ADR, a house-verified - reproduction — write `- **Research doc:** none` and name what it was drawn from with one + If the entry has no Research registry — an org convention, an ADR, a reproduction + backed by committed fixtures or tests named in `Basis:` — write `- **Research doc:** none` and name what it was drawn from with one `- **Basis:** ` line per path. Each Basis path is checked to exist; annotate one that has since been deleted `(removed in )` and the check is skipped. `none` with no Basis is a FAIL.