From 4c1d85048c207722e641e0b7c419c146ceda2261 Mon Sep 17 00:00:00 2001 From: Elron Bandel Date: Mon, 10 Aug 2026 10:12:46 +0300 Subject: [PATCH] skills(delivery,verify): teach the release walk about carried-forward digests (#310) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 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 --- .agents/delivery/release/SKILL.md | 15 +++++++++++++-- .agents/verification/verify/SKILL.md | 5 ++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.agents/delivery/release/SKILL.md b/.agents/delivery/release/SKILL.md index cc8b05ed..0b2c3e69 100644 --- a/.agents/delivery/release/SKILL.md +++ b/.agents/delivery/release/SKILL.md @@ -128,8 +128,8 @@ red), and `.agents/RULES.md:15` (the bake graph is the build artifact). (`.agents/RULES.md:15`, sub-rule d). 7. **Prefer letting CI build the fleet.** `.github/workflows/release-images.yml` - runs bake on every push to `main` (tag: `latest`) and every `v*` tag - (tag: the git tag), setting `GIT_SHA` and `BUILD_DATE`, then + runs bake on every `v*` tag (tag: the git tag) and on `workflow_dispatch` + (tag: the input, or `latest`), setting `GIT_SHA` and `BUILD_DATE`, then `bake --push`es the result. CI runs on real Docker on Linux, where the full sweep is clean; local podman-on-macOS chokes the parallel fleet build on network contention (a documented, non-structural @@ -138,6 +138,17 @@ red), and `.agents/RULES.md:15` (the bake graph is the build artifact). 100+ images locally is slow and flaky; CI is the authoritative fleet builder. + The workflow builds only what changed: every image carries an + `eval.input-hash` label, and a job whose image's inputs are unchanged + from the prior release retags that digest instead of rebuilding + (`.agents/delivery/RULES.md` rules 12–14) — so consecutive releases + share digests for untouched images, and a no-change release builds + nothing. Upstream drift (base images, unpinned packages) is invisible + to the hash: for CVE refreshes dispatch with `force_rebuild: true` + (or `rebuild_bases: true` for the shared bases alone). Audit any + tag's freshness with the **Fleet status** workflow or + `containers/scripts/fleet-status.sh `. + 8. **Commit the fleet report alongside the release tag.** When cutting the tag, commit the final `.agents/verification/fleet/report.md` so the release artifact carries its own verification record diff --git a/.agents/verification/verify/SKILL.md b/.agents/verification/verify/SKILL.md index 78452d7d..eba70fe6 100644 --- a/.agents/verification/verify/SKILL.md +++ b/.agents/verification/verify/SKILL.md @@ -220,7 +220,10 @@ verification record (`tests/run/fleet/RULES.md:8`). dry verification; this is the live release step.)* 39. **Push the tag + trigger the release workflow:** `git push origin eval-vX.Y.Z`. 40. **Verify images published** — `docker pull ghcr.io/exgentic/:eval-vX.Y.Z` - for each. Pass = every expected tag exists. + for each, then `containers/scripts/fleet-status.sh eval-vX.Y.Z`. Pass = every + expected tag exists **and** reads `fresh` (its recorded `eval.input-hash` + matches the repo at the tag — carried-forward digests included; + `.agents/delivery/RULES.md` rules 12–14). 41. **Verify signatures / attestations** — `cosign verify ghcr.io/exgentic/:eval-vX.Y.Z`. 42. **Smoke test one image from a clean machine** — pull + run from a different host. Pass = end-to-end works from nothing.