Review round 1 on #997 (Codex): the comment had the removal condition
backwards. #996 landing is when a workflow starts USING the
ubuntu-26.04-arm label, not when the entry becomes safe to drop. Keep
both entries; the only correct trigger to remove the file is a released
actionlint that knows the labels natively (rhysd/actionlint#682).
Also corrects an overstated PR-body/comment claim (Node/.NET/Playwright
are the only per-job-installed tools, Docker the only runner-provided
one) and softens the optical-size.spec.ts flake framing per the same
review round; those are PR body/comment edits, no code change.
Why
Published images only contain amd64. Build and test both amd64 and arm64 on native runners, then publish one index that Docker can resolve on either host.
Scope
imageas a native two-architecture matrix, with both legs pinned to Ubuntu 26.04. Pinpublishto Ubuntu 26.04 as well. Trivy and the boot smoke test gate each image.publishchecks both before pushing the platform manifests.Tradeoffs
The digest-keyed child tags remain in GHCR so repair builds cannot orphan an older release's platform manifests. Plain per-commit architecture tags are convenience names. Publication waits for both matrix legs; a failed leg blocks the release until a successful CI dispatch or fix commit. The NuGet lock-drift guard runs once because its verdict is architecture-independent.
Blast Radius
CI gains an arm64 runner and a second image artifact. Releases still promote the CI digest without rebuilding. The amd64 cache key remains byte-identical to E2E's; the arm64 prefix cannot match amd64's broad restore key. The image and publisher runners are pinned so an
ubuntu-latestalias move cannot change a build or digest-publication host without a workflow edit.Verification
The pinned Ubuntu 26.04 CI image legs passed Trivy and the readiness smoke test on both architectures. The measured
Build runtime imagestep was amd64 57 s and arm64 28 s on same-commit, fully cached reruns. One further same-commit rerun measured 35 s and 34 s, respectively; the 57 s amd64 sample did not repeat. Earlier Ubuntu 24.04 measurements were amd64 63 s cold / 33 s warm and arm64 66 s cold / 32 s warm; no 26.04 cold build was measured. The decision record links the run attempts.On a Docker 29.8.1 client and daemon with the containerd store, a push to local
registry:2produced the exacttag: digest: sha256:… size: …line extracted by the workflow parser. The Docker 29.4.2 source uses this format in both image-store paths. LocalRepoDigestsstill named the source index rather than the pushed platform manifest, so image inspection is unsafe for this handoff.The local registry's exact-child assertion rejected a substituted amd64 manifest and an added Windows child; the former Linux-filtered assertion accepted that extra child. The dry-run JSON's locally computed digest matched the pushed index, and the immutable digest-built index stayed valid after the plain amd64 tag moved. Both
imagetools createmodes preserved an existing index digest; the decision record links the buildx implementation. An index-only GHCR attestation verified by index digest and failed by platform child digest. Bash syntax and the tracked-file image-pin guard passed.actionlintpassed with only its stale unknown-label diagnostics for the two GA Ubuntu 26.04 labels ignored.Closes #995