carlos / platform Public

console: the move mutation dispatcher: Phase 1, else the self-serve doors in self-serve mode, else legacy

handleAPIInstanceMoveRequest, Cut and Abort send Phase 1 on as today, the
self-serve body in self-serve mode, and the legacy body otherwise, byte for
byte. The three self-serve bodies run selfServeGate and, until Task 5
writes them, answer the family's 404. The status door is unchanged.
CARLOS_SELF_SERVE_MOVES reaches Config.SelfServeMoves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 35d1bdc53818168b67b7941d1a02874b32f4068e parent 78c8a87
3 files changed, +45 −0
  • cmd/console/main.go +3 −0
  • internal/console/apiinstancemove.go +18 −0
  • internal/console/selfserve_gate.go +24 −0
diff --git a/cmd/console/main.go b/cmd/console/main.go
index 6de4364ba..a6ce8575a 100644
--- a/cmd/console/main.go
+++ b/cmd/console/main.go
@@ -415,6 +415,9 @@ func serve() {
PlanCatalog: catalog,
TemporaryApps: os.Getenv("CARLOS_TEMPORARY_APPS") == "1",
LifetimesMigrate: os.Getenv("CARLOS_LIFETIMES_MIGRATE") == "1",
+ // CARLOS_SELF_SERVE_MOVES=offline is the self-serve offline moves
+ // switch (selfServeMode). Unset on every deployment today.
+ SelfServeMoves: strings.TrimSpace(os.Getenv("CARLOS_SELF_SERVE_MOVES")),
// CARLOS_ACME_DELEGATION_ZONE — the same variable the edge reads
// (internal/edge/wildcard.go's newWildcardFromEnv) for the same
// delegated-ACME story; NewServer normalizes it (lowercase, trim).
diff --git a/internal/console/apiinstancemove.go b/internal/console/apiinstancemove.go
index 2ac1ca6b4..16290e8bd 100644
--- a/internal/console/apiinstancemove.go
+++ b/internal/console/apiinstancemove.go
@@ -556,6 +556,12 @@ func moveGuardOf(rec *provision.Record) provision.MoveGuard {
// pass of Plan 5 Task 7 releases it.
func (s *Server) handleAPIInstanceMoveRequest(w http.ResponseWriter, r *http.Request) {
if !s.cfg.MovesEnabled {
+ // Self-serve mode makes this the self-serve door; outside it the
+ // legacy door answers, byte for byte.
+ if s.selfServeMode() {
+ s.selfServeMoveRequest(w, r)
+ return
+ }
s.legacyHandleAPIInstanceMoveRequest(w, r)
return
}
@@ -1015,6 +1021,12 @@ func (s *Server) settleFailedMoveWrite(w http.ResponseWriter, r *http.Request, c
// only be aborted (MV-N7 says so).
func (s *Server) handleAPIInstanceMoveCut(w http.ResponseWriter, r *http.Request) {
if !s.cfg.MovesEnabled {
+ // Self-serve mode makes this the self-serve door; outside it the
+ // legacy door answers, byte for byte.
+ if s.selfServeMode() {
+ s.selfServeMoveCut(w, r)
+ return
+ }
s.legacyHandleAPIInstanceMoveCut(w, r)
return
}
@@ -1046,6 +1058,12 @@ func (s *Server) handleAPIInstanceMoveCut(w http.ResponseWriter, r *http.Request
// changed" (final review I5). A stuck move keeps the grant's own answer.
func (s *Server) handleAPIInstanceMoveAbort(w http.ResponseWriter, r *http.Request) {
if !s.cfg.MovesEnabled {
+ // Self-serve mode makes this the self-serve door; outside it the
+ // legacy door answers, byte for byte.
+ if s.selfServeMode() {
+ s.selfServeMoveAbort(w, r)
+ return
+ }
s.legacyHandleAPIInstanceMoveAbort(w, r)
return
}
diff --git a/internal/console/selfserve_gate.go b/internal/console/selfserve_gate.go
index abbe666a8..f4da2636e 100644
--- a/internal/console/selfserve_gate.go
+++ b/internal/console/selfserve_gate.go
@@ -91,3 +91,27 @@ func (s *Server) instanceRails(w http.ResponseWriter, r *http.Request, acct *Acc
}
return true
}
+
+// The three self-serve door bodies. Task 5 writes them; until then each
+// answers the family's 404 once the gate has passed.
+
+func (s *Server) selfServeMoveRequest(w http.ResponseWriter, r *http.Request) {
+ if _, _, _, _, ok := s.selfServeGate(w, r); !ok {
+ return
+ }
+ http.NotFound(w, r)
+}
+
+func (s *Server) selfServeMoveCut(w http.ResponseWriter, r *http.Request) {
+ if _, _, _, _, ok := s.selfServeGate(w, r); !ok {
+ return
+ }
+ http.NotFound(w, r)
+}
+
+func (s *Server) selfServeMoveAbort(w http.ResponseWriter, r *http.Request) {
+ if _, _, _, _, ok := s.selfServeGate(w, r); !ok {
+ return
+ }
+ http.NotFound(w, r)
+}