carlos / platform Public

plan: console conversion extracted as restartWire for a pure test

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 3d8a7864e83f23dfed9a6417deeaeb900d97415c parent 5a4f100
1 file changed, +61 −1
  • docs/superpowers/plans/2026-09-07-named-unit-config-delivery.md +61 −1
diff --git a/docs/superpowers/plans/2026-09-07-named-unit-config-delivery.md b/docs/superpowers/plans/2026-09-07-named-unit-config-delivery.md
index 1d1d96459..eb4485101 100644
--- a/docs/superpowers/plans/2026-09-07-named-unit-config-delivery.md
+++ b/docs/superpowers/plans/2026-09-07-named-unit-config-delivery.md
@@ -2731,7 +2731,67 @@ Leave `restartCopyUnit` and the `Unit` fields in place (spec §3.4: an older con
- [ ] **Step 5: Console-side test**
-Find the console test that exercises `configRestartNotice` or decodes the config door's `restart` field (`grep -rn 'restart' internal/console/apiconfig_test.go` or the nearest `*_test.go` naming `apiConfigRestart`). Add one case that seeds the test registry with an un-opted addr route and a stamped socket route for the app, performs the write the door exposes, and asserts the decoded JSON has `undelivered: ["<host>"]` and one `blocked` entry whose `reason` contains `socket`. Follow that file's existing setup verbatim (server construction, registry path, bearer token).
+No console test names `apiConfigRestart` today, so extract the conversion into a pure function and test that. In `internal/console/apiconfig.go`, replace the tail of `configRestartNotice` (from `p := appconfig.AwaitingRestart(...)`) with:
+
+```go
+ return restartWire(appconfig.AwaitingRestart(ctx, s.cfg.Releases, routes, acct, app, envName, keys))
+}
+
+// restartWire is the wire shape of one RestartPending, Known: this box
+// looked. Pure, so the field-by-field copy is testable without a server.
+func restartWire(p appconfig.RestartPending) apiConfigRestart {
+ out := apiConfigRestart{Known: true, Unresolved: p.Unresolved, Undelivered: p.Undelivered}
+ for _, h := range p.Hosts {
+ out.Hosts = append(out.Hosts, apiConfigRestartHost{Host: h.Host, Unit: h.Unit})
+ }
+ for _, b := range p.Blocked {
+ out.Blocked = append(out.Blocked, apiConfigBlockedHost{Host: b.Host, Reason: b.Reason})
+ }
+ return out
+}
+```
+
+Create `internal/console/apiconfig_restart_test.go`:
+
+```go
+package console
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/appconfig"
+)
+
+func TestRestartWireCarriesEveryList(t *testing.T) {
+ got := restartWire(appconfig.RestartPending{
+ Hosts: []appconfig.RestartHost{{Host: "h", Unit: "u.service"}},
+ Unresolved: []string{"x"},
+ Undelivered: []string{"plain"},
+ Blocked: []appconfig.BlockedHost{{Host: "a", Reason: "socket"}},
+ })
+ raw, err := json.Marshal(got)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var back map[string]any
+ json.Unmarshal(raw, &back)
+ for _, k := range []string{"known", "hosts", "unresolved", "undelivered", "blocked"} {
+ if _, ok := back[k]; !ok {
+ t.Errorf("wire lacks %q: %s", k, raw)
+ }
+ }
+ // Empty lists are omitted so an older CLI sees exactly what it saw.
+ raw, _ = json.Marshal(restartWire(appconfig.RestartPending{}))
+ back = nil
+ json.Unmarshal(raw, &back)
+ for _, k := range []string{"undelivered", "blocked"} {
+ if _, ok := back[k]; ok {
+ t.Errorf("empty %q must be omitted: %s", k, raw)
+ }
+ }
+}
+```
- [ ] **Step 6: Run everything**