Skip to content

A composition never promises support past the layers it composes (v0.43.0 plan + REQ-COMPOSEWINDOW-001) - #261

Merged
avrabe merged 5 commits into
mainfrom
feat/composition-support-window
Oct 16, 2026
Merged

avrabe merged 5 commits into
mainfrom
feat/composition-support-window

Conversation

@avrabe

@avrabe avrabe commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #254. Fixes #226.

Two things

1. v0.43.0 planned in rivet. #205 is the release's scope, but four of its items existed only as closed issues pointing at the epic, so rivet release status v0.43.0 showed one requirement for a release of five. Each is now a requirement with failable clauses:

REQ-COMPOSEWINDOW-001 composition window capped at its includes' #254, #226 — this PR
REQ-ENVQUOTE-001 varve env quotes the root it asks you to eval #46 — next PR
REQ-NOPINNOTOOL-001 no pin in scope: which/run/shims refuse like status #198
REQ-MUTANTDEBT-001 declared mutation debt measured in full #181

#112 (root custody hardware) and #97 (spar/WIT/MC-DC in or out) stay with the maintainer as decisions.

2. The cap. varve support-horizon --manifest layer.toml reads each [[include]] from its own realm — manifest by digest, verified against that realm's root, then the line-status install would pick (baseline or later correction, whichever verifies and is newer; extracted as current_line_status so the cache and the cap share one rule). The horizon is the earliest of the channel policy and every include.

  • capping is the default, so an automatic deposit needs no person
  • an include with no stated window refuses (skipping it would make the cap vacuous)
  • --past-includes "<reason>" promises longer, with the reason printed beside the date; an empty reason is refused
  • stdout stays the bare date, so SUPPORT_UNTIL="$(varve support-horizon …)" keeps working

Evidence

Against the live registries, covalent-layers' real layer.toml:

support capped at 2026-10-24 by included layer 2026.09.0 (realm 'pulseengine-wasm'); the rolling policy alone would say 2026-11-02
2026-10-24

— #254's nine days, exactly.

  • 15 unit tests (support.rs) + 2 CLI tests, all // rivet: verifies REQ-COMPOSEWINDOW-001
  • cargo-mutants on the new code: first pass left 2 survivors in the earliest-include comparison (my test listed includes earliest-first); added an order/tie test, re-run 9/9 caught-or-unviable
  • negative control: disabling the include loop in the CLI turns support_horizon_refuses_an_include_from_an_undefined_realm red
  • full workspace: 1168 passed / 0 failed; clippy -D warnings clean

Not in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu

@avrabe
avrabe force-pushed the feat/composition-support-window branch 2 times, most recently from cf96a9b to fde9b03 Compare October 15, 2026 22:48
avrabe and others added 5 commits October 16, 2026 06:48
pointing at the epic, so `rivet release status v0.43.0` reported one
requirement for a release that holds five. Each is now a requirement with
clauses that a test can fail:

  REQ-COMPOSEWINDOW-001  a composition's window is capped at its includes' (#254, #226)
  REQ-ENVQUOTE-001       varve env quotes the store root it asks you to eval (#46)
  REQ-NOPINNOTOOL-001    no pin in scope: which/run/shims refuse as status does (#198)
  REQ-MUTANTDEBT-001     declared mutation debt is measured in full (#181)

maintainer's decisions and stay as such.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
covalent 2026.10.0 signed support until 2026-11-02 over a wasm-layers layer
whose own realm stops vouching for it on 2026-10-24 (#254, #226). The window
came from the composition's channel alone.

`varve support-horizon --manifest layer.toml` now reads every [[include]]
from its own realm: manifest by digest, verified against that realm's root,
then the line-status install would choose (baseline or later correction,
whichever verifies and is newer — extracted as current_line_status so both
readers share one rule). The horizon is the earliest of the policy and
every include. An include that states no window refuses rather than being
skipped. --past-includes "<reason>" promises longer, on the record.

Measured against the live registries with covalent-layers' real layer.toml:
"support capped at 2026-10-24 by included layer 2026.09.0 (realm
'pulseengine-wasm'); the rolling policy alone would say 2026-11-02" — the
nine days of #254, exactly.

REQ-COMPOSEWINDOW-001 clause 4 is corrected: a layers repository adopts
this with one argument, not with nothing; covalent's deposit needs it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
Found by a background security review of the previous commit. The cap
read an include's window through current_line_status, which treats a
failed fetch of the line's published correction as "no correction". A
correction only ever narrows the baseline, so a dropped connection or a
withholding registry made the composition sign the longer, superseded
window: fail-open on exactly the value being capped.

Install keeps that reading on purpose (a best-effort floor, documented),
so the choice is now explicit: Published::BestEffort for the cache,
Published::Required for a reader about to sign. The new test serves a
valid baseline and fails the correction fetch; it failed before this.

Residual, stated: a registry that answers 404 for the correction tag is
indistinguishable from one that never had it. Binding that needs the
realm's signed index to name the status counter; not this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
…xhaust the runner

The varve-core (export) mutation shard died twice on this PR with "the
runner has received a shutdown signal" right after the same mutant:
sdkexport.rs's `i = hit + built.len()` mutated to `hit * built.len()`,
which never advances when the hit is at 0 and appends on every pass — so
it did not merely hang, it grew a buffer until the VM ran out of memory.
On main it happened to reach its 120 s timeout first.

The three copies of that loop (text path, per-string binary path, SYSDIRS
table) are now one replace_all that advances with split_at: no operator
for the mutant to turn. Local cargo-mutants on it and its callers: 65
tested, 0 missed, 0 timeouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
The previous commit's replace_all still let the mutant `find_sub -> Some(0)`
spin forever on an empty rest, appending each pass — the runner ran out of
memory and was shut down right after the baseline (export shard, attempt
on fde9b03). My local check had filtered mutants to replace_all and
relocate_*, so find_sub's own mutants never ran against it.

replace_all now advances only past a match lying wholly inside the
remaining input, and relocate_bytes' outer loop stops on a hit behind its
cursor instead of re-patching the same field until the test times out.
Local cargo-mutants over the whole of sdkexport.rs: the two find_sub
mutants that hung are now caught; on find_sub/relocate_bytes/replace_all,
46 tested, 44 caught, 2 unviable, 0 timeouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
@avrabe
avrabe force-pushed the feat/composition-support-window branch from 48620c3 to fe70259 Compare October 16, 2026 04:48
@avrabe
avrabe merged commit f2cc221 into main Oct 16, 2026
34 checks passed
@avrabe
avrabe deleted the feat/composition-support-window branch October 16, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant