Skip to content

🤖 fix: finish the control plane hold and cleanup record follow-ups of #353 - #410

Merged
ThomasK33 merged 22 commits into
mainfrom
issue-353-cleanup-followups
Oct 30, 2026
Merged

ThomasK33 merged 22 commits into
mainfrom
issue-353-cleanup-followups

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

This PR fixes 6 of the 14 follow-ups listed in #353. It leaves 7 open with a reason each, and 1 was already fixed. A provider delete under the control plane hold ends at the hold end, as key and MCP server deletes already do. A CoderMCPServer that releases its finalizer without a delete in Coder now counts in coder_k8s_cleanup_released_without_delete_total. Two cleanup record gaps are closed, and the how-tos name MCP servers in the hold.

Refs #353
Refs #156

Background

#353 tracks what a namespace or control plane deletion can leave in Coder. Its main parts shipped in v0.1.5 (#362, #374, #375, #384, #385, #386). Two comments of #353 list follow-ups from those reviews: items 1 to 9 from #362 (#353 (comment)) and items 1 to 5 from #384 (#353 (comment)). I checked each item against main at 3d902c9.

Item On main before this PR This PR
#362 item 1. Operator access is not repaired during the hold. Open. Dependents wait 10 minutes with OperatorAccessNotReady, then release. Not done. No signal proves that no dependent cleanup is in flight, see Risks.
#362 item 2. A dependent with another finalizer keeps the hold. Fixed in #362. No change
#362 item 3. Queue backlog at the hold deadline. The fix that the item names (cleanup records) covers providers (#374, #375) and keys (#385, #386). Not done for MCP servers. It needs #384 item 3.
#362 item 4. Foreground deletion seen after its marker is gone. Open. Not done. No signal proves that no dependent cleanup is in flight. The only sign is a missing Coder Deployment, and that sign does not prove that Coder stopped, see Risks.
#362 item 5. The provider delete path reads the wall clock. Open (time.Now()). Not done. It changes testability only. A provider clock also needs the create time in coderaiprovider_create.go, which another PR edits, and the MCP server path reads the wall clock too.
#362 item 6. The deployment check and the delete are two requests. Open. Not done. It needs a design decision, see Risks.
#362 item 7. An ID-less provider record is dropped after a deployment switch. Open. Done
#362 item 8. A record is lost when a namespace is reused with a fake Coder. Open. The item says that it needs design. Not done
#362 item 9. A key record keeps an older create time after a status edit. Open. Done
#384 item 1. The providers how-to hold sentence does not name MCP servers. Open, in the keys how-to too. Done
#384 item 2. MCP server releases do not count in the metric. Open. Done
#384 item 3. Cleanup records cover only providers. Keys done in #385 and #386. MCP servers open. Not done, see Risks.
#384 item 4. Provider and key delete passes have no hold-end deadline. Keys done in #385. Providers open. Done for providers
#384 item 5. No unit test for the per-kind count with MCP servers as the largest kind. Open. Done

Implementation

  1. controlPlaneHolds is unchanged from main. Earlier revisions of this PR ended the hold early in two cases, and an independent check showed that each lost cleanup that main performs. No replacement signal is added.
  2. 🤖 fix: hold a deleted CoderControlPlane while CoderMCPServer objects still use it #384 item 4. The provider delete pass under the hold runs with a context deadline at the hold end, and its retry counts from the end of the pass. This is the same code as the key path (🤖 feat: write a cleanup record before each CoderAIGatewayKey create (#353 part 2c) #385) and the MCP server path (🤖 fix: hold a deleted CoderControlPlane while CoderMCPServer objects still use it #384).
  3. 🤖 fix: hold a deleted CoderControlPlane while CoderMCPServer objects still use it #384 item 2. The MCP server delete path records each release without a delete, and the controller counts it after the finalizer patch succeeds. Each delete reconcile first drops an earlier record, as the provider and key controllers do.
  4. 🤖 fix: hold a deleted CoderControlPlane while AI Gateway keys and providers still use it #362 item 9. recordAIGatewayKeyID also rewrites the record when its create time is older than status.lastCreateAttemptTime.
  5. 🤖 fix: hold a deleted CoderControlPlane while AI Gateway keys and providers still use it #362 item 7. ensureAIProviderRecord skips the write only for a record with a provider ID. A record without an ID belongs to a pending create. So the write reads the deployment ID and stalls with CoderDeploymentChanged on a mismatch, before a name conflict in the new deployment can clear the create marker.
  6. 🤖 fix: hold a deleted CoderControlPlane while CoderMCPServer objects still use it #384 items 1 and 5. The keys, providers and MCP servers how-tos name all three kinds. TestControlPlaneDependentsPerKind pins the per-kind count with each kind as the largest.

Validation

Risks

  • 🤖 fix: hold a deleted CoderControlPlane while AI Gateway keys and providers still use it #362 item 1 stays open. A control plane that lost operator access before its deletion still holds for 10 minutes, as on main. A status without operator access does not prove that no dependent cleanup is in flight: a cleanup that already read the token can still call Coder. Generation checks stop stale status writes, but not a status snapshot or token that another reconciler already holds.
  • 🤖 fix: hold a deleted CoderControlPlane while AI Gateway keys and providers still use it #362 item 4 stays open. A foreground deletion that the operator sees only after its foregroundDeletion marker is gone still holds for 10 minutes, as on main. The dependents' calls fail during that time, and they release after the hold. A missing Deployment alone cannot end the hold, because an orphan delete or a cache miss shows the same thing while Coder's pods still run. A safe signal needs more, for example an uncached read that finds neither the Deployment nor a Coder pod.
  • While a provider create is pending (ConfirmingCreate, retried every 5 s), each reconcile sends one more buildinfo request and one record update with unchanged data.
  • 🤖 fix: hold a deleted CoderControlPlane while AI Gateway keys and providers still use it #362 item 6 stays open. A second buildinfo read after the delete narrows the window, but in my reading it does not close it, because that read can also reach a pod on the old database. Recreating the Deployment on a database change is a control plane change outside the cleanup code.
  • Follow-up, not changed here. ensureAIProviderRecord rewrites a record whose ID is set while status.providerID is empty, and the write drops that ID. main does the same. Codex flagged it on this PR. Keeping the recorded ID needs its own record design change.
  • 🤖 fix: hold a deleted CoderControlPlane while CoderMCPServer objects still use it #384 item 3 stays open. Cleanup records for CoderMCPServer need their own design. Option B′ allows a delete of exact recorded IDs, so a recorded config ID fits. A delete of a config found only by its temporary display name would extend invariant 5, which names a key prefix and a provider nonce. MCP server configs belong to an organization, so the record also needs the organization ID. Providers and keys each took a record PR and a sweep PR with a Kind run, so MCP server records are a separate follow-up, together with the MCP server part of 🤖 fix: hold a deleted CoderControlPlane while AI Gateway keys and providers still use it #362 item 3.

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

… hold end (#353)

Change-Id: Ib45cb0e8ada72ddebca134b0c75dcb7262aa6e7c
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…old end (#353)

Change-Id: Idd99f51f9b69f1d51228090a15b9d965082bbce8
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I12ec09f9374ff5c91cedf843b7d0be637891dda8
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…nup_released_without_delete_total (#353)

Change-Id: Ia7fc446d421c2f95496d26d23065894dd96f6216
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…ch kind (#353)

Change-Id: I0efae04d44d60e32c821b656636f24365e2703bf
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…fter a status edit (#353)

Change-Id: Ia86a2e47096359ec5248b654b3da7e6afaf90eea
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…tus.lastCreateAttemptTime (#353)

Change-Id: If34b70a7c627e0a500f6168129502ac060e3cf98
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…witch (#353)

Change-Id: Ibde71ab3c6d21f32d016f7c963aae62cf2e7cde5
Signed-off-by: Thomas Kosiewski <tk@coder.com>
… pending create is confirmed (#353)

Change-Id: I07403a11500125126e518ada28479b362443abcf
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…ployment does not hold (#353)

Change-Id: Iada71ed3a9231a388eb8737ff927936f9d01bfc5
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…nd its Coder Deployment (#353)

Change-Id: I96e990e46152796b2fee072da36c588a45ae53cf
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…ses without a hold (#353)

Change-Id: I2a732a6a1531c2c558e4f5f4ac89c43adc09b553
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…being deleted (#353)

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

chatgpt-codex-connector Bot commented Oct 30, 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-30T16:40:41.962164Z 822a8c1 Manual request
🔒 Security Review ✅ Completed 2026-10-30T16:36:26.556575Z 902e888 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: b92c573049

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.

…lowups

Change-Id: Ibac7c737a909417b7d410b2ac1e3aa796a633d5b
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…t reconciles first (#353)

Change-Id: Ie1b0cd061d176ec43a0b93e34f99b925629d6460
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…#353)

An orphan delete or a cache miss shows no Deployment while Coder's pods
still run. Ending the hold then removed the control plane before its
dependents deleted their resources in Coder.

Change-Id: I967bbab03cbfafddc46a302fd11a4ed7ce830720
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…oes not get it back (#353)

Change-Id: Ibbbb21ce939ed0c2483a9161d3ee165759a40dd7
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…lowups

Change-Id: I37be0530a097ff2bf1339b2747eba03277d02848
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 Review: Didn't find any major issues. Breezy!

Reviewed commit: a417651e17

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

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

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

Reviewed commit: a417651e17

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.

Change-Id: I56c4f4ea8c22c10463fa435820f4c30da91d74b5
Signed-off-by: Thomas Kosiewski <tk@coder.com>
A provider cleanup that read a valid operator token before a Postgres
failure cleared operator access still calls Coder. Releasing the control
plane at once lets its Service and Deployment go and loses that cleanup,
so the hold applies as on main. TestControlPlaneHoldsForCleanupInFlight
covers the case.

Change-Id: I315344184b059e1067b3ffb0e7ddd0d261fc6d11
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I24abcf46ed6aab2f3b9fe4b3bcc2b3851cbe7abf
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: 902e888f50

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: 902e888f50

ℹ️ 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 docs/how-to/manage-ai-gateway-keys.md Resolved
Change-Id: I803385a71a62827cf1a28e6f0a95678c34b854e4
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: 822a8c1e81

ℹ️ 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 30, 2026
Merged via the queue into main with commit 93d8854 Oct 30, 2026
12 of 13 checks passed
@ThomasK33
ThomasK33 deleted the issue-353-cleanup-followups branch October 30, 2026 17:23
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