rivet coverage renders a rule whose population is empty as 100.0%, in both the per-rule table and the V-closure summary. On a project that adopts a preset covering more process levels than it models, that turns "we do not do this" into a green row.
Measured on pulseengine/scry (schemas: common, dev, research, research-ext, safety-case, aspice@0.2.0)
Rule Source Type Covered Total %
swe2-allocated-from-swe1 sw-arch-component 0 0 100.0%
swe3-refines-swe2 sw-detail-design 0 0 100.0%
swe4-verifies-swe3 unit-verification 0 0 100.0%
swe3-has-verification sw-detail-design 0 0 100.0%
...
V-closure: sw-detail-design (all 2 rules) 100.0% [0/0]
Four of seventeen rules, plus one V-closure line. scry has zero artifacts of those three types (and zero textual occurrences of the type names) — it deliberately does not model SWE.2 / SWE.3 / SWE.4, because its design intent lives in a parallel dev spine and authoring a unit-verification artifact per absent detail-design element would be fabricated traceability.
The aggregate is already correct — this is a rendering issue
overall reports checks_covered: 119, checks_total: 135, percentage: 88.1 — an empty rule contributes 0 to both numerator and denominator, so it does not inflate the weighted figure. Verified in both directions: --fail-under 88.2 exits 1, --fail-under 88.0 exits 0.
So the number a gate keys off is honest. What misleads is the row-by-row read, which is how a report gets skimmed and how an assessor checks a specific process area.
Suggestions, roughly in order of preference
- Render
n/a (or —) instead of 100.0% when total == 0, in the table and in V-closure. In JSON, percentage: null alongside the existing total: 0 would let consumers distinguish the cases without string parsing.
- Let a project declare which preset rules it does not model, so the rule is omitted rather than rendered. Today the
aspice preset is embedded and there appears to be no way to subset its rules — a project that adopts it for SWE.1/SWE.6 necessarily inherits SWE.2/3/4 rows it can never satisfy.
- At minimum, mark such rows visually (e.g. a trailing
(no population)).
(1) alone would resolve the misleading read; (2) is the more complete fix if rule subsetting is something you want to support generally.
Workaround in use
scry now declares its unmodelled levels in a checked-in file and gates on it in CI, failing both when an empty population is undeclared and when a declaration goes stale. That keeps the project honest but does not change what rivet coverage prints, and every other ASPICE-preset project has the same four rows.
Same family as the --explain reporting I raised in #852 — a true statement that reads as the wrong conclusion.
rivet coveragerenders a rule whose population is empty as 100.0%, in both the per-rule table and the V-closure summary. On a project that adopts a preset covering more process levels than it models, that turns "we do not do this" into a green row.Measured on pulseengine/scry (schemas: common, dev, research, research-ext, safety-case, aspice@0.2.0)
Four of seventeen rules, plus one V-closure line. scry has zero artifacts of those three types (and zero textual occurrences of the type names) — it deliberately does not model SWE.2 / SWE.3 / SWE.4, because its design intent lives in a parallel dev spine and authoring a unit-verification artifact per absent detail-design element would be fabricated traceability.
The aggregate is already correct — this is a rendering issue
overallreportschecks_covered: 119, checks_total: 135, percentage: 88.1— an empty rule contributes 0 to both numerator and denominator, so it does not inflate the weighted figure. Verified in both directions:--fail-under 88.2exits 1,--fail-under 88.0exits 0.So the number a gate keys off is honest. What misleads is the row-by-row read, which is how a report gets skimmed and how an assessor checks a specific process area.
Suggestions, roughly in order of preference
n/a(or—) instead of100.0%whentotal == 0, in the table and in V-closure. In JSON,percentage: nullalongside the existingtotal: 0would let consumers distinguish the cases without string parsing.aspicepreset is embedded and there appears to be no way to subset its rules — a project that adopts it for SWE.1/SWE.6 necessarily inherits SWE.2/3/4 rows it can never satisfy.(no population)).(1) alone would resolve the misleading read; (2) is the more complete fix if rule subsetting is something you want to support generally.
Workaround in use
scry now declares its unmodelled levels in a checked-in file and gates on it in CI, failing both when an empty population is undeclared and when a declaration goes stale. That keeps the project honest but does not change what
rivet coverageprints, and every other ASPICE-preset project has the same four rows.Same family as the
--explainreporting I raised in #852 — a true statement that reads as the wrong conclusion.