Repository navigation
fix(build): a build under an agent override is tagged apart from the release - #1146
Merged
Merged
Conversation
…release `codefly deploy gitops render` refused a release whose module had not moved (compute/excel:0.3.2, model/model:0.1.0, records/records:0.4.2) as "already published from other inputs: its version was not moved with its code" once the workspace's agent-overrides moved the agent its services build with. The agent emits the build recipe, so the image identity moved with the agent while the release tag already held the build of the previous agent. A released version names the build its release pins. A pushed build of a released version whose agent the workspace overrides away from the module's own pin is now pushed as `<version>-build.<16 hex of its input identity>`, never under the release tag; the release check does not apply to it, another checkout adopts it from the registry by that tag, and its digest is always captured so the deployment pins it. Every build also records the agent that emitted its recipe (org.codefly.build.agent), and the refusal that remains names which input class differs: another agent, or the same agent with changed code or base image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
antoinetoussaint-byte
force-pushed
the
fix/override-build-not-the-release
branch
from
October 24, 2026 19:01
ce8dbc8 to
0b807a9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Defect
Rendering the obin-blue cell with CLI 0.1.210 (2026-10-24),
codefly deploy gitops render <module> --env bluerefused:It refused the same way for
model/model:0.1.0andrecords/records:0.4.2. The module releases had not changed. The workspace'sagent-overrideshad (codefly.dev/python-fastapi: 0.0.119,codefly.dev/go-grpc: 0.1.58). An override replaces the agent each module'sservice.codefly.yamlpins. The agent emits the build recipe, so the image identity (imageBuildIdentity: RecipeTree, the Dockerfile, the buildx argv…) changed. The registry already held<image>:<version>built by the previous agent, so the released-version check indecideImageReuserefused. The message was also wrong: the version had moved with its code, and it was the build that changed.Design: a released version names one build
The rule this applies: a released version names one build, the one made with the agent the release itself pins. A build made under a workspace override is a different build. It must never be pushed under the release's tag or adopted from it.
Chosen: option (a), a build-qualified tag. When a pushed build of a released version (
x.y.z, not0.0.0) runs on an agent the workspace overrides away from the module's own pin, the image is tagged<version>-build.<first 16 hex of its input identity>, for exampleexcel:0.3.2-build.3f9c0a1b2d4e5f60. That is a valid docker tag, and semver reads it as a prerelease, soreleasedVersionTagnever treats it as the release.0.0.0(identity reuse, no release check), but they would still be pushed to<image>:<version>. That overwrites the release's tag where tags are mutable and fails where they are immutable, which breaks the rule above.pkg/gitops/workloads.gosplitPinnedImagedrops the tag and keeps repository + digest, and that is all the cell file records (cellContainers). The agent'sDockerImagenames<image>:<version>@<captured digest>. For a qualified build the CLI now always captures the digest, even inDeployModewithoutCaptureImageDigest, so the deployed image pins the overridden build's digest and never falls back to the release tag.agent-overridesinModule.LoadServiceFromReference(applyAgentOverride) and keeps no record of what it replaced.Builder.overriddenAgentchecks first whether the workspace'sAgentOverrides()match the service's agent at all, so a workspace without overrides reads no file. When one matches, it reads the service's own file withresources.LoadServiceFromDir, the same recordcomposition.ResolveAgentOverridesuses. An override to the version the module already pins moves nothing, and the build is the release's.org.codefly.build.agent=<publisher>/<name>:<version>, added after the identity like the inputs label, so it is never an input. When a release tag holds other inputs, the refusal now says which of three cases applies:Classification: fix, at the owner. The CLI owns the image build and the reuse decision (
pkg/orchestration). Nothing changes in core or in any agent.Reused:
imageBuildIdentity(the qualified tag is derived from it), the existing registry adopt-or-refuse probe,withBuildInputsLabel(now built onwithBuildFlags), core'sWorkspace.AgentOverrides,AgentOverride.MatchesandLoadServiceFromDir, and thesplitPinnedImagecell path, which is unchanged.Overlap with open branches
feat/ghcr-push-pull-throughtouches the same code inpkg/orchestration/build_plan.go:decideImageReuse. This PR changes the condition line just above its edit and the refusal case.withBuildFlags. This PR adds the identical helper (same body and doc comment) becausegoconstrefused a second"build"literal.recipeAsBuilt. This PR does not touch it: the qualified tag is applied from the reuse decision (imageReuse.image) inbuildRecipe, afterrecipeAsBuilt.Expect a small textual conflict in
decideImageReuseand aroundwithBuildFlags. Both are mechanical to resolve. One composition point: with that branch,recipeAsBuiltrewrites the image to the push reference first, and this change then qualifies that reference's tag. Both orders yield<pushed repo>:<version>-build.<id>.Tests
TestAnOverriddenAgentBuildOfAPublishedVersionIsTaggedApart: the release tag is published from other inputs by agent 0.1.0, and the workspace overrides the agent to 0.2.0. The build is not refused. It is pushed as-t example.test/app:1.2.3-build.<16 hex>and never as-t example.test/app:1.2.3, carries the agent label, and captures its digest withoutCaptureImageDigest. A second checkout (cache wiped) with the qualified tag published from the same identity adopts it and builds nothing. Verified red with the qualification disabled: it fails with "already published from other inputs".TestAnOverrideToTheModulesOwnPinIsTheReleaseBuild: an override to the pinned version builds under the release tag.TestARefusedReleaseNamesWhatDiffers: without an override, a changed build still refuses, with one message for each of the three cases (another agent, same agent, no agent recorded).TestAPublishedVersionFromTheSameInputsIsAdoptedNotRebuilt/…FromOtherInputsRefusesTheBuild/…WithNoInputRecordIsBuiltAgainstill pass. Without an override, identical inputs still adopt the published image, and changed ones still refuse.TestOverrideBuildImageIsAValidDockerTag: tag grammar,releasedVersionTagis false for it, and the agent label argv.TestOnlyASha256DigestPinsAnImagenow also covers the cell file:repo:1.2.0@d,repo:1.2.0-build.<id>@dandrepo@dall recordrepo+d.go test ./pkg/orchestration/ ./pkg/gitops/pass;make lintreports 0 issues.Docs
docs/commands.md: "Keeping an image whose inputs did not change" now describes the agent label, how the refusal names what differs, and the new rule that a released version names the build its release pins (the qualified tag). "Moving the agent version of composed services" links to it.Not verified
SetDockerImage) does not take the captured digest in core'sDockerImage. For such an agent, a qualified build inDeployModewould deploy by its tag. No current agent was checked for this.load) keep the agent's tag, since nothing is published.🤖 Generated with Claude Code