carlos / platform Public

console: a switch-off console reports one region available, so the CLI never prints C11 for a flag it ignores (final review, C11)

regions_available is what THIS create could use, not what the fleet has.
With CONSOLE_APP_REGIONS off, or no named home, every create lands on
the home and --region is ignored (C13b); the create response counted the
fleet's eligible regions anyway, so a no-flag create printed C11 and
invited a flag the console would ignore. The console now answers 1 when
appRegionsOn is false. Fixed console-side so older CLIs benefit; no CLI
string changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 0d0376ddceac7a36b14903903f875a3607693c8b parent 498b192
2 files changed, +32 −1
  • internal/console/apicli.go +11 −1
  • internal/console/regionclaim_test.go +21 −0
diff --git a/internal/console/apicli.go b/internal/console/apicli.go
index 7fa6c931a..0787152fb 100644
--- a/internal/console/apicli.go
+++ b/internal/console/apicli.go
@@ -483,6 +483,16 @@ func (s *Server) handleAPICreateApp(w http.ResponseWriter, r *http.Request) {
if ferr == nil {
cands = s.regionCands(files)
}
+ // regions_available is what THIS create could use, not what the
+ // fleet has. With the switch off (or no named home) every create
+ // lands on the home and --region is ignored (C13b), so there is
+ // one; a CLI that prints C11 at two or more then never invites a
+ // flag this console ignores. Fixed here rather than in the CLI so
+ // older CLIs benefit (final review, C11 on a switch-off console).
+ available := eligibleCount(cands)
+ if !s.appRegionsOn() {
+ available = 1
+ }
writeJSON(w, http.StatusOK, map[string]any{
"account": acct.Sqid, "app": name,
"url": s.cfg.Origin + "/a/" + url.PathEscape(acct.Sqid) + "/apps/" + url.PathEscape(name),
@@ -492,7 +502,7 @@ func (s *Server) handleAPICreateApp(w http.ResponseWriter, r *http.Request) {
"region": s.homeRegionOut(gotRegion),
"region_name": s.placeOf(gotRegion, cands),
"region_source": gotSource,
- "regions_available": eligibleCount(cands),
+ "regions_available": available,
})
default:
// Any future claimOutcome lands here rather than silently 200ing
diff --git a/internal/console/regionclaim_test.go b/internal/console/regionclaim_test.go
index 1da50338c..d8262ecee 100644
--- a/internal/console/regionclaim_test.go
+++ b/internal/console/regionclaim_test.go
@@ -248,6 +248,27 @@ func TestAPICreateAppSwitchOffIgnoresAnExplicitRegion(t *testing.T) {
}
}
+// Final review, C11 on a switch-off console: regions_available is what the
+// create could actually use. With the switch off every create lands on the
+// home and --region is ignored (C13b), so the answer is 1, and a CLI, old
+// or new, that prints C11 at two or more never invites a flag this console
+// ignores. The same fleet with the switch on still answers 2.
+func TestAPICreateAppSwitchOffReportsOneRegionAvailable(t *testing.T) {
+ fx, token := regionFixture(t)
+ if status, res := postJSON(t, newAppURL(fx), map[string]string{"name": "on"}, token); status != http.StatusOK || res["regions_available"] != 2.0 {
+ t.Fatalf("switch on = %d %v, want regions_available 2", status, res)
+ }
+ fx.srv.cfg.AppRegions = false
+ if status, res := postJSON(t, newAppURL(fx), map[string]string{"name": "off"}, token); status != http.StatusOK || res["regions_available"] != 1.0 {
+ t.Fatalf("switch off = %d %v, want regions_available 1", status, res)
+ }
+ // An unnamed home is the switch off too (appRegionsOn).
+ fx.srv.cfg.AppRegions, fx.srv.cfg.HomeRegion = true, ""
+ if status, res := postJSON(t, newAppURL(fx), map[string]string{"name": "unnamed"}, token); status != http.StatusOK || res["regions_available"] != 1.0 {
+ t.Fatalf("unnamed home = %d %v, want regions_available 1", status, res)
+ }
+}
+
// Defence in depth for future doors: an explicit code that is not a valid
// region never reaches the row.
func TestResolveNewAppRegionRejectsAGarbageExplicitCode(t *testing.T) {