Skip to content

feat(release): end-of-run fleet inventory report (completeness + freshness) - #233

Open
elronbandel wants to merge 4 commits into
mainfrom
elron/fleet-report
Open

feat(release): end-of-run fleet inventory report (completeness + freshness)#233
elronbandel wants to merge 4 commits into
mainfrom
elron/fleet-report

Conversation

@elronbandel

Copy link
Copy Markdown
Contributor

What

Adds an end-of-run fleet inventory report to the release workflow's report job. Every release now writes, to the run summary + a durable fleet-inventory.tsv artifact:

  • Inventory by freshness — every published container image bucketed (base / leaf / per-task / combo / standalone), split into built this run vs older (registry push-time vs the run's start), with the older span.
  • Failures this run — failed jobs bucketed by stage, full list in a <details>.
  • Stale-layer warnings::warning annotations for consumable layers (base/combo/standalone) that did NOT refresh this run.

Why

The release's only report was per-leaf size/build-time. Nothing surfaced which images were stale, missing, or failed — so v0.1.0 shipped with ~6,400 stale combo/standalone images (06-18/06-19, pre-otel/gosu fix) and the only way to learn that was inspecting GHCR by hand. This makes "did the release publish a complete, fresh fleet?" answerable at a glance.

Sample (rendered locally against run 27940336791)

category total built this run older older span
base 20 19 1 2026-06-18 → 2026-06-18
leaf 127 124 3 2026-06-16 → 2026-06-16
per-task 663 90 573 2026-06-21 → 2026-06-22
combo 3211 2 3209 2026-06-16 → 2026-06-19
standalone 3200 2 3198 2026-06-18 → 2026-06-19

Failures: 73 — combos 42 · per-task 28 · leaf 2 · compose 1 (matches the run's actual failures exactly).

Verified

  • actionlint clean (shellchecks the run: script).
  • The exact script, run locally against a real run, reproduces the inventory + the 73-failure split.
  • Only CI-specific unknown: whether GITHUB_TOKEN (with packages: read, already granted via packages: write) can list org packages — handled gracefully (empty → "inventory unavailable", never fails the release). Confirmed on the first release run after merge.

Adds actions: read so the report job can read this run's job results (the existing build-time column uses the same API).

…hness)

The release reported only per-leaf size/build-time, so stale, missing, or
failed images stayed invisible — a published-but-stale combo could hide behind
green stages (v0.1.0's combos were ~all 06-18/06-19 and nothing flagged it; it
was found by hand in GHCR).

Add a step to the report job that cross-checks the registry against the run:
- every container package bucketed (base/leaf/per-task/combo/standalone) and
  split built-this-run vs older (push-time vs run start) -> step summary + a
  durable fleet-inventory.tsv artifact;
- failed jobs bucketed by stage;
- ::warning annotations for consumable layers (base/combo/standalone) that did
  not refresh this run.

Adds actions:read so the report job can read this run's job results.

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
… + failures)

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
…rge)

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
… GITHUB_TOKEN fallback

GITHUB_TOKEN can't list org packages (confirmed in CI: total=0; the failure
summary + freshness window DO work on it). Use a GHCR_READ_TOKEN secret (a
read:packages PAT) for the org-packages listing call only, falling back to
GITHUB_TOKEN when unset — inventory then shows 'unavailable', never failing
the release. Drops the temporary debug line.

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
elronbandel added a commit that referenced this pull request Aug 9, 2026
…stead of rebuilding (#292) (#293)

Add delivery rules 11-15: an image's build inputs are its context + in-repo
base inputs + resolved external-base digests (11); every published image
records a build-input hash in its config (12); a released image with
unchanged inputs is retagged from the prior release's digest, never rebuilt
(13); an absent/unreadable/mismatched hash counts as changed (14); carrying
forward exempts nothing from release gates (15).

Principle 9 gains the matching carve-out: a release tag MAY point at a
digest produced by an earlier release when build inputs are unchanged.
This refines, not repeals, 'different tag, different bits' — carrying the
byte-identical digest forward is stricter immutability than a
non-reproducible rebuild (v0.1.0 shipped ~6,400 silently stale combos,
found only by hand: #233).

Keying on a content hash with fail-dirty answers the silent-staleness
objection that closed #241; #168 lists this change-detection matrix as
its blessed follow-up. Folding external-base digests into the inputs
makes an upstream base bump a changed input, so CVE refreshes rebuild
naturally (#247 interlock via rule 15).

Rules-only PR per contributing/RULES.md rule 2; implementation follows
in small PRs (hash primitive + static test, label stamping, freshness
status, selective retag).

Resolves #292

Signed-off-by: Elron Bandel <elron.bandel@ibm.com>
elronbandel added a commit that referenced this pull request Aug 9, 2026
…shes (#304) (#305)

Rung 4 of the carried-forward ladder (#292): the rule-14 comparison.
containers/scripts/fleet-status.sh derives every static target's
registry ref from the graph's context column (dot-safe — target names
mangle models/gpt-5.4), reads eval.input-hash from the image config at
a tag via imagetools inspect --format '{{json .Image}}' (labels live in
the per-arch config, never the index; both manifest-list and single-arch
shapes handled, attestation entries ignored), and classifies each image
fresh / stale / unlabeled / absent — everything non-fresh is 'changed'
under rule 14 and is what the next release must rebuild or retag.

Combos are deliberately not read: a combo is stale iff a parent is (the
hashes are derived), so ~150 leaf reads cover the ~5,500-combo fleet.

.github/workflows/fleet-status.yml (dispatch-only, packages:read) runs
the sweep against any tag and writes a per-verdict summary + stale
warnings — the report #233 wanted, now keyed on content instead of
build dates. Report-only; nothing gates.

tests/static/fleet_status.rs proves every verdict and read shape
offline by stubbing docker on PATH: fresh via a manifest list with an
attestation entry, stale via a single-arch config, unlabeled, absent,
plus the dotted-model ref map, over the real repo's 153 targets.

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.

1 participant