Skip to content

🤖 feat: bind CoderWorkspaceClaims to ready CoderWorkspacePool members and write the claim status - #387

Merged
ThomasK33 merged 4 commits into
mainfrom
feat/workspace-pool-claims
Oct 15, 2026
Merged

ThomasK33 merged 4 commits into
mainfrom
feat/workspace-pool-claims

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Summary

This PR lets the dormant CoderWorkspacePool reconciler bind CoderWorkspaceClaim objects to its ready members and write the claim status (plan 6.3 steps 5 and 10). Nothing registers the reconciler yet, so no user sees a change.

  1. Binding. In each reconcile where the pool's inputs resolve and the uncached control plane read allows the owner and template, the pool binds its waiting claims, oldest first (creationTimestamp, then name). It picks a ready unclaimed member that it controls: current before outdated, then the oldest readyTime. "Ready" is the rule that the counts use: phase Ready, Ready=True, and not Used (plan 16, PR 9 advisor item (a)). A member whose agent is not ready, a used member, a failed member, and a deleting member are never bound.
  2. One update per bind. The pool sets spec.claimRef and moves the controller owner reference from the pool to the claim (with blockOwnerDeletion) in one Update that carries the resourceVersion from the uncached member list. A member that changed after the list, for example one that its reconciler marked used, answers 409 and stays unbound. A conflict ends the reconcile. The pool label stays, so the pool still counts the member in boundReplicas. The set-once CEL rule on claimRef refuses a second bind of the same member.
  3. Claim status. The member is the source of truth: each claim's status comes from the member whose claimRef.uid is the claim's UID. A bound claim shows Bound, the member, the workspace ID and name, the owner's Coder username (so coder ssh <ownerName>/<workspaceName> works), and boundTime. Ready=True follows the member's readiness. A claim without a member waits with Pending WaitingForReadyWorkspace. After a crash between the bind and the claim status write, the next reconcile finds the member and finishes the status, and it binds no second member.
  4. Claim delete deletes the workspace. The claim controls its member, so garbage collection deletes the member when the claim goes, and the member's cleanup deletes the workspace. A bound member skips the last use check (this was already in the member cleanup), so the workspace is deleted even after the claimant used it.

Refs #153

Background

This is PR 11a of the CoderWorkspacePool stack (#153). PR 11b (on-demand creation for waiting claims, PoolNotFound, and the bound-member watch that marks a claim Lost) stacks on this branch.

The pool lists claims through its client (the cache, once PR 12 registers the reconciler) and filters them by spec.poolName. The member list, which decides each bind, stays uncached. PR 12 wiring adds the claim watch that maps a claim to its pool (recorded in plan section 16). resolve now also returns the owner's Coder username from the owner read it already does.

Validation

New tests (coderworkspacepool_claim_test.go). I wrote them first and ran them on the base (8f580b0b, the reviewed #380 head): all 5 failed (member ... is not bound, the second bind of the member must fail). With this PR they pass.

  • TestPoolBindsOldestClaimFirst: one ready member and two claims. The older claim gets the member: claimRef, the claim as the only controller with blockOwnerDeletion, no reference to the pool, the pool label kept. Its status is Bound with the member, workspace ID and name, owner tester, boundTime, and Ready=True. The newer claim waits with WaitingForReadyWorkspace. The pool counts 1 bound member and creates a replacement.
  • TestPoolBindsCurrentBeforeOutdated: a current member (newer) goes to the first claim, an older outdated member to the second claim, and a third claim waits. A used member and a member with Ready=False are never bound.
  • TestPoolBindRace (plan mutation check 4): two reconciles race for one member, the second with a cache that has not seen the older claim. Exactly one bind lands, and the other reconcile fails. Second case: someone uses the member right after the pool's member list. The bind answers 409, and the member stays unbound.
  • TestPoolFinishesClaimAfterCrash: a member already holds the claim, but the claim has no status. The reconcile writes Bound from that member, with the owner name, and binds no second member.
  • TestPoolNeverRebindsClaim (round 1): a member of another pool that names the claim is not its holder. After the bound member is deleted, a reconcile whose claim list has no status binds no second member, and the claim becomes Lost with MemberDeleted and Stalled=True.
  • TestPoolClaimDeleteDeletesWorkspace: after the bind, the claimant uses the workspace, then the claim is deleted. envtest runs no garbage collector, so the test checks the owner reference and deletes the member as the collector would. The member's cleanup starts the delete build and then releases its finalizer.

Codex review round 1 (all fixed in c4824691):

  • 4277243288: a claim that a member held once (boundTime set, or phase Bound or Lost) never binds again. Right before each bind, the pool reads the claim without the cache, so a status that the cache has not shown yet counts too. A once-bound claim whose member is gone becomes Lost with MemberDeleted (TestPoolNeverRebindsClaim).
  • 4277243297: the bind sets the pool label again, in case it drifted.
  • 4277243304: a holder must have the claim's pool in its immutable spec.poolName, so a member of another pool never counts.
  • For 4277241752 on 🤖 feat: create CoderWorkspacePool members on demand for waiting claims, keep claims of a missing pool, and mark a claim Lost when its workspace is deleted #388: before the bind, the pool stores the owner's Coder username in the claim status, so a crash right after the bind cannot lose it.

Codex review round 2 (fixed in c8c6095d):

Both new tests failed on the previous head.

Codex review round 3 (fixed in 366c494d): 4277508974: a free member must also name the pool in its immutable spec.poolName, so a misnamed member is never bound (TestPoolBindsCurrentBeforeOutdated).

Codex review round 4 (blockers only, both deferred to before PR 12 and recorded in plan section 16): 4277607232 (two overlapping pool reconciles, which need two operator replicas at once, can bind two different members to one claim; planned fix: reserve the member in the claim status first) and 4277607237 (a new pool that reuses a deleted pool's name with another owner overwrites the claim's ownerName). Round 5: clean.

Mutation checks: I removed one control at a time, and each removal made a named test fail (20 of 20): bind with an empty resourceVersion (plan mutation 4: the API server refuses it), bind with a resourceVersion read again just before the update (the used-after-list case catches it), newest claim first, outdated before current, binding a used member, binding a member with Ready=False, ignoring a member that already holds the claim, keeping the pool as controller, not moving the counts, dropping the owner username, scoping the holder to the pool, the uncached claim read before a bind, the once-bound rule, Lost with MemberDeleted, the label repair, skipping a replaced claim, the holder check before Lost, the claim refresh, and the spec.poolName check on free members.

Gates on the final commit: drift (codegen, manifests, installer, API reference: no diff), make docs-check, dormant-CRD guard, docs lint and spelling, make verify-vendor, make build, make lint, actionlint, make test, make test-integration, make vuln, race. All passed.

Size

672 hand-written lines (265 production, 407 test, counting removals). This is over the 500-line target: the first version had 477, and the three review rounds added about 195 lines of race handling and tests. No generated files.

Risks

None for users. The reconciler is dormant. Recorded for PR 12: the claim watch and its mapping to the pool key.


Generated with mux • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $173.65

…nd write the claim status

Change-Id: Ia47cdccaaad51b9a7cfa069a5e5de45de22be757
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T00:16:51.170749Z 366c494 Manual request
🔒 Security Review ✅ Completed 2026-10-15T00:07:07.280999Z 366c494 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 3f5e8707ad

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: 3f5e8707ad

ℹ️ 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 internal/controller/coderworkspacepool_claim.go Outdated
Comment thread internal/controller/coderworkspacepool_claim.go
Comment thread internal/controller/coderworkspacepool_claim.go
…pool, repair the pool label, and store the owner name before the bind

Change-Id: Id61727ee0e9898f2def86bd569dbc814c6b44fa4
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: c482469109

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: c482469109

ℹ️ 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 internal/controller/coderworkspacepool_claim.go Outdated
Comment thread internal/controller/coderworkspacepool_claim.go
…eplaced claim, and check the holder again before Lost

Change-Id: I536b0015fc519c2ffd84a81fb4b055c5f0a0b871
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: c8c6095d95

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: c8c6095d95

ℹ️ 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 internal/controller/coderworkspacepool_claim.go Outdated
Change-Id: I06dd83d03cfd1e061e4d3a03940ac6e5a2be9934
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 366c494d0b

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@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: 366c494d0b

ℹ️ 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 internal/controller/coderworkspacepool_claim.go
Comment thread internal/controller/coderworkspacepool_claim.go
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 366c494d0b

ℹ️ 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".

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 15, 2026
Merged via the queue into main with commit 66902b2 Oct 15, 2026
10 checks passed
@ThomasK33
ThomasK33 deleted the feat/workspace-pool-claims branch October 15, 2026 00:41
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