Repository navigation
fix(clusters): keep the chosen region when a second region is removed on a single-region tier - #1842
Open
dawsontoth wants to merge 2 commits into
Open
dawsontoth wants to merge 2 commits into
dawsontoth wants to merge 2 commits into
Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request updates the region correction logic in ClusterForm to prioritize keeping the user's chosen region when correcting regions on a tier that limits allowed regions, falling back to 'US' or the first available region only if the chosen region is not offered. It also adds corresponding documentation in DESIGN.md and a comprehensive suite of unit tests in ClusterForm.test.tsx to verify this behavior. There are no review comments to address.
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||
This was referenced Oct 11, 2026
dawsontoth
added this pull request to stack #1907
October 11, 2026 21:26
dawsontoth
removed this pull request from stack #1907
October 12, 2026 17:25
dawsontoth
force-pushed
the
claude/1275-region-removal-keeps-siblings
branch
from
October 12, 2026 18:05
fe4bbe8 to
d2c4490
Compare
dawsontoth
added this pull request to stack #1919
October 12, 2026 18:29
dawsontoth
marked this pull request as ready for review
October 14, 2026 01:11
…ects it A tier with allowedRegionIds (the free tier) takes a single region, and the form corrects that region whenever it is the only one left. The correction always jumped to the default US region, so removing the second region, which is what the tier's "only one region" error asks the user to do, also threw away the first region and its latency. Prefer a latency the tier allows in the region the user chose, and fall back to the default region only when the tier offers nothing there. Refs #1275 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… regions Removing the first row shifts the survivor to index 0 before the correction runs, so pin that it keeps its region there too. Refs #1275 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dawsontoth
force-pushed
the
claude/1275-region-removal-keeps-siblings
branch
from
October 14, 2026 01:18
d2c4490 to
d9703d2
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.
⊙ Problem
On a tier that allows only one region (the free tier, which carries
allowedRegionIds), removing the second region of a new cluster threw away the first region too: it snapped back to the default US region and its smallest latency (#1275). The free tier's own validation error on the second row ("You can only select one region with this performance tier!") is what asks the user to remove it, so the natural fix-up step is the one that loses their choice.Reproduced on
stagein a real browser before this rebase (Playwright against a local dev server with mocked API responses): pick Medium, choose Europe 45ms for region 1, add a region, switch to Free, remove region 2. Region 1 readUS / 90ms, small distributionafterwards. #1780 keeps that US-first correction, so the bug is still there on its branch: with the fix reverted on top of #1780, the two #1275 tests below go red.The cause is
autoSelectRegionBasedOnAllowedRegionIdsinClusterForm.tsx. It corrects the only remaining region whenever that region is not one the tier allows, and it always corrected to US. Removing the second row is what drops the count to one and fires it. The triage suspect,autoPickLatencyDescriptioninRegionFormInputs.tsx(which #1780 removes), was not involved: rows are keyed byfield.id, and removing a row leaves the other row's region and latency untouched on tiers without a region allow-list (pinned by a test below).Stack: #1780 ← this PR ← #1849 ← #1851 ← #1870. This branch is based on #1780's branch (
david/1778-custom-regions), so it lands on top of #1780 instead of #1780 rebasing around it; retarget tostageonce #1780 merges. On 2026-10-13 this branch was rebased with #1780 ontostage, after #1917 merged.stagehad gained its ownClusterForm.test.tsx(#1846's refused-edit cases), so this branch's region cases now sit beside it inClusterForm.regions.test.tsx, following the repo'sComponent.topic.test.tsxconvention. Both files keep every case.💡 Solution
The correction now prefers an allowed entry in the region the user already chose, and falls back to US, then the first allowed region, only when the tier offers nothing there.
How it fits #1780: #1780 stores each region plan as a region id, so the effect looks up the surviving id in #1780's
regionLookupand matches the catalog region's name (ResolvedRegion.name, the catalog row'sregion). A custom region (oreg-…) is never corrected, because #1780's effect already skips those ids: the allow-list describes the catalog. Before the rebase the same preference read the entry'sregionNamedirectly.When the tier allows several latencies in the chosen region, the correction takes the first allowed one in catalog order rather than the one closest to the old latency. Today's single-region allow-lists offer one latency per region, so the two can't differ yet.
🔧 Changes
src/features/clusters/upsert/ClusterForm.tsx— the change inautoSelectRegionBasedOnAllowedRegionIds: the surviving id's catalog name, then afindon it, run before the existing US and first-allowed fallbacks. Nothing else in the effect, including when it runs, changed.src/features/clusters/DESIGN.md— records when the correction runs (including on removal), that a custom region is never corrected, and the same-region-first rule.✅ Verification
Route: a component test driving the real
ClusterForm(react-hook-form, zod resolver, Radix selects, #1780's region lookup, the real Remove button) in jsdom.src/features/clusters/upsert/ClusterForm.regions.test.tsx(new) — five cases, reading each row as it is shown, because the form now stores a region id: removing a row on an unrestricted tier leaves the survivor untouched; on the free tier the survivor keeps its region whether row 2 or row 1 was removed ([Create Cluster] Deleting the second region will also revert the first chosen region and latency #1275); an already-allowed survivor is untouched; and a survivor in a region the tier does not offer still falls back to US. The fixtures now give each row a region id, and the harness passes feat(clusters): org-owned custom regions — picker group and units on the cluster form #1780's newClusterFormprops (no custom regions).finddisabled, the two [Create Cluster] Deleting the second region will also revert the first chosen region and latency #1275 cases go red (expected [ 'US / 90ms, small distribution' ] to deeply equal [ 'Europe / 60ms, small distribution' ]) and the other three stay green.npx vitest run src/features/clusters/upsert/ClusterForm.regions.test.tsx→ 5 passed (exit 0). Full gate via the pre-commit hook at d2c4490: vitest 399 files / 3698 tests passed,oxlintclean,dprint check --stagedclean, commitlint ok;npx tsc -bexit 0.stage(d9703d2):npx tsc -bexit 0, andnpx vitest run src/features/clusters203 passed. The full suite passed at the stack's top tree: 5,552 tests, exit 0.stagebefore it.Cross-model review on the rebased branch (one round, vs
david/1778-custom-regions): codex (graded), gemini and the Harper domain adjudicator all ran. The adjudicator kept two nits. Taken: the test helper's comment narrated its DOM walk, so it now says only why rows are read as shown. Rejected: explicit import extensions (this repo's imports are extensionless throughout). It dropped gemini's three majors on evidence:ResolvedRegion.nameis the catalog row'sregion(lib/regionLookup.ts:53), theincludescall only runs onceallowedRegionIds?.lengthis truthy, and submit re-resolves each id from the same form state the effect writes. Its two open decisions (first allowed latency vs closest, silent latency change) are answered above.Closes #1275
🤖 Generated by Anthropic Claude Code (Claude Opus 5.5); posted via @dawsontoth.
🤖 Generated with Claude Code
Related PRs: #1780 overlaps (this branch is stacked on it; it rewrote the same correction effect for region ids), #1849 overlaps (stacked on this branch), #1846 overlaps (it created stage's
ClusterForm.test.tsx; this branch's cases sit beside it inClusterForm.regions.test.tsx), 3 others independentComplexity: easy
Review-Coverage: authored=claude; ran=gemini,codex; adjudicated=domain; declined=cursor-grok,cursor-composer,cursor-kimi,cursor-muse; rounds=1; full=1 @ d2c4490
Review-Attention: read ~3m (decisions: same-location-picks-first-allowed-latency, silent-latency-correction) @ d2c4490