You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When coder update runs against a workspace whose template has had its workspace_region option set modified since the workspace was created (e.g. the recent addition of eu-central-1), Coder surfaces an interactive picker to select the new value. Per Coder's docs: "when template authors modify parameter options (add, remove, or substitute values), workspace users will be prompted to select the new value." Neither --use-parameter-defaults nor --yes bypasses this picker — it's a parameter-collection prompt, not a confirmation. (For the same reason, coder create had to start forwarding --preset explicitly; see comment at coder.py:33.)
When the picker fires in an environment that can't deliver stdin — for example an IDE's read-only output channel — the command wedges with no way out. Reported in the wild this morning after a manual hogli devbox:update.
Note: coder update doesn't even accept --yes (confirmed in coder/cli/update.go — it only registers parameterFlags.allOptions() and bflags.cliOptions(), neither of which contains cliui.SkipPromptOption()). Earlier commits on this branch tried to add --yes to coder update; that would have broken the command outright with an unknown-flag error. Reverted.
Changes
New helper _pinned_region_param(workspace) in cli.py: reads the workspace's current region from coder metadata, defaulting to us-east-1 for boxes that predate the region metadata item.
_sync_workspace_parameters(name, workspace) now takes the workspace dict and merges the pinned region into the params dict — only when other params are being pushed, preserving the "skip when nothing to sync" fast path.
devbox:update always merges the pinned region into its params dict (it always invokes coder update).
Comment block at coder.py:48 rewritten to explain why region is forwarded on update — the previous comment's "immutable, so never forward on update" logic is what allowed the bug to land.
The retry shim in _run_with_param_retry already handles the template-no-longer-declares-this-parameter case, so this is forward-compatible with template changes.
(Earlier commits on this branch went through a Y/n gate on devbox:start and an incorrect --yes addition before landing on the actual fix. Cumulative branch diff against master is only the changes described above — happy to squash on merge.)
How did you test this code?
I'm an agent. No manual run on a real devbox.
Updated existing tests test_syncs_then_starts_when_stopped and test_devbox_update_applies_when_outdated to assert the pinned region appears in the params dict.
Added test_sync_pins_workspace_region_from_metadata_to_suppress_picker exercising the metadata-driven region pin.
Existing test_update_paths_drop_unknown_params_and_retry already covers the case where Coder rejects a forwarded parameter — confirms workspace_region is dropped cleanly if the template removes it.
Full test_devbox.py suite: 241 passed.
ruff check, ruff format --check, pre-commit (bin/hogli lint:python:fix, bin/hogli format:python, uv run ty check) all green.
Publish to changelog?
no
Docs update
n/a
🤖 Agent context
Tooling: Claude Code (Opus 4.7), /wt worktree skill, /code-review for the calibration pass that surfaced the wrong-flag issue.
Two false starts before the right fix: (1) a Y/n gate on devbox:start based on a misread of the symptom, (2) adding --yes to coder update based on a misread of which Coder prompt was wedging. Both reverted on this branch. The actual mechanism is the rich-parameter picker that fires when a template's option set changes, which only goes away when callers forward the current value explicitly — same pattern as --preset on create.
Verified coder update's flag set by reading coder/cli/update.go and coder/cli/parameter.go upstream; --yes is not a valid flag for update (it's a per-command option attached via cliui.SkipPromptOption() on commands like start/stop/restart/delete).
Considered widening the region pin to also fire when no other params need pushing (i.e. always invoke coder update on devbox:start to clear any pending parameter prompt proactively). Out of scope: that adds a Coder round-trip on every start without addressing a known wedge surface — left as a follow-up if reviewers want it.
The reason will be displayed to describe this comment to others. Learn more.
Clean fix to internal developer tooling: pins the current workspace region parameter on coder update to suppress an interactive region picker. Author is on the owning team, tests cover both the default-region and EU-region cases, and there are no production, security, or data-model concerns.
tools/hogli-commands/hogli_commands/tests/test_devbox.py, line 2199-2240 (link)
New region-pin test not parametrised alongside existing case
The new test_sync_pins_workspace_region_from_metadata_to_suppress_picker test and the existing test_syncs_workspace_parameters_before_starting_stopped_workspace test exercise _start_existing_workspace with the same structure — the only meaningful differences are the workspace metadata dict (no metadata → DEFAULT_REGION vs. eu-central-1 in metadata → "eu-central-1") and the resulting expected workspace_region value. Per the team's preference, these two cases would naturally belong together as a single @pytest.mark.parametrize-driven test. Similarly, test_devbox_update_applies_when_outdated only covers the DEFAULT_REGION path for devbox_update; a second parametrised case with non-default region metadata would confirm that path reads region from the workspace dict too.
Prompt To Fix With AI
This is a comment left during a code review.
Path: tools/hogli-commands/hogli_commands/tests/test_devbox.py
Line: 2199-2240
Comment:
**New region-pin test not parametrised alongside existing case**
The new `test_sync_pins_workspace_region_from_metadata_to_suppress_picker` test and the existing `test_syncs_workspace_parameters_before_starting_stopped_workspace` test exercise `_start_existing_workspace` with the same structure — the only meaningful differences are the workspace metadata dict (no metadata → `DEFAULT_REGION` vs. `eu-central-1` in metadata → `"eu-central-1"`) and the resulting expected `workspace_region` value. Per the team's preference, these two cases would naturally belong together as a single `@pytest.mark.parametrize`-driven test. Similarly, `test_devbox_update_applies_when_outdated` only covers the `DEFAULT_REGION` path for `devbox_update`; a second parametrised case with non-default region metadata would confirm that path reads region from the workspace dict too.
How can I resolve this? If you propose a fix, please make it concise.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---### Issue 1 of 1
tools/hogli-commands/hogli_commands/tests/test_devbox.py:2199-2240
**New region-pin test not parametrised alongside existing case**
The new `test_sync_pins_workspace_region_from_metadata_to_suppress_picker` test and the existing `test_syncs_workspace_parameters_before_starting_stopped_workspace` test exercise `_start_existing_workspace` with the same structure — the only meaningful differences are the workspace metadata dict (no metadata → `DEFAULT_REGION` vs. `eu-central-1` in metadata → `"eu-central-1"`) and the resulting expected `workspace_region` value. Per the team's preference, these two cases would naturally belong together as a single `@pytest.mark.parametrize`-driven test. Similarly, `test_devbox_update_applies_when_outdated` only covers the `DEFAULT_REGION` path for `devbox_update`; a second parametrised case with non-default region metadata would confirm that path reads region from the workspace dict too.
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
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
When
coder updateruns against a workspace whose template has had itsworkspace_regionoption set modified since the workspace was created (e.g. the recent addition ofeu-central-1), Coder surfaces an interactive picker to select the new value. Per Coder's docs: "when template authors modify parameter options (add, remove, or substitute values), workspace users will be prompted to select the new value." Neither--use-parameter-defaultsnor--yesbypasses this picker — it's a parameter-collection prompt, not a confirmation. (For the same reason,coder createhad to start forwarding--presetexplicitly; see comment atcoder.py:33.)When the picker fires in an environment that can't deliver stdin — for example an IDE's read-only output channel — the command wedges with no way out. Reported in the wild this morning after a manual
hogli devbox:update.Note:
coder updatedoesn't even accept--yes(confirmed incoder/cli/update.go— it only registersparameterFlags.allOptions()andbflags.cliOptions(), neither of which containscliui.SkipPromptOption()). Earlier commits on this branch tried to add--yestocoder update; that would have broken the command outright with an unknown-flag error. Reverted.Changes
_pinned_region_param(workspace)incli.py: reads the workspace's current region from coder metadata, defaulting tous-east-1for boxes that predate the region metadata item._sync_workspace_parameters(name, workspace)now takes the workspace dict and merges the pinned region into the params dict — only when other params are being pushed, preserving the "skip when nothing to sync" fast path.devbox:updatealways merges the pinned region into its params dict (it always invokescoder update).coder.py:48rewritten to explain why region is forwarded on update — the previous comment's "immutable, so never forward on update" logic is what allowed the bug to land._run_with_param_retryalready handles the template-no-longer-declares-this-parameter case, so this is forward-compatible with template changes.(Earlier commits on this branch went through a Y/n gate on
devbox:startand an incorrect--yesaddition before landing on the actual fix. Cumulative branch diff against master is only the changes described above — happy to squash on merge.)How did you test this code?
I'm an agent. No manual run on a real devbox.
test_syncs_then_starts_when_stoppedandtest_devbox_update_applies_when_outdatedto assert the pinned region appears in the params dict.test_sync_pins_workspace_region_from_metadata_to_suppress_pickerexercising the metadata-driven region pin.test_update_paths_drop_unknown_params_and_retryalready covers the case where Coder rejects a forwarded parameter — confirmsworkspace_regionis dropped cleanly if the template removes it.test_devbox.pysuite: 241 passed.ruff check,ruff format --check, pre-commit (bin/hogli lint:python:fix,bin/hogli format:python,uv run ty check) all green.Publish to changelog?
no
Docs update
n/a
🤖 Agent context
/wtworktree skill,/code-reviewfor the calibration pass that surfaced the wrong-flag issue.devbox:startbased on a misread of the symptom, (2) adding--yestocoder updatebased on a misread of which Coder prompt was wedging. Both reverted on this branch. The actual mechanism is the rich-parameter picker that fires when a template's option set changes, which only goes away when callers forward the current value explicitly — same pattern as--preseton create.coder update's flag set by readingcoder/cli/update.goandcoder/cli/parameter.goupstream;--yesis not a valid flag for update (it's a per-command option attached viacliui.SkipPromptOption()on commands likestart/stop/restart/delete).coder updateondevbox:startto clear any pending parameter prompt proactively). Out of scope: that adds a Coder round-trip on every start without addressing a known wedge surface — left as a follow-up if reviewers want it.