Skip to content

Commit f87e154

Browse files
authored
Merge pull request #663 from pulseengine/docs/issue-612-require-coverage-semantics
docs(release): explain `require: coverage` semantics — coverage-rules ≠ every V-level (#612)
2 parents 8f9fac6 + 14ce9cc commit f87e154

2 files changed

Lines changed: 161 additions & 2 deletions

File tree

docs/release-status.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
---
2+
id: DOC-RELEASE-STATUS
3+
title: "Release readiness — rivet release status"
4+
type: reference
5+
status: current
6+
tags: [release, cuttability, coverage, aspice, v-model, reference]
7+
---
8+
9+
# Release readiness — `rivet release status`
10+
11+
`rivet release status <version>` is the cuttability gate for a release
12+
scope. It reports a per-status burn-down for every artifact carrying
13+
`release: <version>` and exits non-zero when the scope is not release-ready
14+
— the CI-gating contract.
15+
16+
Two `rivet.yaml` knobs (REQ-240, [#612]) widen what counts as ready so
17+
V-model / ASPICE projects — which verify via links, not a status flip —
18+
can green the gate. This page pins the semantics of those knobs, in
19+
particular the subtle one: `require: coverage` greens when the configured
20+
**coverage-rules are satisfied**, which is not the same thing as "every
21+
verification level is present".
22+
23+
## The knobs
24+
25+
`rivet.yaml`:
26+
27+
```yaml
28+
release:
29+
ready-when: [approved] # extend the ready status set
30+
require: coverage # OR: derive readiness from validate V-closure
31+
```
32+
33+
### `ready-when: [<status>, ...]`
34+
35+
Extends the release-ready status set beyond the built-in
36+
`verified` / `accepted`. Purely additive — the built-ins still count. Use
37+
this when the project's own lifecycle terminal is a status string other
38+
than the built-ins (e.g. an `approved` sign-off).
39+
40+
### `require: coverage`
41+
42+
Also counts an artifact ready when every applicable **validate coverage
43+
rule** for its type is satisfied, regardless of the status string. Purely
44+
additive: a `verified` / `accepted` / `ready-when` artifact still counts,
45+
so switching to `coverage` never makes a release *less* cuttable.
46+
47+
This is the escape hatch for V-model / ASPICE projects that carry
48+
requirements at a terminal status like `approved` and express verification
49+
through links (`verified-by` / `verifies`) rather than a further status
50+
flip.
51+
52+
## The precision note
53+
54+
`require: coverage` reads whatever coverage-rules the project's schema
55+
declares. It is **not** a hard-coded "every V level is present" gate. What
56+
counts as V-closed depends entirely on how the schema's coverage-rules are
57+
written.
58+
59+
The ASPICE built-ins ship a permissive shape. `swe1-has-verification` is
60+
declared as:
61+
62+
> An `sw-req` at a lifecycle status of `implemented` or later is verified
63+
> by **≥ 1** of `{sw-verification, unit-verification, sw-integration-verification}`.
64+
> **severity: warning**.
65+
66+
So a requirement with **one** verification measure linked (e.g. formal
67+
verification via `sw-verification`) passes the rule and counts as ready
68+
under `require: coverage`, even though the granular `rivet validate`
69+
breakdown for the same requirement will still list `missing:
70+
unit-verification, sw-integration-verification` at info severity.
71+
72+
Both outputs are internally correct. They answer different questions:
73+
74+
| View | Question it answers |
75+
|----------------------------|------------------------------------------------|
76+
| `rivet release status` under `require: coverage` | Does the schema's `swe1-has-verification` rule pass? (≥ 1 measure) |
77+
| `rivet validate` granular breakdown | Is every declared verification level present? (per-level) |
78+
79+
The `release status` verdict follows the rule literally. If a green
80+
verdict means "≥ 1 measure exists somewhere" and the project needs it to
81+
mean "every level is closed", the schema must be tightened, not the
82+
release-status command.
83+
84+
### Concrete example
85+
86+
A project runs `rivet release status v0.1.0` on eleven `sw-req` artifacts
87+
under an aspice-flavoured schema. Each requirement carries a formal
88+
verification link (`sw-verification`) plus a system-level verification
89+
link but no unit / integration verification.
90+
91+
| `rivet.yaml` `release:` config | Verdict |
92+
|--------------------------------|------------------|
93+
| *(none — default status-mode)* | ✗ NOT cuttable — no artifact is `verified`/`accepted` |
94+
| `ready-when: [approved]` | ✓ Cuttable — every `sw-req` is `approved` |
95+
| `require: coverage` | ✓ Cuttable — the ≥ 1-measure rule passes |
96+
97+
Under `require: coverage` the gate greens because
98+
`swe1-has-verification` fires only when *zero* verification measures are
99+
linked. `rivet validate` on the same repo still reports the per-level
100+
gaps as info because those are a separate check.
101+
102+
## When "≥ 1 measure" isn't strict enough
103+
104+
An ASIL-D (or DAL-A, or IEC 62304 Class C) project wanting the gate to
105+
mean **full per-level V-closure** — every declared verification level
106+
present, not just at least one — should express that in the schema's
107+
coverage-rules, not by reinterpreting the command. Two options that keep
108+
the command's contract:
109+
110+
1. **Split the built-in rule.** Replace the single ≥ 1-of-many rule with
111+
per-level rules — one for `sw-verification`, one for
112+
`unit-verification`, one for `sw-integration-verification` — each with
113+
`severity: error`. `require: coverage` then greens only when every
114+
level's rule passes; a missing unit-verification blocks the gate the
115+
same way a missing formal verification would.
116+
2. **Author the coverage-rules from scratch.** For a project that already
117+
diverges from the aspice built-ins, declare a project-specific
118+
coverage-rule per verification level at `severity: error`. Same effect.
119+
120+
Both keep readiness derived from the schema — the intended shape — rather
121+
than embedding "every level" into the tool. Projects that keep the ≥ 1
122+
warning-severity rule opt in to that meaning of green.
123+
124+
## Backwards compatibility
125+
126+
The default mode is unchanged: no `release:` block in `rivet.yaml` means
127+
`rivet release status` gates on `status ∈ {verified, accepted}` exactly
128+
as before. The knobs are strictly additive; a project can adopt
129+
`ready-when` and `require: coverage` without ever making a previously
130+
cuttable release non-cuttable.
131+
132+
The `--format json` output continues to expose `cuttable` as a boolean
133+
under a stable key; the exit code stays consistent with that verdict
134+
(non-zero when `cuttable == false`) so the CI-gating contract is
135+
untouched.
136+
137+
## See also
138+
139+
- [`docs/schemas.md`](schemas.md) — coverage-rule authoring shape.
140+
- [`docs/verification.md`](verification.md) — how verification maps to
141+
ASPICE SWE.4 / SWE.5 / SWE.6.
142+
- [REQ-240](../artifacts/requirements.yaml) — the requirement anchoring
143+
the `ready-when` + `require: coverage` widening.
144+
- [#612](https://github.com/pulseengine/rivet/issues/612) — the original
145+
friction report against a link-verification project (gale).
146+
147+
[#612]: https://github.com/pulseengine/rivet/issues/612

rivet-cli/src/main.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,8 +1529,20 @@ enum BaselineAction {
15291529
enum ReleaseAction {
15301530
/// Readiness burn-down for a release (REQ-233, #516): per-status counts of
15311531
/// the artifacts scoped to `release: <version>`, plus the set that is not
1532-
/// yet `verified`/`accepted`. The release is cuttable when that set is
1533-
/// empty. Exits non-zero when not cuttable (so CI can gate on it).
1532+
/// yet release-ready. The release is cuttable when that set is empty.
1533+
/// Exits non-zero when not cuttable (so CI can gate on it).
1534+
///
1535+
/// By default an artifact is release-ready at `status ∈
1536+
/// {verified, accepted}`. `rivet.yaml`'s `release:` block widens that:
1537+
/// `ready-when: [<status>...]` extends the ready status set;
1538+
/// `require: coverage` (REQ-240, #612) ALSO counts an artifact ready
1539+
/// when every applicable validate coverage rule passes for its type —
1540+
/// the escape hatch for V-model / ASPICE projects that verify via
1541+
/// links rather than a status flip. `require: coverage` greens when
1542+
/// the configured coverage-rules pass, which is NOT the same as
1543+
/// "every verification level present" — see `docs/release-status.md`
1544+
/// for the precision note and how to tighten the schema when a
1545+
/// stricter meaning is required.
15341546
Status {
15351547
/// Release version, e.g. v0.22.0
15361548
version: String,

0 commit comments

Comments
 (0)