Skip to content

feat(docs-check): subcommand-coverage gate — walk clap tree + assert each path has an embedded doc#241

Merged
avrabe merged 4 commits intomainfrom
feat/docs-coverage-gate
Apr 29, 2026
Merged

feat(docs-check): subcommand-coverage gate — walk clap tree + assert each path has an embedded doc#241
avrabe merged 4 commits intomainfrom
feat/docs-coverage-gate

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented Apr 29, 2026

Summary

Lands the subcommand-coverage doc gate that surfaced as Test 1 in the
embedded-docs corpus audit. The gate walks the live clap CLI tree and
asserts that every subcommand path has an embedded rivet docs <topic>
entry; it surfaces the uncovered set in plain text or JSON and supports
a warn-only and a --strict (CI-gate) mode.

This is the inverse of the existing SubcommandReferences invariant
(which catches docs referencing non-existent subcommands): here we
catch existing subcommands without documentation.

What's new

  • rivet docs check --coverage — walk-and-report. Default warn-only,
    exits 0 even when uncovered paths exist.
  • rivet docs check --coverage --strict — fail-on-uncovered. The
    future CI gate.
  • rivet docs check --coverage --format json — the standard envelope
    (command, status, total, covered, uncovered, subcommands).
  • New embedded rivet docs docs-coverage topic with the matching
    rules, the warn-then-strict ramp-up, and the allow-list policy.
  • CI step in .github/workflows/ci.yml runs --coverage warn-only on
    every PR. Flip to --strict once the obvious gaps are filled.

Coverage rules (priority order)

  1. Exact slug match (schema/showschema-show, or literal
    schema/show).
  2. Parent-walk to the next-shorter path.
  3. Manual umbrella mapping via COVERAGE_TOPIC_MAP — e.g. cli covers
    most top-level commands; mutation covers add/link/modify/etc.
  4. Allow-list for clap-builtin synthetic commands (help,
    commit-msg-check).

Inventory at 0.6.0

The gate currently flags 33 uncovered paths across 7 top-level
subcommands:

  • variant (12 leaves) — feature model + binding model surface
  • baseline (2 leaves) — distributed baselines
  • snapshot (3 leaves) — project state capture/diff
  • runs (3 leaves) — .rivet/runs/ audit trail
  • pipelines (3 leaves) — agent-pipelines blocks
  • templates (4 leaves) — per-pipeline-kind templates
  • close-gaps (top-level) — oracle-gated gap-closure loop

mcp got its dedicated topic in 0.5.1 and is now covered. The
intended follow-up is to fill these gaps one family at a time, then
flip the CI step to --strict.

Warn-then-strict ramp-up

The CI step intentionally lands warn-only so the existing inventory
doesn't break the build. The follow-up PR (or a final commit on this
branch once docs catch up) flips the step to --strict. Tests are
written against report shape rather than specific names so they
stay green as the inventory shrinks.

Test plan

  • cargo check -p rivet-cli clean
  • cargo clippy -p rivet-cli --all-targets -- -D warnings clean
  • cargo fmt -p rivet-cli --check clean
  • cargo test -p rivet-cli all green (8 new unit tests + 5
    integration tests)
  • Smoke: rivet docs check --coverage lists 81 paths, marks 33
    uncovered (warn-only exits 0)
  • Smoke: rivet docs check --coverage --strict exits 1 with the
    same report
  • Backward-compat: rivet docs check (no flags) still runs the
    existing doc-vs-reality invariants
  • rivet docs docs-coverage renders the new topic content

🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

📐 Rivet artifact delta

No artifact changes in this PR. Code-only changes (renderer, CLI wiring, tests) don't touch the artifact graph.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

avrabe added 4 commits April 29, 2026 22:15
…each path has an embedded doc

Adds `--coverage` (and `--strict`) flags to `rivet docs check` that walk
the live clap CLI tree, build subcommand paths (`schema/show`,
`variant/check-all`, …), and cross-reference each against the embedded
docs registry. Default is warn-only so the gate can land in CI before
the existing inventory of uncovered subcommands is filled.

Coverage rules are layered:
  1. Exact slug match (`schema/show` → `schema-show` or literal `schema/show`)
  2. Parent-walk to the next-shorter path
  3. Manual umbrella mapping via `COVERAGE_TOPIC_MAP` (e.g. `cli` covers
     most top-level commands; `mutation` covers add/link/modify/…)
  4. Allow-list for clap-builtin synthetic commands (`help`,
     `commit-msg-check`)

The 0.6.0 inventory has 33 uncovered paths across 7 top-level
subcommands: variant, baseline, snapshot, runs, pipelines, templates,
close-gaps. (`mcp` got its topic in 0.5.1 and is now covered.) The
`--strict` flag is the future CI gate; `--coverage` alone is the
discovery surface.

Touches the existing `cmd_docs_check` dispatch only to add the new
`--coverage` early branch — backward compatible with `rivet docs check`
(no flags).

Implements: REQ-007
Refs: REQ-004
…ic update

Exposes `docs::topic_slugs()` and `docs::has_topic()` so the
subcommand-coverage gate can cross-reference clap subcommand paths
against the embedded TOPICS registry without re-listing slugs.

Adds a new `docs-coverage` reference topic that documents the gate's
matching rules, the warn-then-strict ramp-up, and the allow-list policy
for clap-builtin synthetic commands.

Updates the `cli` reference topic to surface `rivet docs check
--coverage` next to the existing `rivet docs check` entry.

Implements: REQ-007
Five integration tests exercising the subcommand-coverage gate's
external contract:

  * coverage_warn_only_exits_zero — the default mode never breaks the
    build, even when uncovered paths are listed
  * coverage_strict_fails_when_uncovered_present — `--strict` exits
    non-zero exactly when the report shows uncovered paths (and exit 0
    otherwise, so the test stays green when docs catch up)
  * coverage_json_envelope — `--format json` produces the standard
    envelope (command/status/total/covered/uncovered/subcommands)
  * coverage_allowlist_excludes_internal_helpers — `commit-msg-check`
    is allow-listed and never appears in the uncovered list
  * docs_check_without_coverage_unchanged — backward compatibility:
    `rivet docs check` (no flags) still runs the existing doc-vs-reality
    invariants

Asserts on report SHAPE rather than specific names so the tests stay
green as docs are written for previously-uncovered subcommands.

Eight unit tests in `coverage_gate_tests` exercise
`compute_coverage_rows` against a fake clap tree (one parent + two
leaves) — the implementation sketch from the task spec — covering
parent-walk, leaf-specific override, allow-list, umbrella topic_map,
and a sanity check that every entry in the production
`COVERAGE_TOPIC_MAP` points at a real topic in `docs::TOPICS`.

Verifies: REQ-007
Adds a new step to the existing `docs-check` job that runs the
subcommand-coverage gate in warn-only mode (no `--strict`). This makes
the inventory visible in every CI run without breaking the build on the
existing seven uncovered top-level commands (variant, baseline,
snapshot, runs, pipelines, templates, close-gaps).

The flip to `--strict` happens in a follow-up commit once the obvious
gaps have docs.
@avrabe avrabe force-pushed the feat/docs-coverage-gate branch from 392b2fd to f9f8671 Compare April 29, 2026 20:16
@avrabe avrabe merged commit 40fdff0 into main Apr 29, 2026
25 of 40 checks passed
@avrabe avrabe deleted the feat/docs-coverage-gate branch April 29, 2026 21:36
avrabe added a commit that referenced this pull request Apr 30, 2026
…246)

Workspace, vscode-rivet, and npm root package versions bumped to 0.7.0.
Platform packages stay on the release-npm.yml override path.

What's in 0.7.0:

- feat(schema): rivet schema migrate Phase 2 (#242) — full git-rebase
  conflict-resolution UX. Conflict markers in YAML, --continue,
  --skip, --edit. New MigrationConflict invariant in rivet docs check.
- feat(docs-check): subcommand-coverage gate (#241) — walks the live
  clap CLI tree and asserts each path has an embedded docs topic.
  Default warn-only; --strict makes it enforcing.
- feat(validate): prose-mention-without-typed-link warning (#234,
  closes #207).
- feat(schemas): vv-coverage repo-status type (#232, partial #188).
- feat(mutants): canonical cargo-mutants template (#229, closes #185).
- docs(pre-commit): canonical 21-hook template (#222, closes #186).
- fix(ci): Release workflow now idempotent on existing tag (#244).

Known issue: v0.5.0 / v0.5.1 / v0.6.0 release pages have no binary
assets attached because the workflow's Create Release step failed
on each (race with manual gh release create). The fix in #244 lands
in this release; v0.7.0 onward is unaffected. Older releases need
a manual gh release upload to backfill.

Verified: cargo check, cargo clippy --workspace -- -D warnings,
cargo test -p rivet-cli, rivet docs check (clean), rivet docs check
--coverage reports 48/81 paths covered (warn-only).

Trace: skip
avrabe added a commit that referenced this pull request May 1, 2026
…) (#250)

Two fixes to `rivet docs check --coverage` (the gate from #241):

* B5 — rule 4 (umbrella mapping via `COVERAGE_TOPIC_MAP`) now requires
  the parent topic body to mention the child subcommand by name as a
  whole word, case-insensitive. A catch-all `cli` mapping that doesn't
  reference the family is no coverage at all. With the current TOPICS
  registry this surfaces `lsp` and `batch` as additional gaps
  (was 48/81 covered; now 46/81).

* B6 — replace the implicit two-state warn/strict pattern with three
  explicit modes:
    --coverage              print, exit 0, no annotations (local use)
    --coverage --warn-only  print + emit ::warning::file=…::… GitHub
                            Actions annotations per gap, exit 0
                            (CI rollout — surface gaps inline on PRs
                            without failing the build)
    --coverage --strict     print, exit 1 on any uncovered (enforcing CI)

  `--warn-only` and `--strict` are mutually exclusive (clap-enforced).
  CI workflow now uses `--warn-only` explicitly so the contract is
  legible at the call site rather than relying on the previous default
  warn-on-failure semantics.

The `rivet docs docs-coverage` topic and the docs::TOPICS body are
updated to describe the three modes and the rule-4 body-mention check.

Tests:
  * 6 new unit tests for the body-mention rule (positive/negative,
    case-insensitive, whole-word, plus a direct test of the
    `topic_body_mentions` helper).
  * Integration: `coverage_warn_only_emits_github_annotations` asserts
    at least one `::warning file=…::` line is printed and exit is 0.
  * Integration: `coverage_strict_currently_fails_on_main` pins exit 1
    behaviour while the inventory has gaps.
  * Integration: `coverage_warn_only_and_strict_are_mutually_exclusive`
    pins clap conflict-rejection.
  * Integration: existing `coverage_default_exits_zero_no_annotations`
    asserts no `::warning::` lines in the default mode.

Closes #248.

Implements: REQ-007
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant