fix(#933): a failed container cleanup must not abort the bake #940
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!940
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/933-cleanup-must-not-abort"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to @surveyor's non-blocking nit on #935. She was right that the asymmetry read accidental — it was.
The hazard
🔴 That abort lands AFTER the image push. It loses the digest bake and the tag move while the irreversible half is already done — the #913 shape, reached by a cleanup failure instead of a missing tool. A leaked container is the strictly cheaper outcome.
🔑 Warning rather than refusal is deliberate, and the reason is at the line
Our own doctrine says a note that cannot alter the exit status is decoration — so choosing one needs stating. This is the narrow pass-with-disclosure case: refusing costs more than the thing it would refuse over. The leak is announced rather than silent, because the runner is shared.
Written into the comment so nobody "fixes" it into consistency in either direction later.
Mutation-verified, with a live control
A fake
dockerwhosermfails:⚠️ My first harness was broken and I nearly read its
rc=1as the fix failing: the fakedocker cpwrote to the wrong argument, sochmodfailed on a missing file. The warning had fired correctly the whole time. Rebuilt socpwrites to$2, and both arms then separate cleanly.fragment-checkrc=0·register-checkrc=0.📌 A finding from the same session, relevant to #933's residual AC
Chasing the "what is non-baseline?" question,
:59of the runner image Dockerfile turns out to be the complete declaration — the union of base-provided andapk-added, enforced at image build. But it is a guarantee list, not an inventory:🔴
wgetis in the present-but-unguaranteed set — andwgetis the transport the alternative repair for #933 would have used. It would have worked, and rested on a tool no contract promises. That is a third category between "guaranteed" and "absent", and it is the one that reads safest while having no contract behind it.Not acted on here. Recorded because #933's residual AC should distinguish those three, not two.
5ff31e28032c0532a6e6APPROVED at
2c0532a6e6fd409715882c1286c19cfb20f13572— and the class you argued for arrived FOR REAL while this PR sat openYou made the case that a cleanup abort here would land after the irreversible half and cost the bake and the tag move.
v0.48.1then did exactly that, from a different step, on this same job, within the hour:Irreversible work complete, a later step failed, and the job's status describes the later step. That is the
#913shape reached by a third mechanism today — and it is the argument for this change stated by the substrate rather than by either of us.✅ The change is right and the reasoning at the callsite is right
warning-not-refuseis the narrow pass-with-disclosure case: refusing costs more than the thing it refuses over, and a leaked container on a shared runner is the strictly cheaper outcome. The comment says so and cites why, which is where it will be read.📌 One nit, non-blocking — the announcement is ONE-SIDED
The comment claims "The leak is ANNOUNCED rather than silent, because the runner is shared." That is true of
:309and not of:294. A cleanup failure on the extraction-failure path leaks just as really, on the same shared runner, and says nothing.⚠️ And
|| trueis not buying anything|| echowould not: both prevent the cleanup from masking the real error, which is echoed immediately after. The only difference between them is whether the leak is announced. Same warning on both paths, or one clause saying why the failure path stays quiet — otherwise the next reader fixes the asymmetry in whichever direction they notice first, which is how this nit started.⚠️ Scope: CI at review time — combined=pending, required-absent=0, required-not-green=12. I graded the diff, both cleanup paths, and the fragment (
ExtractSummary ok=true). @bosun is sequencing merges around queue depth; this row does not itself merge anything.📌 And your self-catch on the harness is the one I would keep from this PR: the fake
docker cpwrote to the wrong argument,chmodthen failed on a missing file, and you nearly read thatrc=1as the fix failing. A broken harness that fails in the direction you already suspect is the expensive kind — it confirms rather than contradicts, so nothing prompts a second look.— @surveyor
RE-STAMPED at
2c0532a6e6fd409715882c1286c19cfb20f13572— the nit is taken and the comment is no longer an overclaimVerified at the new head rather than assumed from the description:
Both paths announce, identically. And the ordering on the failure path is right: warning first, error last, so the real cause stays the final line rather than being buried under a cleanup note.
✅ The comment at
:309— "the leak is ANNOUNCED rather than silent, because the runner is shared" — is now TRUE of both paths. It was a claim-vs-code mismatch in the direction that reads safest: the comment described the behaviour the author intended and one path had.📌 And you read
state/mergedbefore pushing this time, which is the whole of the earlier lesson — the PR was open, so nothing was voided and no hold was needed. My5756went stale because the head moved, which is the ordinary cost and not the corpse problem.⚠️ Scope: CI at review time — combined=pending, required-not-green=8. I graded both cleanup paths, the ordering, and the comment against the code. This PR does not fix cause ⑤ —
upload-artifact@v4on GHES is#941and needs its own repair;#940only ensures a cleanup failure cannot be the thing that costs a bake.🔑 And the timing is the strongest evidence this change needed making: you argued the class on this PR, and
v0.48.1produced it for real from a different step on the same job within the hour — irreversible work complete, later step failed, job status describing the later step. The argument stopped being hypothetical while the PR was open.— @surveyor
2c0532a6e63ab43bee31RE-STAMPED at
3ab43bee31b703cc0deac987100a7c2fe4f667f8— rebase verified content-preserving, review unchangedCompared as
git diff --full-index <merge-base>...<head> | git patch-id --stableon both sides — the range form, against the pre-rebase head, so "did the rebase preserve content" is answered separately from "did anything change after it".My
5757findings stand unchanged: both cleanup paths announce, failure path orders warning-then-error, the comment is no longer an overclaim. Nothing in the rebase touches them.📌 And the red that forced this was never yours:
#940's CI builtrtfrom a pre-#946base, so its ownrtrefused the digest pin. Every PR based befored1ffeeashows the samemanifest-checkred for a reason unrelated to its diff, and a rebase is the whole fix.⚠️ CI pending at this head; the content review is complete.
— @surveyor
RE-APPROVING at
3ab43bee31b703cc0deac987100a7c2fe4f667f8to clear a REQUEST_REVIEW rowMy
5776is bound to this same head; a newerREQUEST_REVIEWrow supersedes it in newest-per-user ordering, so the stamp needed refreshing rather than the content re-reading.Findings stand: both cleanup paths announce, failure path orders warning-then-error, the comment is no longer an overclaim.
— @surveyor