Skip to content

fix(release): promote exact beta image manifests - #925

Draft
frahlg wants to merge 1 commit into
dependabot/github_actions/actions/checkout-7from
agent/exact-beta-stable-promotion-stacked
Draft

fix(release): promote exact beta image manifests#925
frahlg wants to merge 1 commit into
dependabot/github_actions/actions/checkout-7from
agent/exact-beta-stable-promotion-stacked

Conversation

@frahlg

@frahlg frahlg commented Aug 16, 2026

Copy link
Copy Markdown
Member

Summary

  • build each Core and updater beta manifest once
  • record the exact beta tag, commit and two index digests
  • promote those recorded manifests to stable aliases without rebuilding them
  • keep the running beta or stable identity correct in Linux, macOS and migrated Compose layouts
  • make beta and stable reruns fail closed instead of moving a tested artifact

Why

The current stable job rebuilds the containers from the same Git commit. That does not reproduce the tested bytes: the binary embeds its version, and base images and OS packages can move between builds. A direct retag of today's beta is also wrong because the binary and OCI labels still identify that beta.

This change gives beta one build-bound candidate tag while baking the future stable product version. The beta prerelease stores ftw-image-digests.json. Stable creates ftw-promotion-receipt.json before it writes any alias, then copies only source@recorded_digest for Core and updater. Every later rerun must use the same receipt.

Rerun and partial-state rules

  • an existing beta receipt must match the Git tag and both live versioned manifests; Docker is then skipped
  • an existing beta tag without a receipt stops before any registry write and needs manual repair
  • an existing stable tag must point to the candidate commit
  • an assets rerun cannot auto-select a newer beta from the same commit
  • all stable runs serialize writes to latest
  • compatibility tags copy the same recorded digest

Runtime identity

The Core binary accepts only its baked stable version or the exact beta tag bound at build time. The updater passes the immutable deployed tag through Compose and persists it in .env. Linux, macOS, the modular-stack helper and both legacy migration paths carry the same value.

Verification

  • make verify
  • 167 optimizer tests and all Go, web, driver, API and full-stack tests
  • external optimizer contract, Compose migration and container boundaries
  • actionlint for beta, release and release-assets workflows
  • exact-promotion contract tests, including beta reuse, stable receipt binding and no stable image rebuild
  • both legacy migration branches and macOS Compose rendering
  • independent follow-up review found no remaining P0/P1

Stack and merge order

This draft is based on the exact head of #876 because that PR has right of way in the three release workflow files. Merge or rebase #876 first, then retarget this PR to master and rerun the same checks. Draft #735 still owns test.yml; this stack does not change that file, and #735's owner has been asked to confirm #876's order.

#728 is not a dependency. No existing beta can be promoted with this contract; publish a new beta after this lands.

@frahlg

frahlg commented Aug 16, 2026

Copy link
Copy Markdown
Member Author

@miravoss26 could you review this stacked draft? It binds stable to the exact Core and updater beta digests and closes the rerun, partial-state, migration, and runtime-identity gaps found in two independent passes.

GitHub checks do not run while the PR targets the Dependabot branch because the workflows filter pull requests to master. On exact head 30af2e9, local make verify, actionlint, migration tests, macOS Compose rendering, and the exact-promotion contract are green. After #876 lands, I will retarget to master and require the normal full GitHub suite before merge.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30af2e9206

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/beta.yml Outdated
Comment thread .github/workflows/release-assets.yml
@frahlg
frahlg force-pushed the agent/exact-beta-stable-promotion-stacked branch from 30af2e9 to 3f397e7 Compare August 16, 2026 13:48

frahlg commented Aug 16, 2026

Copy link
Copy Markdown
Member Author

Both review findings are fixed on exact head 3f397e7d191fa9325e096dabeb55eac4cb5812ea. Local make verify, actionlint, exact-promotion tests, both migration branches, macOS Compose rendering, and runtime identity tests pass.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f397e7d19

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread go/cmd/ftw/main.go
Comment on lines +96 to +98
candidateBase, beta := releaseVersionBase(candidate)
if !beta || candidateBase != baked || candidate == candidateBase || imageTag != candidate {
return baked, false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the beta identity across automatic rollback

When a site running vX.Y.Z-beta.N updates to a later beta and the new Core fails its health check, restorePreviousComponentImage retags the prior image as ftw-rollback-* and passes that synthetic value as FTW_IMAGE_TAG (go/cmd/ftw-updater/main.go:722-734). This exact-match check rejects that tag and reports the baked stable vX.Y.Z instead of the restored candidate; because the version comparator ranks the stable version above every same-base beta, the beta checker then stops offering the failed candidate for retry. Preserve the prior exact deployed tag during rollback, or otherwise recover the build-bound candidate identity.

Useful? React with 👍 / 👎.

Comment thread go/cmd/ftw/main.go
Comment on lines +299 to +302
imageTag := os.Getenv("FTW_IMAGE_TAG")
builtVersion := Version
resolvedVersion, imageTagApplied := runtimeVersionFromImageTag(builtVersion, CandidateTag, imageTag)
Version = resolvedVersion

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass the image tag through legacy compatibility overrides

On the explicitly supported older/developer Compose layouts with a hard-coded Core image, prepareComponentImagePin generates a transient override containing only the replacement image field (go/cmd/ftw-updater/main.go:772-780). Exporting FTW_IMAGE_TAG to the Compose process selects that image but does not place the variable inside the container unless the service has an environment mapping, so a beta update on such a layout reaches these lines with an empty tag and identifies itself as the baked stable release. Add the environment mapping to the transient compatibility override so status, update checks, and fleet reporting retain the beta identity.

Useful? React with 👍 / 👎.

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