Skip to content

coverage: a rule with an empty population renders as 100.0%, so an unmodelled level reads as a satisfied one #871

Description

@avrabe

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

  1. 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.
  2. 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.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions