Repository navigation
fix(repo): a status write that conflicts after a successful push no longer wedges the Repo (#26) - #27
Merged
Conversation
…onger wedges the Repo (#26) A Repo whose push had LANDED wedged permanently on krateo.io/external-create-pending. The status write after the push lost an optimistic-concurrency race, Create returned that 409, and provider-runtime answers a conflict from Create by requeueing without recording an outcome (reconciler.go:997-1008) — pending stays with neither -succeeded nor -failed, and every later reconcile refuses with "cannot determine creation result". Seen on krateo-057 (0.15.4) on the first publish of a blueprint, 14ms after a successful push. - Both status writes in SyncRepos (the committed path and the already-up-to-date path) go through updateStatusWithRetry: RetryOnConflict that re-reads the object and keeps the status the sync produced and the external name it set — the LocalResource fix from #16, which Repo never got. - A status-subresource write returns the server's object, whose annotations replace the copy's, so the helper sets the external name again after the write: the runtime persists it as the create's critical annotation, the one record of the push that does not depend on the status write. - Observe reads the target commit from the external name when status.targetCommitId is empty, instead of checking the history for "" — so a Repo whose status write was lost converges. Tests: a REAL conflict (a concurrent write makes the reconciler's resourceVersion stale) — the status lands, the concurrent write survives, the external name survives; with the refresh removed the test fails. A source guard pins that no bare Status().Update exists outside the helper (the LocalResource guard, #17). go test -race ./... passes. Not fixed here: Repos wedged before this release (#22) — resolving an existing pending annotation needs the runtime-side confirm-the-negative. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016V8EVEvyty3XvXMHUWJvPg
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.
Fixes #26.
The bug
Repowhose push had landed got stuck permanently onkrateo.io/external-create-pending.Createreturned that 409. provider-runtime requeues a conflict fromCreatewithout recording an outcome (reconciler.go:997-1008), so the resource stays stuck.The fix
SyncRepos(the committed path and the already-up-to-date path) now go throughupdateStatusWithRetry. It retries on conflict, re-reads the object, and keeps both the status the sync produced and the external name it set. This is the LocalResource fix from LocalResource wedges on external-create-pending under fan-out: concurrent pushes to one branch + a lost status-write race #16, which Repo never got.Observefallback:Observereads the target commit from the external name whenstatus.targetCommitIdis empty, so a Repo whose status write was lost converges.Tests
resourceVersionstale, then the test checks that:Status().Updatemay exist outside the helper, as fix: a concurrent push must not wedge a LocalResource forever (#16) #17 does for LocalResource.go test -race ./...andgo vetpass.Observefallback, which needs a git remote; it's covered by the live check after rollout.Not in scope
Repos that got stuck before this release (#22). Resolving an existing pending annotation needs the runtime-side confirm-the-negative.
🤖 Generated with Claude Code
https://claude.ai/code/session_016V8EVEvyty3XvXMHUWJvPg