Skip to content

feat(release): carried-forward retag — unchanged images keep their digests - #307

Merged
elronbandel merged 2 commits into
mainfrom
elron/carried-forward-retag
Aug 10, 2026
Merged

feat(release): carried-forward retag — unchanged images keep their digests#307
elronbandel merged 2 commits into
mainfrom
elron/carried-forward-retag

Conversation

@elronbandel

Copy link
Copy Markdown
Contributor

Resolves #306. Rung 5 — the final rung of #292's migration path (rules #293, primitive #298, stamping #303, freshness #305).

What

The release acts on freshness: an image whose inputs are unchanged from the prior release is retagged from that release's digest instead of rebuilt (delivery rule 13). Same bits, new tag; provenance/SBOM ride along via the same imagetools create manifest copy the :latest promotion already uses.

Site Behavior
bases The whole-set FROZEN sentinel becomes a per-target judgment: fresh → retag, stale → rebuild (the bake covers only the stale subset). Side effect: stale bases now rebuild on dev dispatches too, eliminating the stamped-label skew frozen bases could cause.
leaves Check + retag before the bake. Ref derived from the graph context column — dotted models (gpt-5.4) are judged correctly, which the old skip_published mapping never matched.
per-task Per-item check keyed on the task-mixed hash.
combos eval and eval-standalone judge independently — a stale standalone rebuilds while the lean combo carries forward.
  • fleet-status.sh check <ref> <hash> (new one-ref form, exit 0 = fresh) keeps the label-read logic in a single home; verified live against real GHCR (fresh→0, stale→1, absent→1).
  • skip_published deleted — subsumed with hash-correct semantics (tag existence said nothing about content).
  • force_rebuild input added — upstream base/package drift is invisible to the input hash, so CVE refreshes force-rebuild (principle 9 classes them as patch releases). The CVE gate scans whatever :TAG points to, carried or fresh (rule 15 gate parity).
  • docs/concepts/release-freshness.md — what a version tag now means (a coherent input set, not a build timestamp), how to audit freshness, when to force (docs rules 7/13/15; indexed).

Comparison baseline

:latest (per-arch :latest-<arch> for the per-arch jobs) — the promoted prior release, gated by the CVE scan before promotion. On a :latest dispatch a fresh image is simply kept; on a tagged release it is retagged vNEW ← latest.

Verification

  • check subcommand exercised against the real registry (live fresh on the images stamped by run 31318078405, correct non-zero on stale/absent) and by the stubbed-docker static suite (green).
  • shellcheck + actionlint clean (actionlint caught an A && B || C; rewritten).
  • The workflow-graph invariants the feat(scripts): fleet-hash — deterministic build-input hashes over the bake graph #298 audit demanded hold by construction: no matrix pruning, no job skipping — every carry-forward happens inside its job, so merge/combos/compose/release-gate see the world unchanged.
  • The decisive validation is the next real dispatch: with aime + claude-code already fresh at :latest, a repeat dispatch should log "fresh: … (unchanged; kept)" and build nothing — I recommend exactly that as the post-merge check before any tagged release.

Rules checked against

…gests (#306)

Rung 5, the last of the carried-forward ladder (#292): the release acts
on freshness. Every build job first asks fleet-status whether its
image's inputs are unchanged from the prior release (:latest, the
promoted last release; :latest-<arch> for per-arch jobs) and, when
fresh, retags that digest with imagetools create — the same manifest
copy the :latest promotion already uses — instead of rebuilding
(delivery/RULES.md rule 13). Same bits, new tag; provenance/SBOM ride
along and honestly name the original build.

Per site:
- bases: the whole-set FROZEN sentinel becomes a per-target judgment —
  stale bases now rebuild even on dev dispatches (which also eliminates
  the stamped-label skew that frozen bases could cause), fresh ones
  retag; the bake covers only the stale subset
- leaves: check + retag before the bake; the ref comes from the graph
  context column, so dotted models (gpt-5.4) are judged correctly —
  the old skip_published mapping never matched them
- per-task: per-item check keyed on the task-mixed hash
- combos: eval and eval-standalone judge independently — a stale
  standalone can rebuild while the lean combo carries forward

fleet-status.sh gains the one-ref form the workflow calls:
  fleet-status.sh check <ref> <hash>   # exit 0 = fresh
so the label-read logic keeps a single home.

skip_published is deleted — the freshness check subsumes it with
hash-correct semantics (tag existence said nothing about content). A
new force_rebuild input bypasses every check: upstream base/package
drift is invisible to the input hash, so CVE refreshes force-rebuild
(principle 9 classes them as patch releases). The CVE gate scans
whatever :TAG points to, carried or fresh (rule 15).

docs/concepts/release-freshness.md documents what a version tag now
means (a coherent input set, not a build timestamp) per docs rule 15.

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
@elronbandel
elronbandel force-pushed the elron/carried-forward-retag branch from d38e6b6 to 7bbac86 Compare August 9, 2026 15:44
@elronbandel
elronbandel merged commit 4194456 into main Aug 10, 2026
5 checks passed
@elronbandel
elronbandel deleted the elron/carried-forward-retag branch August 10, 2026 06:55
elronbandel added a commit that referenced this pull request Aug 10, 2026
… digests (#310) (#311)

Release skill step 7: correct the trigger description (tags +
workflow_dispatch — a plain main push never fired the fleet) and
document what the workflow now does: rebuild only images whose
eval.input-hash changed, retag the rest from the prior release
(delivery/RULES.md rules 12-14), force_rebuild / rebuild_bases for CVE
refreshes, freshness auditable via the Fleet status workflow.

Verify skill step 40: the pass criterion becomes existence AND
freshness — fleet-status.sh <tag> must read every image fresh, which
covers carried-forward digests exactly (tag existence alone cannot
distinguish a correct carry from a stale image). No step renumbering.

Rules-side companion to the merged #307 (contributing rule 2 split).
Resolves #310.

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

drift: delivery/RULES.md#13 — releases rebuild unchanged images instead of retagging their digests

1 participant