Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
*An advisory arrives as a prepared line-status, a composition's support is capped
by what it composes, and two independent reviews found what this release fixes.*

`rivet release status v0.43.0`: REQ-ENVQUOTE-001, REQ-NOPINNOTOOL-001 and
REQ-SBOMFIELDS-001 are **verified**. REQ-ADVISORYWATCH-001,
REQ-COMPOSEWINDOW-001 and REQ-MUTANTDEBT-001 ship **implemented**, not verified,
by the maintainer's decision: each has a clause that can only be shown after this
release, or open work moved to v0.44.0 (see "Not verified in this release").
`rivet release status v0.43.0`: REQ-ENVQUOTE-001, REQ-NOPINNOTOOL-001,
REQ-SBOMFIELDS-001 and REQ-MUTANTDEBT-001 are **verified**.
REQ-ADVISORYWATCH-001 and REQ-COMPOSEWINDOW-001 ship **implemented**, not
verified, by the maintainer's decision: each has a clause that can only be shown
after this release, with the open work moved to v0.44.0 (see "Not verified in
this release").

### Upgrading: behaviour that changes

Expand Down Expand Up @@ -40,6 +41,16 @@ release, or open work moved to v0.44.0 (see "Not verified in this release").
refused. See "Upgrading".
* rustls-webpki 0.103.16 and webpki-roots 1.0.10, for RUSTSEC-2026-0381 and
RUSTSEC-2026-0382 (distrusted emSign intermediates).
* `ureq` is capped below 3.5: ureq 3.5.0 broke `wsc` 0.11.0, so a build
without varve's lockfile (`cargo install varve` without `--locked`) failed to
compile (pulseengine/sigil#319).

### The deposit refuses a malformed tool entry

Two `TARBALL_TOOLS` entries fused by a missing space used to parse as one
plausible tool and silently drop the other (#267). One validator now decides an
entry's shape, used by the deposit before it fetches anything and by its system
test; a negative control fuses two real entries and requires both to refuse.

### An advisory arrives as a prepared line-status

Expand Down Expand Up @@ -83,8 +94,9 @@ The nightly mutation run shards the `[not-yet]` files of `mutation-scope.toml`
(read at run time, never copied into the workflow) into jobs that finish inside
the cap. A shard with no summary, or one that tested a different number of
mutants than planned, is INCOMPLETE and turns the run red; it is never a zero.
The first full measurement: 939 mutants across 21 files, 111 surviving, the debt
that was declared and is now counted.
The first scheduled run on main (run 39736152885) completed all four shards
inside the cap, each testing exactly its planned count: 945 mutants across 21
files, 111 surviving. That is the debt that was declared, now counted.

### Not verified in this release

Expand All @@ -95,8 +107,6 @@ that was declared and is now counted.
* **REQ-COMPOSEWINDOW-001.** The cap holds for direct includes only. An expired
include is not refused, the override reason is not signed, and no layers
repository passes `--manifest` yet. Moved to REQ-COMPOSEWINDOW-002.
* **REQ-MUTANTDEBT-001.** It is verified once a scheduled nightly run of the
merged workflow completes on main; the evidence so far is one dispatch run.
* **#277:** a binary changed in the store after install still runs, for every
pin, until `varve verify` is run. It is a design question, not a regression.

Expand Down
38 changes: 37 additions & 1 deletion artifacts/requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5055,7 +5055,7 @@ artifacts:
- id: REQ-MUTANTDEBT-001
type: requirement
title: Declared mutation debt is measured in full, not cut off at a time cap
status: implemented
status: verified
release: v0.43.0
description: "varve#181: the nightly advisory mutation run is cancelled at its 90-minute cap every night after ~32% of 2,675 mutants, so 11 of the 22 not-yet files are never reached. The instrument that makes declared debt counted rather than hidden counts half of it. Clauses: (1) Every not-yet file in mutation-scope.toml shall be tested by some scheduled run that completes. (2) A run that does not complete shall be reported as incomplete, never as a measurement."
provenance:
Expand Down Expand Up @@ -5104,3 +5104,39 @@ artifacts:
created-by: ai
model: claude-opus-5-5
timestamp: 2026-10-21T16:52:38Z

- id: REQ-ROLLBACK-002
type: requirement
title: A deliberate, digest-pinned layer that its line still supports installs on any machine, whatever that machine has seen
status: approved
release: v0.44.0
description: "varve#256 (gale, reproduced on one machine and on ~11 shared CI runners; gale's CI red since 2026-10-08): the anti-rollback high-water mark is per MACHINE, but a pin is per PROJECT. Once any project on a shared runner installs a newer layer of a line, every other project's older pin on that line is refused as a rollback, although varve status reports it unyanked and in support. Refusing is correct against a per-machine baseline; the scope is what is wrong. REQ-ROLLBACK-001 protects against a stale validly-signed layer being PASSED OFF as current, and a digest written into a reviewed varve.toml is not that. Clauses (to be decided, see the issue's three remedies): (1) A layer selected by digest in the project's pin, which the line's signed line-status reports as neither yanked nor out of support, shall install regardless of the machine's high-water mark, and the install shall say that it did so and why. (2) Resolution by NAME, with no digest, keeps today's refusal, because that is the replay REQ-ROLLBACK-001 exists for. (3) The high-water mark shall still advance from what is installed, so the protection for name-resolved pins is not weakened. Kill-criterion from the issue: a layer varve status reports unyanked and in support cannot be installed on a machine that has seen a newer layer on the same line. . DECIDED 2026-10-21 by the maintainer: digest-as-consent (clauses 1-3), over a per-project baseline (a fresh checkout has none and would trust its first sight) and an --allow-stale flag (copied into every CI config until it means nothing)."
links:
- type: derives-from
target: REQ-ROLLBACK-001
provenance:
created-by: ai
model: claude-opus-5-5
timestamp: 2026-10-21T19:12:07Z

- id: REQ-OWNYAML-001
type: requirement
title: varve reads the inputs whose shape it defines through rivet's owned YAML stack
status: approved
description: "varve#272, org policy (maintainer, 2026-10-13): a repository reads its OWN inputs through rivet-yaml; other formats stay only for exports and formats others define. varve's own inputs are all TOML today: varve.toml, varve-realms.toml, layer.toml, deposit-spec.toml, the previous-deposit state, mutation-scope.toml, and JSON state files. UNDECIDED, and the reason this is proposed, not approved: varve.toml and varve-realms.toml are files USERS write and commit, so moving them to YAML is a breaking change to every pinned project and every realm. Decide: migrate the user-facing files (with a transition that reads both), only the internal ones (deposit-spec, state), or keep TOML for user-facing inputs as a recorded exception to the policy. . DECIDED 2026-10-21 by the maintainer: everything, with a transition. Clauses: (1) varve.toml, varve-realms.toml, layer.toml and deposit-spec.toml shall be read as YAML through rivet-yaml, and for a transition of at least one release the TOML form is still read, with a deprecation note naming the YAML equivalent. (2) Internal state (previous-deposit state, mutation-scope, JSON state files) moves without a transition. (3) The removal of TOML is announced in the release before it happens. (4) A file present in both forms is refused rather than one silently preferred."
provenance:
created-by: ai
model: claude-opus-5-5
timestamp: 2026-10-21T19:12:07Z
release: v0.45.0

- id: REQ-SHIMFALLBACK-001
type: requirement
title: A shim asked for a tool the pinned layer does not carry says what it can do instead
status: approved
description: "varve#273 (maintainer): in a pinned project, a shim for a tool the layer does not carry refuses, so a tool installed locally cannot be used without editing PATH, which then shadows the layer. Asked for: fall through to the tool on PATH with a warning that it ran outside the layer; and where nothing is on PATH but another installed layer carries it, list the options. UNDECIDED, because it cuts against a stated property: a shim that falls back to an ambient binary is the mixed-toolchain hazard varve exists to close, and REQ-SHADOW-001 reports exactly that shadowing as a defect. Decide: fall-through with a warning (per project opt-in, or default), list-only (refuse but name what is on PATH and which layers carry it), or keep the refusal. . DECIDED 2026-10-21 by the maintainer: refuse, but list the options. Clauses: (1) A shim for a tool the pinned layer does not carry keeps refusing, and no ambient binary ever runs through a shim. (2) The refusal names the matching executable on PATH (outside the shim directory) and the exact command that runs it directly, and every installed layer that carries the tool, with the pin change that would select it. (3) The refusal still exits 1."
provenance:
created-by: ai
model: claude-opus-5-5
timestamp: 2026-10-21T19:12:07Z
release: v0.44.0
8 changes: 5 additions & 3 deletions artifacts/verification.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3429,11 +3429,11 @@ artifacts:
- id: VER-MUTANTDEBT-001
type: verification
title: Declared mutation debt is sharded from mutation-scope.toml and an unfinished shard reports INCOMPLETE, never zero
status: draft
status: verified
release: v0.43.0
fields:
method: test
baseline: "Measured 2026-10-21 with cargo mutants --list: the 21 current not-yet files hold 939 mutants and pack into 4 shards of 314, 300, 298 and 27 (the whole workspace was 2,675 in one job). An earlier version of this record said 850, which disagrees with its own shard sizes (they sum to 939) and with the run below. Falsified by negative control: a mutants.log truncated before its summary makes 'mutant-debt-plan.py report' exit 1 and print INCOMPLETE, a full log exits 0; a shard whose artifact is missing is INCOMPLETE too; and a log whose summary names a different number of mutants than the shard was planned with (fewer, or more) is INCOMPLETE too, with both numbers shown. The workflow has run on GitHub once, by workflow_dispatch: run 39541389293 on pulseengine/varve completed all 4 shards (939 mutants over 21 files, 111 missed, longest shard 66 minutes) and its report job printed MEASURED for all four. That run predates the planned-versus-tested comparison, so it did not exercise it. It measured about 4.75 mutants per minute (shards of 314, 300, 298 and 27 mutants took 66, 61, 59 and 7 minutes), not the ~7 the plan assumed; a 300-mutant target leaves about 24 minutes under the 90-minute cap. No SCHEDULED run of the merged workflow has completed yet, so REQ-MUTANTDEBT-001 clause 1, which asks for a scheduled run that completes, is not yet evidenced by a scheduled run."
baseline: "Measured 2026-10-21 with cargo mutants --list: the 21 current not-yet files hold 939 mutants and pack into 4 shards of 314, 300, 298 and 27 (the whole workspace was 2,675 in one job). An earlier version of this record said 850, which disagrees with its own shard sizes (they sum to 939) and with the run below. Falsified by negative control: a mutants.log truncated before its summary makes 'mutant-debt-plan.py report' exit 1 and print INCOMPLETE, a full log exits 0; a shard whose artifact is missing is INCOMPLETE too; and a log whose summary names a different number of mutants than the shard was planned with (fewer, or more) is INCOMPLETE too, with both numbers shown. The workflow has run on GitHub once, by workflow_dispatch: run 39541389293 on pulseengine/varve completed all 4 shards (939 mutants over 21 files, 111 missed, longest shard 66 minutes) and its report job printed MEASURED for all four. That run predates the planned-versus-tested comparison, so it did not exercise it. It measured about 4.75 mutants per minute (shards of 314, 300, 298 and 27 mutants took 66, 61, 59 and 7 minutes), not the ~7 the plan assumed; a 300-mutant target leaves about 24 minutes under the 90-minute cap. No SCHEDULED run of the merged workflow has completed yet, so REQ-MUTANTDEBT-001 clause 1, which asks for a scheduled run that completes, is not yet evidenced by a scheduled run. SCHEDULED RUN on main, 2026-10-22: run 39736152885 at e7019ad (the v0.43.0 release commit) completed all 4 shards inside the 90-minute cap (58/60/60/7 min). Each shard tested exactly its planned count (314/300/299/32), the report job on the self-hosted pool read all four MEASURED, 945 mutants across 21 files, 111 missed, 5 timed out, and the shards with survivors stayed green as an advisory run should. Clause 1 (every not-yet file tested by a scheduled run that completes) is met."
steps: python3 -m unittest discover -s tools -p 'test_*.py'
links:
- type: verifies
Expand All @@ -3450,7 +3450,7 @@ artifacts:
release: v0.43.0
description: "The recorded independent review for v0.43.0 (REQ-INDEP-001, DD-019). Advisory at v0.x: a missing or dissenting review is visible, not blocking. Both reviews dissented, and the fixes landed before any requirement was promoted."
fields:
baseline: "Two independent clean-room reviews (fresh context, refute-framed) of the v0.43.0 scope, 2026-10-21. REVIEW 1 at 8a3c26e: DISSENT on all six requirements. It reproduced a shell injection through varve.toml's [[export]] out (a newline ended the comment varve env prints, and eval ran the rest), and realmless dispatch with no trust root while status refused. It also found REQ-COMPOSEWINDOW-001's clauses 1-3 lost at merge, no end-to-end test of the cap, payloads the advisory watch dropped silently, the SBOM supplier ignoring the proof signer, the SBOM author depending on a local realm alias, and the mutation report not comparing tested against planned. All were fixed test-first in #278. REVIEW 2 at the #278 branch: no requirement REFUTED; four PARTIAL. It reproduced that ANY well-formed VARVE_TRUST_ROOT let a realmless pin dispatch a layer verify refused, and that shim install printed a dot-source line with command substitution live. Both were fixed test-first and negative-controlled in #278 (the layer's retained envelope must verify against the root in scope; the printed line is quoted literally). It also found fish never executed, so a CI job now installs fish and runs the round trip, failing rather than skipping when fish is absent. Outcome: REQ-ENVQUOTE-001, REQ-NOPINNOTOOL-001 and REQ-SBOMFIELDS-001 are verified, with clause amendments recorded on each artifact. REQ-ADVISORYWATCH-001 and REQ-COMPOSEWINDOW-001 stay implemented, their open clauses moved to REQ-ADVISORYWATCH-002 and REQ-COMPOSEWINDOW-002 (v0.44.0), by the maintainer's decision. REQ-MUTANTDEBT-001 waits for a scheduled nightly run on main. Tampering after install, which affects every pin, is #277."
baseline: "Two independent clean-room reviews (fresh context, refute-framed) of the v0.43.0 scope, 2026-10-21. REVIEW 1 at 8a3c26e: DISSENT on all six requirements. It reproduced a shell injection through varve.toml's [[export]] out (a newline ended the comment varve env prints, and eval ran the rest), and realmless dispatch with no trust root while status refused. It also found REQ-COMPOSEWINDOW-001's clauses 1-3 lost at merge, no end-to-end test of the cap, payloads the advisory watch dropped silently, the SBOM supplier ignoring the proof signer, the SBOM author depending on a local realm alias, and the mutation report not comparing tested against planned. All were fixed test-first in #278. REVIEW 2 at the #278 branch: no requirement REFUTED; four PARTIAL. It reproduced that ANY well-formed VARVE_TRUST_ROOT let a realmless pin dispatch a layer verify refused, and that shim install printed a dot-source line with command substitution live. Both were fixed test-first and negative-controlled in #278 (the layer's retained envelope must verify against the root in scope; the printed line is quoted literally). It also found fish never executed, so a CI job now installs fish and runs the round trip, failing rather than skipping when fish is absent. Outcome: REQ-ENVQUOTE-001, REQ-NOPINNOTOOL-001 and REQ-SBOMFIELDS-001 are verified, with clause amendments recorded on each artifact. REQ-ADVISORYWATCH-001 and REQ-COMPOSEWINDOW-001 stay implemented, their open clauses moved to REQ-ADVISORYWATCH-002 and REQ-COMPOSEWINDOW-002 (v0.44.0), by the maintainer's decision. REQ-MUTANTDEBT-001 waits for a scheduled nightly run on main. Tampering after install, which affects every pin, is #277. ADDENDUM 2026-10-22: both reviews' only open point on REQ-MUTANTDEBT-001 was clause 1's missing scheduled run. Scheduled run 39736152885 on main completed all four shards, each at its planned count, so it is verified and linked here."
method: review
steps: cargo test --workspace; VARVE_REQUIRE_FISH=1 cargo test -p varve --test cli -- --exact env_quotes_a_hostile_root_for_fish_so_eval_cannot_run_embedded_commands (CI job 'varve env round trip in fish')
links:
Expand All @@ -3460,6 +3460,8 @@ artifacts:
target: REQ-NOPINNOTOOL-001
- type: verifies
target: REQ-SBOMFIELDS-001
- type: verifies
target: REQ-MUTANTDEBT-001
provenance:
created-by: ai
model: claude-opus-5-5
Expand Down
13 changes: 13 additions & 0 deletions tools/build-deposit-spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ WORK="${1:?usage: build-deposit-spec.sh <workdir>}"

PLATFORMS="${PLATFORMS:-aarch64-apple-darwin x86_64-apple-darwin aarch64-unknown-linux-gnu x86_64-unknown-linux-gnu}"

# Every TARBALL_TOOLS entry's shape, checked before anything is fetched and by
# the same function the systest's live-pin check uses (varve#267): a fused
# entry otherwise parses as a plausible first tool and silently drops the
# second. Sourced before the `cd` below, while $0 still resolves.
. "$(dirname "$0")/tarball-entry.sh"
for entry in $TARBALL_TOOLS; do
fault="$(tarball_entry_fault "$entry")"
if [ -n "$fault" ]; then
echo "::error::TARBALL_TOOLS entry '$entry' $fault"
exit 1
fi
done

mkdir -p "$WORK"
WORK="$(cd "$WORK" && pwd)"
cd "$WORK"
Expand Down
Loading
Loading