carlos / platform Public

fleets v2: final-review fixes — audit shape, help verb, ActiveNav, pools recipe, Hardening heading

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 9cbc67a69777bb540f695bc76e771c4fc75c03c1 parent d52edf4
4 files changed, +17 −8
  • docs/superpowers/specs/2026-08-10-fleets-console-design.md +10 −3
  • internal/console/fleets.go +2 −1
  • internal/console/templates/fleet_byo.html +1 −1
  • main.go +4 −3
diff --git a/docs/superpowers/specs/2026-08-10-fleets-console-design.md b/docs/superpowers/specs/2026-08-10-fleets-console-design.md
index 8d04feed0..851b823c5 100644
--- a/docs/superpowers/specs/2026-08-10-fleets-console-design.md
+++ b/docs/superpowers/specs/2026-08-10-fleets-console-design.md
@@ -132,9 +132,16 @@ grammar is validated server-side (reject, don't sanitize).
1. **This branch** (stacked on #63): everything above. Merges after #63;
deploy = binary roll + console restart (new templates/endpoints).
-2. **Free-tier office box** (ops): office box joins with
- `CARLOS_POOLS=free`, free accounts' manifests get `pool: free`. Recipe in
- the BYO/ops docs; no code.
+2. **Free-tier office box** (ops): office box joins with `CARLOS_POOLS=free`
+ in its host env; free-tier apps are enabled operator-side with
+ `carlos instances enable -pool free` (store mode; signed-in mode refuses
+ `-pool`) so every instance record created under that app inherits
+ `pool: free` (`provision.Record.Pool`, stamped from the manifest at
+ create, `apiinstances.go`); `poolServed` at reconcile
+ (`internal/provision/reconcile.go`) then scopes that box's
+ provision/adopt passes to instances whose pool it actually serves, so the
+ office box only ever picks up free-tier instances. This paragraph is the
+ canonical recipe; no code change.
3. **Shared fleet build-out** (pinfra): `region-host` boxes for `us`, `ie`,
`uk`, `au`; console (control) pinned in the IE AZ. Region *placement
values* (`place=us|…`) remain future per v1 — day one, regions appear as
diff --git a/internal/console/fleets.go b/internal/console/fleets.go
index 6c51ca487..5d010fd6f 100644
--- a/internal/console/fleets.go
+++ b/internal/console/fleets.go
@@ -405,7 +405,7 @@ func (s *Server) handleAPIFleetTagBox(w http.ResponseWriter, r *http.Request) {
jsonError(w, http.StatusInternalServerError, "could not tag the box — try again")
return
}
- s.audit(acct, "", addr, "fleet", "tagged "+fleet.Name+"/"+label+" ["+tags+"] (cli)")
+ s.audit(acct, fleet.Name, addr, "fleet-tag-box", "tagged "+fleet.Name+"/"+label+" ["+tags+"] (cli)")
writeJSON(w, http.StatusOK, map[string]any{})
}
@@ -1071,6 +1071,7 @@ func (s *Server) handleFleetPage(w http.ResponseWriter, r *http.Request) {
}
p := s.accountPage(w, r, addr, raw, acct, role)
p.Title = fleet.Name
+ p.ActiveNav = "fleet"
p.FleetDetail = fleet
boxes, apps, warn := s.loadFleetPage(r.Context(), reg, acct, fleet)
p.FleetBoxes = boxes
diff --git a/internal/console/templates/fleet_byo.html b/internal/console/templates/fleet_byo.html
index 5fd76c0f2..5d88b38c2 100644
--- a/internal/console/templates/fleet_byo.html
+++ b/internal/console/templates/fleet_byo.html
@@ -39,7 +39,7 @@ CARLOS_TUNNEL_NAME=&lt;name&gt;/&lt;label&gt;</code></pre>
<code>CARLOS_TUNNEL_NAME</code>'s label half. <code>AWS_SHARED_CREDENTIALS_FILE</code> points at
an access key for the bucket above, written root-owned mode 600 alongside the env file.</p>
-<h2>Harden it</h2>
+<h2>Hardening</h2>
<ul>
<li>Run the agent as a dedicated non-root user, not root.</li>
<li>Make the env file root-owned, mode 600 — it holds the tunnel token.</li>
diff --git a/main.go b/main.go
index 56844d97b..c69f51ff7 100644
--- a/main.go
+++ b/main.go
@@ -142,9 +142,10 @@ Your deployment — stand up and administer boxes, routes and accounts
bootstrap prepare a host: units, dirs, user
accounts the tenancy primitive: create | list | migrate
fleets account-owned groups of remote boxes that dial this
- console: create | add-box | rotate-token | detach-box |
- ls — box tokens print exactly once, at mint or rotate,
- and a compromised box needs detach-box, not rotate-token
+ console: create | add-box | rotate-token | tag-box |
+ detach-box | ls — box tokens print exactly once, at mint
+ or rotate, and a compromised box needs detach-box, not
+ rotate-token
add route a hostname on this box to an app
remove drop one of this box's routes
route repoint a route's channel or config environment, grant or