From d081ff01101da46b3061b92859f824ae81dca46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Wed, 16 Sep 2026 22:00:48 +0100 Subject: [PATCH] ci: exempt canonical plugin registry source (#3736) --- .github/scripts/pr-docs.cjs | 3 + .github/scripts/pr-docs.test.cjs | 34 ++++++ .../2026-09-10-pr-documentation-coverage.md | 6 +- docs/plans/pr-documentation-coverage/plan.md | 23 +++- .../task-04-exempt-plugin-registry-source.md | 102 ++++++++++++++++++ .../pull-request-documentation-coverage.md | 2 + .../pull-request-documentation-coverage.md | 4 +- 7 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 docs/plans/pr-documentation-coverage/task-04-exempt-plugin-registry-source.md diff --git a/.github/scripts/pr-docs.cjs b/.github/scripts/pr-docs.cjs index f7a6a7704a..312c72e63e 100644 --- a/.github/scripts/pr-docs.cjs +++ b/.github/scripts/pr-docs.cjs @@ -232,6 +232,9 @@ function pathExemption(pathname) { if (pathname === 'docs' || pathname.startsWith('docs/')) { return 'documentation tree'; } + if (pathname === 'plugin-registry/plugins.yaml') { + return 'canonical plugin registry source'; + } if (/\.(?:md|mdx|markdown)$/i.test(pathname)) { return 'Markdown file'; } diff --git a/.github/scripts/pr-docs.test.cjs b/.github/scripts/pr-docs.test.cjs index 61efa8a931..0f152c06e8 100644 --- a/.github/scripts/pr-docs.test.cjs +++ b/.github/scripts/pr-docs.test.cjs @@ -39,6 +39,40 @@ test('recognized documentation-only paths are exempt', () => { assert.equal(result.exemptPaths.length, 9); }); +// @covers AC-CI-PR-DOCS-001.7 +test('the canonical plugin registry source is exempt', () => { + const result = validator.classifyChangedFiles([ + { filename: 'plugin-registry/plugins.yaml', status: 'modified' }, + ]); + + assert.equal(result.requiresCoverage, false); + assert.deepEqual(result.triggeringPaths, []); + assert.deepEqual(result.exemptPaths, ['plugin-registry/plugins.yaml']); +}); + +// @covers AC-CI-PR-DOCS-001.7 +test('the registry exemption does not cover other registry files or mixed changes', () => { + const otherRegistryFile = validator.classifyChangedFiles([ + { filename: 'plugin-registry/schema.json', status: 'modified' }, + ]); + assert.equal(otherRegistryFile.requiresCoverage, true); + assert.deepEqual(otherRegistryFile.triggeringPaths, ['plugin-registry/schema.json']); + + const registryBuilder = validator.classifyChangedFiles([ + { filename: 'plugin-registry/build-index.mjs', status: 'modified' }, + ]); + assert.equal(registryBuilder.requiresCoverage, true); + assert.deepEqual(registryBuilder.triggeringPaths, ['plugin-registry/build-index.mjs']); + + const mixedChange = validator.classifyChangedFiles([ + { filename: 'plugin-registry/plugins.yaml', status: 'modified' }, + { filename: 'apps/backend/runtime.go', status: 'modified' }, + ]); + assert.equal(mixedChange.requiresCoverage, true); + assert.deepEqual(mixedChange.exemptPaths, ['plugin-registry/plugins.yaml']); + assert.deepEqual(mixedChange.triggeringPaths, ['apps/backend/runtime.go']); +}); + // @covers AC-CI-PR-DOCS-001.2 test('recognized harness configuration paths are exempt', () => { const result = validator.classifyChangedFiles([ diff --git a/docs/decisions/2026-09-10-pr-documentation-coverage.md b/docs/decisions/2026-09-10-pr-documentation-coverage.md index f08931ff1e..6466e4e5b1 100644 --- a/docs/decisions/2026-09-10-pr-documentation-coverage.md +++ b/docs/decisions/2026-09-10-pr-documentation-coverage.md @@ -12,6 +12,7 @@ The diff does not establish which harness the contributor used. The file-based knowledge system permits manually authored artifacts. Enforcement should validate useful context while allowing small corrections without artificial documentation churn. +A curated marketplace update to the canonical `plugin-registry/plugins.yaml` source is a similarly narrow repository-maintenance change. Requiring a delivery package for that single pointer update adds process without providing additional design context. ## Decision @@ -20,6 +21,8 @@ Other changes require a changed work order linked to a plan, requirements, accep Previously merged specifications can be referenced without cosmetic edits. Reviewers judge whether changed behavior needs updated contracts. The override persists while the label is present and affects only this check. +The exact `plugin-registry/plugins.yaml` source is exempt when it is the only non-documentation path changed. The exemption does not include other files under `plugin-registry/`; a pull request that also changes any non-exempt path still requires linked delivery context. + Harness configuration and definitions are exempt when they use the repository's recognized harness formats: Codex agent or config TOML, Claude settings JSON, or Cursor rule MDC. Markdown harness files are covered by the general Markdown exemption. This avoids requiring delivery records for contributor tooling changes while keeping arbitrary JSON, YAML, and other files subject to normal evaluation. CI owns this policy. It does not require use of a particular agent or prove that plans were committed before code. @@ -27,7 +30,7 @@ The check reports failures before ruleset activation; mandatory merge enforcemen ## Consequences -Results are reproducible and need no model credentials. Small code fixes and refactors can require a maintainer exception. +Results are reproducible and need no model credentials. Small code fixes and refactors can require a maintainer exception. A registry-only pointer update passes without a package while the rest of the registry remains covered by the normal policy. Structural links cannot prove semantic relevance. Review remains responsible for incomplete or misleading artifacts. PR-wide exceptions can become stale as scope grows; maintainers must remove the label when it no longer applies. @@ -39,6 +42,7 @@ PR-wide exceptions can become stale as scope grows; maintainers must remove the - Let a PR-body declaration exempt runtime changes: makes the policy self-waivable without the requested label. - Use an AI classifier as the required gate: introduces cost, nondeterminism, and untrusted prompt inputs before a simple structural policy has been evaluated. - Require changes to every linked document: encourages meaningless edits when an implementation follows an already merged design. +- Exempt the entire `plugin-registry/` tree: would also bypass context for schema, generator, and generated-catalog changes. ## Related artifacts diff --git a/docs/plans/pr-documentation-coverage/plan.md b/docs/plans/pr-documentation-coverage/plan.md index b58135e430..92b79597a7 100644 --- a/docs/plans/pr-documentation-coverage/plan.md +++ b/docs/plans/pr-documentation-coverage/plan.md @@ -1,5 +1,6 @@ --- created: 2026-09-10 +updated: 2026-09-16 status: done requirements: - REQ-CI-PR-DOCS-001 @@ -14,12 +15,12 @@ legacy_specs: [] ## Overview -Build a deterministic coverage validator, integrate PR status reporting, then add merge-queue evaluation and contributor guidance. +Build a deterministic coverage validator, integrate PR status reporting, add merge-queue evaluation and contributor guidance, then refine narrow path exemptions from observed repository-maintenance cases. The CI system owns this package because it controls repository checks and label exceptions. ## Scope -In scope: narrow exemptions, linked artifact validation, the exact `no-docs-allow` override, current-revision statuses, queue compatibility, and actionable summaries. +In scope: narrow exemptions including the canonical plugin registry source, linked artifact validation, the exact `no-docs-allow` override, current-revision statuses, queue compatibility, and actionable summaries. Out of scope: AI classification, application UI, automatic label management, publishing a PR, and live ruleset mutations. Public user documentation remains governed by the existing contribution checklist. @@ -30,6 +31,7 @@ Use the proposed `.github/scripts/pr-docs.cjs` module for pure policy functions Use `.github/workflows/pr-docs.yml` for base-controlled execution and the `PR documentation coverage` commit status. Reuse the existing Node runtime from GitHub-hosted runners and the built-in test runner; no pnpm dependency installation is needed. Register Node and workflow contract tests in `.github/workflows/lint-action-pinning.yml`. +Keep `plugin-registry/plugins.yaml` as an exact path exemption in the classifier; do not broaden the rule to the full registry tree. Existing patterns: `.github/workflows/pr-size-label.yml` for metadata pagination, `.github/scripts/pr-size-label-workflow-contract_test.py` for workflow checks, and @@ -42,6 +44,7 @@ All named test suites below are proposed files. | Criteria | Evidence | | --- | --- | | AC-CI-PR-DOCS-001.2 through .6 | `pr-docs.test.cjs`: classification and artifact graph fixtures | +| AC-CI-PR-DOCS-001.7 | `pr-docs.test.cjs`: exact registry-source exemption and mixed-path trigger fixture | | AC-CI-PR-DOCS-001.1; AC-CI-PR-DOCS-002.1 through .4 | Fake GitHub adapter exercises draft/fork events and label transitions | | AC-CI-PR-DOCS-003.1 through .3 | API failures, pagination caps, stale head/label reads, path and content restrictions | | AC-CI-PR-DOCS-003.4 through .5 | Per-member queue evaluation, active prefix reevaluation, mismatched queue boundaries, override removal, and rollout checklist | @@ -61,6 +64,7 @@ Live smoke tests and required-check activation are deployment steps, not complet - [x] [Task 01: Validate documentation coverage](task-01-coverage-validator.md) - [x] [Task 02: Report pull request coverage](task-02-pr-workflow.md) - [x] [Task 03: Support merge queue coverage](task-03-queue-coverage.md) +- [x] [Task 04: Exempt the canonical plugin registry source](task-04-exempt-plugin-registry-source.md) Execute sequentially. No subagents are authorized. @@ -98,9 +102,24 @@ Implementation verification on 2026-09-10: Repository-wide `zizmor .github/workflows` still reports existing findings in unrelated workflows; the new workflow has no reported findings. +## Amendment: canonical plugin registry source + +The original three work orders remain complete. This amendment adds one exact +path exemption for the curated `plugin-registry/plugins.yaml` pointer source. +The implementation preserves normal coverage for every other registry path and +for any pull request that combines the exempt source with a non-exempt path. + +Task 04 verification completed on 2026-09-16: + +- 77 validator tests, 7 workflow contract tests, and 9 action-pinning tests passed. +- All 24 workflow files passed action-pinning lint. +- `zizmor .github/workflows/pr-docs.yml` reported no findings. +- The specification catalog and linter passed; `git diff --check` passed. + ## Risks - Conservative defaults require labels for some small fixes, refactors, and dependency manifest changes. +- An overly broad registry match could allow schema, generator, or generated-catalog changes to bypass delivery context; exact-path tests constrain this risk. - The target-branch event queue retains up to 100 pending runs; higher bursts can still cancel new runs. - Structural validation cannot establish semantic relevance or planning chronology. - Merge queue boundary resolution needs real payload validation before mandatory rollout. diff --git a/docs/plans/pr-documentation-coverage/task-04-exempt-plugin-registry-source.md b/docs/plans/pr-documentation-coverage/task-04-exempt-plugin-registry-source.md new file mode 100644 index 0000000000..4ad46b6483 --- /dev/null +++ b/docs/plans/pr-documentation-coverage/task-04-exempt-plugin-registry-source.md @@ -0,0 +1,102 @@ +--- +id: "04-exempt-plugin-registry-source" +title: "Exempt the canonical plugin registry source" +status: done +wave: 4 +depends_on: + - "03-queue-coverage" +plan: "plan.md" +requirements: + - REQ-CI-PR-DOCS-001 +acceptance_criteria: + - AC-CI-PR-DOCS-001.7 +system_design: + - ../../specs/ci/system-design/pull-request-documentation-coverage.md +--- + +# Task 04: Exempt the canonical plugin registry source + +## Summary + +Allow a pull request that updates only the curated `plugin-registry/plugins.yaml` +source to pass documentation coverage without a linked delivery package. Keep +all other registry paths and mixed registry-plus-runtime changes covered. + +## In scope + +- Add the exact `plugin-registry/plugins.yaml` path to the classifier exemption list. +- Add regression coverage for the registry-only and mixed-path cases. +- Reconcile the CI requirement, system design, decision, and plan records. + +## Out of scope + +- Exempting the full `plugin-registry/` directory. +- Changing the registry index workflow, registry schema, package validation, labels, or rulesets. +- Updating public product documentation. + +## Acceptance + +- A registry-only change is classified as exempt and does not require delivery artifacts. +- A registry change combined with any non-exempt path still requires coverage. +- Existing path exemptions and generic YAML classification remain unchanged. + +## Verification + +Run from the repository root: + +```bash +node --test .github/scripts/pr-docs.test.cjs +python3 .github/scripts/pr-docs-workflow-contract_test.py +python3 .github/scripts/lint-action-pinning_test.py +python3 .github/scripts/lint-action-pinning.py +zizmor .github/workflows/pr-docs.yml +python3 scripts/list-docs.py validate +python3 scripts/lint-spec-files.py --all +git diff --check +``` + +## Files likely touched + +- `.github/scripts/pr-docs.cjs` +- `.github/scripts/pr-docs.test.cjs` +- `docs/specs/ci/requirements/pull-request-documentation-coverage.md` +- `docs/specs/ci/system-design/pull-request-documentation-coverage.md` +- `docs/decisions/2026-09-10-pr-documentation-coverage.md` +- `docs/plans/pr-documentation-coverage/plan.md` + +## Dependencies + +Task 03. The existing coverage validator and workflow must remain the implementation boundary. + +## Risks + +- A prefix or glob exemption could accidentally cover registry schema, generator, or generated-catalog changes. Use exact-path matching and a negative mixed-path test. + +## Parallelism + +`sequential` + +## Inputs + +- [Requirements](../../specs/ci/requirements/pull-request-documentation-coverage.md) +- [System design](../../specs/ci/system-design/pull-request-documentation-coverage.md) +- [Plan](plan.md) +- [Decision](../../decisions/2026-09-10-pr-documentation-coverage.md) +- `.github/AGENTS.md` and the existing validator tests. + +## Results + +Implemented the exact `plugin-registry/plugins.yaml` exemption in the path +classifier and added positive and mixed-path regression coverage. Other registry +files still trigger coverage, and mixed changes retain their non-exempt paths. + +Verification: + +- `node --test .github/scripts/pr-docs.test.cjs`: 77 tests passed. +- `python3 .github/scripts/pr-docs-workflow-contract_test.py`: 7 tests passed. +- `python3 .github/scripts/lint-action-pinning_test.py`: 9 tests passed. +- `python3 .github/scripts/lint-action-pinning.py`: 24 workflows passed. +- `zizmor .github/workflows/pr-docs.yml`: no findings. +- `python3 scripts/list-docs.py validate`: 279 decisions and 959 specifications validated. +- `python3 scripts/lint-spec-files.py --all`: passed. +- `git diff --check`: passed. diff --git a/docs/specs/ci/requirements/pull-request-documentation-coverage.md b/docs/specs/ci/requirements/pull-request-documentation-coverage.md index 42b1e1d0c4..eb45534cc6 100644 --- a/docs/specs/ci/requirements/pull-request-documentation-coverage.md +++ b/docs/specs/ci/requirements/pull-request-documentation-coverage.md @@ -2,6 +2,7 @@ status: draft system: ci created: 2026-09-10 +updated: 2026-09-16 owners: - kandev --- @@ -33,6 +34,7 @@ Contributors can write the artifacts manually; use of the repository harness is - **AC-CI-PR-DOCS-001.4:** Existing plans and specifications shall qualify when the work order references them and they exist in the proposed revision. Contributors shall update contracts when behavior changes, but shall not need meaningless edits to unchanged contracts. - **AC-CI-PR-DOCS-001.5:** A deleted artifact, empty file, unresolved reference, unrelated unlinked document, or work order without requirement and acceptance references shall not satisfy coverage. - **AC-CI-PR-DOCS-001.6:** The result shall identify triggering paths, accepted references, missing artifacts, and corrective steps. Structural coverage shall not claim semantic completeness or prove that planning preceded coding. +- **AC-CI-PR-DOCS-001.7:** A pull request that changes only `plugin-registry/plugins.yaml` and other already exempt paths shall pass without a delivery package. Any additional non-exempt path shall continue to require coverage. ### REQ-CI-PR-DOCS-002: Explicit documentation exception diff --git a/docs/specs/ci/system-design/pull-request-documentation-coverage.md b/docs/specs/ci/system-design/pull-request-documentation-coverage.md index e234e70a19..37a17a1fec 100644 --- a/docs/specs/ci/system-design/pull-request-documentation-coverage.md +++ b/docs/specs/ci/system-design/pull-request-documentation-coverage.md @@ -1,5 +1,6 @@ --- status: draft +last_updated: 2026-09-16 system: ci requirements: - REQ-CI-PR-DOCS-001 @@ -42,10 +43,11 @@ Initial exemptions: - `docs/**` and Markdown files, including `AGENTS.md` and `CONTRIBUTING.md`. - Go `*_test.go`; JS/TS `*.test.*` and `*.spec.*` restricted to JS/TS source extensions; `apps/web/e2e/**`. - `apps/web/src/locales//.json`. +- Exact canonical registry source `plugin-registry/plugins.yaml`. - Exact lock basenames `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, `go.sum`, and `Cargo.lock`. - Recognized non-Markdown harness files: `.codex/agents/*.toml`, `.codex/config.toml`, `.claude/settings.json`, and `.cursor/rules/*.mdc`. -Do not exempt all JSON, YAML, assets, scripts, package manifests, Rust files, workflows, generated directories, or files containing the word `test`. +Keep other `plugin-registry/**` paths subject to normal coverage. Do not exempt all JSON, YAML, assets, scripts, package manifests, Rust files, workflows, generated directories, or files containing the word `test`. These can change shipped behavior or repository contracts. Add exemptions later only with concrete fixtures. This conservative policy creates false positives for small runtime fixes and refactors. The explicit label is their escape hatch.