Skip to content

A rolling layer should declare its own staleness: support-until exists, is signed, and is never populated #104

Description

@avrabe

Raised while triaging #102, where gale nearly adopted layer 2026.08.3 — four releases behind, carrying meld 0.42.0 against a hard floor of 0.48.0. Adopting it would not have degraded their build, it would have broken it. Nothing in the layer said so.

What already exists

REQ-KP-001 (verified, v0.5.0) shipped exactly this metadata: known-problems entries, a stated support window, and yank markers — DSSE-signed, attached as OCI referrers so they can be added after deposit without changing the layer digest. varve status already surfaces it:

2026.07.0: 3 known problems, 2 with workarounds; supported until 2028-07

LineStatus.support_until is in the schema (linestatus.rs:52), round-trips, and is covered by tests.

What is actually wrong

Nothing ever sets it. The deposit workflow writes the baseline as:

{"line":"...","counter":N,"issued-at":"..."}

No support-until. So every published layer carries the field as None, and the feature is invisible in practice. This is not a missing capability — it is a capability nobody populates.

The rolling-specific point

For a qualified line, "supported until 2028-07" is the Ferrocene/AdaCore model and means what it says.

For a rolling line it needs a different reading. rolling means current until superseded, so the useful question a consumer asks is "is this still the newest?" — which is an online question, and varve is deliberately offline. The counter gives anti-rollback (refuse an older layer) but says nothing when you adopt a stale one, which is precisely the direction that bit gale.

A short, self-declared window makes staleness offline-checkable: deposit a rolling layer with support-until = issued-at + N days (N on the order of the cut cadence — the scanner now proposes daily, so 30 is generous). The layer then declares its own expiry, no network required, and a consumer evaluating a floor sees it before pinning rather than after a build breaks.

Honest catch — this trusts the local clock

varve avoids trusting clocks elsewhere on purpose (docs root-ceremony: no key expiry; DD-026's spike found wsc's clockless fallback is diagnostic-only). An expiry check consults the system clock, and a rolled-back clock hides the expiry.

That is a strictly weaker threat than layer rollback, which the monotonic counter already prevents cryptographically and without a clock — but the limitation must be stated, not glossed. The failure direction should be: past the window, warn loudly and stay installable, exactly as yank behaves. The consumer owns the freeze decision.

Also: this is CRA-shaped

The Cyber Resilience Act requires a manufacturer to declare a support period for a product. A signed, machine-readable support-until riding beside the artifact is that declaration in the form an auditor can check offline. That argues for populating it on the qualified channel with a real multi-year window, not only for using it as a rolling staleness marker.

Proposed scope

  1. The deposit populates support-until — a short window on rolling, a declared long one on qualified.
  2. varve status already prints it; decide whether install / which warn when past it, and with what exit code (status already exits 3 on YANKED — past-support is a different severity and probably should not reuse 3).
  3. Document the clock dependency in docs threat-model beside the other stated limits.
  4. varve inspect should show it too, since rolling layers lag the toolchain they pin: newest (2026.08.3) carries meld 0.42.0 / witness 0.39.0, four releases behind — adopting the pin would regress a consumer #102's author had to resolve each binary and run --version to check a floor by hand.

Related: #102 (the consumer report), REQ-KP-001 (the shipped mechanism), REQ-ADVISORY-002 (the signed-status channel this rides on).

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