You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parent:#1265 · Labels:enhancement, area/docs (auto, docs/**), area/ci (auto, .github/**); addstools/coverage/** to .github/labeler.yml + CODEOWNERS (no glob exists for that root) · Size: M–L · Depends on: none hard for the generator skeleton; soft on the dynamic-clusters epic (DC3 CUJ2 wiring, DC4 CLI-boundary coverage) for the data the matrix reports to be non-trivial. RQ3 can ship the generator + an honest "exercised: no / planned" matrix first, then fill in as the dynamic-clusters epic lands. Listed first deliberately: it de-risks the epic by shipping value independent of #1224 and the TestGrid epic.
Goal. Promote CUJs and CLI-verb coverage from demo+chainsaw-only into a versioned, generated, public coverage matrix that runs on main at a cadence (never a merge gate), cross-linked to the other two surfaces.
Scope.
Define the coverage data model: for each CUJ (CUJ1 training/kubeflow, CUJ2 inference/dynamo) and each CLI verb (snapshot, recipe, query, bundle, verify, validate, evidence{digest,publish,verify}, diff, mirror, trust, skill — the actual pkg/cli/*.go command set), record which is exercised, by what (chainsaw / KWOK / UAT / GPU-nightly), on what hardware class, at what cadence. Honestly mark the verbs no CUJ touches today (query, diff, mirror, verify, trust, skill) as not-yet-covered until the dynamic-clusters epic's DC4 brings them under test.
Account for the AICR-version axis (consistent with the dynamic-clusters epic's version matrix, DC5). The data model also records which AICR versions — main + the previous N stable releases — are exercised per recipe on real hardware, and at what cadence, mirroring the dynamic-clusters epic's nightly version-parameterized UAT matrix ({aicr version} × {intent} × {cloud}); the matrix surfaces this axis rather than collapsing all versions into a single "covered" cell, so a reader can tell whether an older stable AICR is still exercised against a recipe. The per-version live posture itself stays a link into TestGrid (which carries aicr_version as a column facet), never embedded here.
Distinguish from Epic: Recipe health tracking (ADR-009 V1) — enumeration, structural soundness, public matrix #1224's Coverage column (cross-link, don't overlap). ADR-009 V1 already ships a per-recipe Coverage column in docs/user/recipe-health.md derived from declared_coverage (named checks per phase, e.g. R:2 D:4 P:1 C:10; 009-recipe-health-tracking.md:259-262). RQ3's coverage-matrix.md is a different axis: it answers "which CUJs / CLI verbs are exercised, where, at what cadence," not "how many checks per phase does this recipe declare." State this distinction in the matrix header and cross-link the two pages so a reader does not mistake one for the other.
Source the matrix from durable, in-repo signals where possible: the chainsaw CLI trees (tests/chainsaw/cli/*, e.g. cuj1-training/, validate-phases/, bundle-*), the UAT CUJ trees (tests/uat/{aws,gcp,azure}/tests/cuj{1,2}-*/), and demos/cuj{1,2}-*.md. Caveat to call out:tests/uat/azure/tests/cuj{1,2}-*/ exist but no workflow references them (Azure UAT is stubbed — the dynamic-clusters epic's DC6 owns the revive-or-retire decision); the matrix must reflect Azure as stubbed/not-running, not as covered, and link to DC6.
New tools/coverage Go generator (cloning tools/bom / the planned tools/health shape): walks the in-repo signals, emits a deterministic Markdown table spliced into docs/user/coverage-matrix.md, with -deterministic -no-title flags mirroring tools/bom. MDX gate (load-bearing).make lint (inside make qualify) runs tools/check-docs-mdx, which fails any file under docs/user/ that has HTML comments (<!-- … -->) outside fenced code blocks (Check 3, tools/check-docs-mdx:78-79). The only reason container-images.md (the BOM output this clones) passes is a hard-coded single-file exclusion EXCLUDE="container-images.md" (tools/check-docs-mdx:30). Prefer option (b): use a splice marker that is NOT an HTML comment outside a code fence (an MDX-safe sentinel, e.g. inside a fenced block or an MDX comment {/* … */}), so coverage-matrix.md stays inside the MDX gate. Option (a) — refactoring the single EXCLUDE scalar into a multi-file allowlist and adding coverage-matrix.md — is acceptable only as a fallback, because each allowlisted file silently loses MDX/Fern-render validation and the allowlist will accrete every future generated page; if (a) is taken, add a test asserting allowlisted files still render under Fern so the carve-out is not an unguarded blind spot. Without one of these, the page trips the MDX gate and Epic AC fix: use workflow_run for PR coverage comments on fork PRs #5 ("pass make qualify") fails. make coverage-docs regenerates; make coverage-check is an opt-in staleness check paralleling bom-check (explicitly not wired into make qualify/lint/merge gate).
New .github/workflows/coverage-matrix-refresh.yaml, weekly clone of the shipped bom-refresh.yaml (cron, peter-evans/create-pull-request on drift, built-in GITHUB_TOKEN, chore/coverage-refresh branch, delete-branch: true, explicit documentation label; area labels (area/docs, area/ci) auto-assign from changed paths via labeler.yml). It refreshes the structural matrix (which tests exist) weekly; the live "did it pass on hardware" answer is a link into TestGrid, not embedded here (same link-only rule as RQ1).
Docs same PR: register docs/user/coverage-matrix.md in docs/index.yml under User Guide (mirrors ADR-009's registration of recipe-health.md, 009-recipe-health-tracking.md:409); cross-link from docs/user/recipe-health.md (RQ1) and docs/user/cli-reference.md. fern-docs-ci.yaml lychee + MDX-safety run on the new docs/** page on its introducing PR (hence the splice-marker requirement above).
Out of scope. Running the CUJs (the dynamic-clusters epic owns execution; RQ3 reports). A merge gate. Embedding live pass/fail (link to TestGrid). Per-verb unit-coverage % (that's make test-coverage, a different gate). #1224's per-recipe declared_coverage column (orthogonal; cross-link only).
Key files. New tools/coverage/ (+ labeler.yml/CODEOWNERS entries); new docs/user/coverage-matrix.md; docs/index.yml; docs/user/cli-reference.md; tools/check-docs-mdx (splice-marker-safe rendering, or the EXCLUDE allowlist fallback); Makefile (coverage-docs/coverage-check targets paralleling bom-docs / bom-check). Signal sources: tests/chainsaw/cli/*, tests/uat/{aws,gcp,azure}/tests/cuj{1,2}-*/, demos/cuj{1,2}-*.md, pkg/cli/*.go. Pattern source: .github/workflows/bom-refresh.yaml, tools/bom.
Tests. Generator unit tests: deterministic table output across two runs (byte-compare, not struct DeepEqual); a fixture set of chainsaw/UAT/demo trees produces the expected coverage rows; the verb list is derived from the actual pkg/cli command registry (so a new verb without coverage shows up as a not-yet-covered row rather than being silently dropped); Azure rows render as stubbed; make coverage-check flags a deliberately-stale doc. Clears the 75% floor on tools/coverage measured with pkg=tools/coverage, and clears the baseline-delta gate (no > 0.5% per-package regression; no new exported func at 0%).
Acceptance.docs/user/coverage-matrix.md is generated, versioned, registered, and cross-linked (including the explicit distinction from #1224's declared_coverage column); runs on main weekly via a clone of the BOM loop; passes the MDX gate (via an MDX-safe splice marker, or the guarded check-docs-mdx allowlist fallback); never gates merges; honestly reflects covered / not-yet-covered / stubbed; links to TestGrid for live posture rather than embedding it.
Child of #1265 · staged from docs/design/012-recipe-quality-surfaces.md (RQ3).
Parent: #1265 · Labels:
enhancement,area/docs(auto,docs/**),area/ci(auto,.github/**); addstools/coverage/**to.github/labeler.yml+CODEOWNERS(no glob exists for that root) · Size: M–L · Depends on: none hard for the generator skeleton; soft on the dynamic-clusters epic (DC3 CUJ2 wiring, DC4 CLI-boundary coverage) for the data the matrix reports to be non-trivial. RQ3 can ship the generator + an honest "exercised: no / planned" matrix first, then fill in as the dynamic-clusters epic lands. Listed first deliberately: it de-risks the epic by shipping value independent of #1224 and the TestGrid epic.Goal. Promote CUJs and CLI-verb coverage from demo+chainsaw-only into a versioned, generated, public coverage matrix that runs on
mainat a cadence (never a merge gate), cross-linked to the other two surfaces.Scope.
snapshot, recipe, query, bundle, verify, validate, evidence{digest,publish,verify}, diff, mirror, trust, skill— the actualpkg/cli/*.gocommand set), record which is exercised, by what (chainsaw / KWOK / UAT / GPU-nightly), on what hardware class, at what cadence. Honestly mark the verbs no CUJ touches today (query,diff,mirror,verify,trust,skill) asnot-yet-covereduntil the dynamic-clusters epic's DC4 brings them under test.main+ the previous N stable releases — are exercised per recipe on real hardware, and at what cadence, mirroring the dynamic-clusters epic's nightly version-parameterized UAT matrix ({aicr version} × {intent} × {cloud}); the matrix surfaces this axis rather than collapsing all versions into a single "covered" cell, so a reader can tell whether an older stable AICR is still exercised against a recipe. The per-version live posture itself stays a link into TestGrid (which carriesaicr_versionas a column facet), never embedded here.docs/user/recipe-health.mdderived fromdeclared_coverage(named checks per phase, e.g.R:2 D:4 P:1 C:10;009-recipe-health-tracking.md:259-262). RQ3'scoverage-matrix.mdis a different axis: it answers "which CUJs / CLI verbs are exercised, where, at what cadence," not "how many checks per phase does this recipe declare." State this distinction in the matrix header and cross-link the two pages so a reader does not mistake one for the other.tests/chainsaw/cli/*, e.g.cuj1-training/,validate-phases/,bundle-*), the UAT CUJ trees (tests/uat/{aws,gcp,azure}/tests/cuj{1,2}-*/), anddemos/cuj{1,2}-*.md. Caveat to call out:tests/uat/azure/tests/cuj{1,2}-*/exist but no workflow references them (Azure UAT is stubbed — the dynamic-clusters epic's DC6 owns the revive-or-retire decision); the matrix must reflect Azure as stubbed/not-running, not as covered, and link to DC6.tools/coverageGo generator (cloningtools/bom/ the plannedtools/healthshape): walks the in-repo signals, emits a deterministic Markdown table spliced intodocs/user/coverage-matrix.md, with-deterministic -no-titleflags mirroringtools/bom. MDX gate (load-bearing).make lint(insidemake qualify) runstools/check-docs-mdx, which fails any file underdocs/user/that has HTML comments (<!-- … -->) outside fenced code blocks (Check 3,tools/check-docs-mdx:78-79). The only reasoncontainer-images.md(the BOM output this clones) passes is a hard-coded single-file exclusionEXCLUDE="container-images.md"(tools/check-docs-mdx:30). Prefer option (b): use a splice marker that is NOT an HTML comment outside a code fence (an MDX-safe sentinel, e.g. inside a fenced block or an MDX comment{/* … */}), socoverage-matrix.mdstays inside the MDX gate. Option (a) — refactoring the singleEXCLUDEscalar into a multi-file allowlist and addingcoverage-matrix.md— is acceptable only as a fallback, because each allowlisted file silently loses MDX/Fern-render validation and the allowlist will accrete every future generated page; if (a) is taken, add a test asserting allowlisted files still render under Fern so the carve-out is not an unguarded blind spot. Without one of these, the page trips the MDX gate and Epic AC fix: use workflow_run for PR coverage comments on fork PRs #5 ("passmake qualify") fails.make coverage-docsregenerates;make coverage-checkis an opt-in staleness check parallelingbom-check(explicitly not wired intomake qualify/lint/merge gate)..github/workflows/coverage-matrix-refresh.yaml, weekly clone of the shippedbom-refresh.yaml(cron,peter-evans/create-pull-requeston drift, built-inGITHUB_TOKEN,chore/coverage-refreshbranch,delete-branch: true, explicitdocumentationlabel; area labels (area/docs,area/ci) auto-assign from changed paths vialabeler.yml). It refreshes the structural matrix (which tests exist) weekly; the live "did it pass on hardware" answer is a link into TestGrid, not embedded here (same link-only rule as RQ1).docs/user/coverage-matrix.mdindocs/index.ymlunder User Guide (mirrors ADR-009's registration ofrecipe-health.md,009-recipe-health-tracking.md:409); cross-link fromdocs/user/recipe-health.md(RQ1) anddocs/user/cli-reference.md.fern-docs-ci.yamllychee + MDX-safety run on the newdocs/**page on its introducing PR (hence the splice-marker requirement above).labeler.yml+CODEOWNERS: addtools/coverage/**(CODEOWNERS precedent: ADR-009's plannedtools/health/**entry,009-recipe-health-tracking.md:416).Out of scope. Running the CUJs (the dynamic-clusters epic owns execution; RQ3 reports). A merge gate. Embedding live pass/fail (link to TestGrid). Per-verb unit-coverage % (that's
make test-coverage, a different gate). #1224's per-recipedeclared_coveragecolumn (orthogonal; cross-link only).Key files. New
tools/coverage/(+labeler.yml/CODEOWNERSentries); newdocs/user/coverage-matrix.md;docs/index.yml;docs/user/cli-reference.md;tools/check-docs-mdx(splice-marker-safe rendering, or theEXCLUDEallowlist fallback);Makefile(coverage-docs/coverage-checktargets parallelingbom-docs/bom-check). Signal sources:tests/chainsaw/cli/*,tests/uat/{aws,gcp,azure}/tests/cuj{1,2}-*/,demos/cuj{1,2}-*.md,pkg/cli/*.go. Pattern source:.github/workflows/bom-refresh.yaml,tools/bom.Tests. Generator unit tests: deterministic table output across two runs (byte-compare, not struct DeepEqual); a fixture set of chainsaw/UAT/demo trees produces the expected coverage rows; the verb list is derived from the actual
pkg/clicommand registry (so a new verb without coverage shows up as anot-yet-coveredrow rather than being silently dropped); Azure rows render asstubbed;make coverage-checkflags a deliberately-stale doc. Clears the 75% floor ontools/coveragemeasured withpkg=tools/coverage, and clears the baseline-delta gate (no > 0.5% per-package regression; no new exported func at 0%).Acceptance.
docs/user/coverage-matrix.mdis generated, versioned, registered, and cross-linked (including the explicit distinction from #1224'sdeclared_coveragecolumn); runs onmainweekly via a clone of the BOM loop; passes the MDX gate (via an MDX-safe splice marker, or the guardedcheck-docs-mdxallowlist fallback); never gates merges; honestly reflects covered / not-yet-covered / stubbed; links to TestGrid for live posture rather than embedding it.Child of #1265 · staged from
docs/design/012-recipe-quality-surfaces.md(RQ3).