feat: emit coverage summary in coverage.json (v2) and render Markdown report#337
Merged
Conversation
… report
Extends the materializer's coverage artefact with a deterministic
summary block (total spec ops, emitted feature specs, suppressed by
template, variant specs, lifecycle specs, unmapped operations, per-
template aggregates) and adds 'npm run coverage:report' which renders
that block as Markdown by default ('--format=json' passthrough).
The summary is built once at emission time and embedded in
coverage.json so the JSON artefact and the rendered report agree by
construction — the renderer is a pure transform and never re-walks
the planner outputs or the bundled spec.
e90cb93 to
24f0b40
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the materializer’s coverage.json artefact to a v2 shape that includes a deterministic summary block (computed at emission time from the bundled OpenAPI spec + emission/suppression data) and adds a CLI/reporting script to render that summary as a Markdown coverage report.
Changes:
- Add
materializer/src/coverageSummary.tsto load spec operationIds and aggregate deterministic coverage totals + per-template breakdowns. - Update
materializer/src/index.tsto emitcoverage.jsonv2 (config,emitter,summary) while preserving existingsuppressedOpIds/entries. - Add
scripts/render-coverage-report.ts+npm run coverage:reportto render Markdown (default) or re-emit JSON, with unit tests intests/codegen/coverage-summary.test.ts.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/codegen/coverage-summary.test.ts | Adds unit tests for summary reconciliation/sorting and for deterministic Markdown rendering + v1 rejection. |
| scripts/render-coverage-report.ts | New CLI/script to read v2 coverage artefacts and render a Markdown report (or pass through JSON). |
| package.json | Adds coverage:report script entry. |
| materializer/src/index.ts | Tracks emitted feature opIds and writes coverage.json v2 with embedded summary. |
| materializer/src/coverageSummary.ts | New aggregation + spec operationId loader used to build the embedded summary block. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…l and dedupe spec opIds Two Copilot review comments on PR #337: 1. render-coverage-report.ts: findRepoRoot() walked up from cwd looking for any package.json, but this is a monorepo with nested workspace package.json files (materializer/, path-analyser/, …) so running the script from a workspace subdir would stop at the wrong directory and break getActiveConfigName() / getPlaywrightSuiteDir() lookups. Drop findRepoRoot() and derive REPO_ROOT from import.meta.url instead — matches the convention used by sibling scripts (export-ontology.ts, build-ontology.ts, run-pw-request-validation.ts). 2. coverageSummary.ts: loadSpecOperationIds() returned ids.sort() without deduping. OpenAPI does not technically forbid duplicate operationIds; if the bundled spec ever contained any, totalSpecOperations and unmappedOperations would inflate and the reconciliation math would silently disagree with the rest of the repo (configs/camunda-oca/regression-invariants.test.ts already treats spec opIds as a Set). Collect into a Set and return the sorted unique list. Add tests/codegen/coverage-summary.test.ts coverage for both branches of loadSpecOperationIds (dedupe + ENOENT), with a class-scoped assertion that ids.length === new Set(ids).size for any spec.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on top of #336. Once #336 merges, this PR will auto-retarget to
main.What
Extends the materializer's coverage artefact with a deterministic
summaryblock, and adds annpm run coverage:reportscript that renders it as Markdown by default (with--format=jsonpassthrough).Why
The numbers behind "117 emitted feature specs / 73 suppressed-by-template / 190 spec operations / 70 variants / 26 lifecycle" were previously only derivable by hand-walking the planner outputs. Embedding a single source of truth in
coverage.json(built once at emission time) means the JSON artefact and any rendered report agree by construction, and downstream tools can read a fixed shape instead of re-implementing the reconciliation.Changes
materializer/src/coverageSummary.ts(new) — pure aggregation:loadSpecOperationIds(specBundleDir)walksspec.paths.{path}.{method}.operationIdfrom the bundled OpenAPI spec.buildCoverageSummary({ allSpecOpIds, emittedFeatureOpIds, suppressedOpIds, entries, variantSpecs, lifecycleSpecs })returns the summary block: totals, unmapped (sorted), per-template aggregates (sorted by name; specs / unique ops / entries / invoke steps / observe steps).materializer/src/index.ts— tracksemittedFeatureOpIdswhile iterating the--allfeature loop and writescoverage.jsonv2 with new top-levelconfig,emitter,summaryfields (existingsuppressedOpIds/entrieskept verbatim, so L3 invariants remain version-agnostic).scripts/render-coverage-report.ts(new) +npm run coverage:report— pure transform over the embeddedsummaryblock. Markdown by default;--format=jsonpassthrough;--input/--outfor arbitrary artefacts. Throws on v1 input rather than guessing.tests/codegen/coverage-summary.test.ts— 6 tests: reconciliation math (total = emitted + suppressed + unmapped), per-template alphabetical sort, unmapped sort, full Markdown layout against a hand-crafted fixture matching the production figures, empty-perTemplate branch, v1 artefact rejection.Sample output
Validation
configs/camunda-oca/regression-invariants.test.ts) still green — they readsuppressedOpIds/entries.emittedSpec, both unchanged.