carlos / platform Public

spec: fleet-internal engines rev 7 (Astra R6: 1 P1, 1 P2, both accepted)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev d59eec0caf36d47b4847e29bb4253b825ee4966e parent 3829dad
2 files changed, +81 −13
  • docs/superpowers/specs/2026-10-21-fleet-internal-engines-design.md +34 −13
  • docs/superpowers/specs/CODEX-FINDINGS-ENGINES-R6.md +47 −0

CI cancelled — superseded by a newer push — run details

CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok  	amadan.net/carlos/platform.git/launchctx	0.011s
?   	amadan.net/carlos/platform.git/launchctx/controlname	[no test files]
?   	amadan.net/carlos/platform.git/launchctx/wireid	[no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m

amadan: job cancelled — a newer push superseded it
diff --git a/docs/superpowers/specs/2026-10-21-fleet-internal-engines-design.md b/docs/superpowers/specs/2026-10-21-fleet-internal-engines-design.md
index 135b62e3a..de8d42a7e 100644
--- a/docs/superpowers/specs/2026-10-21-fleet-internal-engines-design.md
+++ b/docs/superpowers/specs/2026-10-21-fleet-internal-engines-design.md
@@ -1,9 +1,15 @@
# Fleet-internal engines: a doc engine nobody on the internet can call
**Date:** 2026-10-21
-**Revision:** 6.
+**Revision:** 7.
**Discussion:** amadan carlos/platform #335. Related: #328 (per-app egress allow).
+- **Rev 7** answers Astra round 6 (`CODEX-FINDINGS-ENGINES-R6.md`, reject,
+ a P1 and a P2 in rev 6's minted-row rule, both accepted). Inheritance is
+ scoped to minted `instance` rows, static and service platform rows keep
+ `0` (R6-2), and a `doc-engine` grant on a minted row marks its execution
+ owner, so the whole group goes internal together (R6-1). Marked
+ **(codex R6-n)**.
- **Rev 6** answers Astra round 5 (`CODEX-FINDINGS-ENGINES-R5.md`, accept
with fixes, three P2s, all accepted). Platform-minted rows take their
execution owner's mark and barrier (R5-1). Arming judges exec-backed
@@ -190,17 +196,27 @@ An `instance` route is classified from the manifest of its live release:
`1` if it declares `doc_engine`, `0` otherwise. The `doc-engine` grant also
sets `1`, whatever the manifest says. The edge treats `NULL` like `1`.
-**Platform-minted rows (codex R5-1).** A platform domain is its own
-registry row (`Platform: true`, `domains/reconcile.go:881`), copying the
-source's backend but no version, and adoption skips it
-(`release/adopt.go:1210`). Such a row never carries a mark of its own. Its
-**execution owner** is the non-platform `instance` row on the box with the
-same account, app and backend (`Socket`, or for a fleet-placed source the
-same `Region`); the edge resolves the owner at `Reload` and the row is
-internal exactly when its owner is. The admission epoch of §5.1's barrier
-is the owner's, so a minted row's in-flight requests are cancelled with the
-owner's. A minted row whose owner the edge cannot find is treated as `NULL`
-and refused, and logged by name.
+**Platform-minted rows (codex R5-1, R6-1, R6-2).** A platform domain is
+its own registry row (`Platform: true`, `domains/reconcile.go:881`),
+copying the source's kind and backend but no version, and adoption skips it
+(`release/adopt.go:1210`).
+
+- A minted `static` or `service` row (including a static canary on its own
+ channel, `reconcile.go:368`) is `0` by construction, like any row of
+ those kinds. The rest of this paragraph does not apply to it.
+- A minted `instance` row's **execution owner** is the non-platform
+ `instance` row on the box with the same account, app and backend
+ (`Socket`, or for a fleet-placed source the same `Region`). The edge
+ resolves owners at `Reload`.
+- The owner and every minted row that shares it form one **group** with
+ one mark and one admission epoch. The group is internal when the owner's
+ own classification is `1` **or any row in the group holds the
+ `doc-engine` grant**. The grant CLI already permits a grant on a plain
+ minted row (`cli.go:1432`); such a grant marks the whole group, and
+ `--grant` and `--revoke` on any row of the group run §5.1's barrier for
+ the group.
+- A minted `instance` row whose owner the edge cannot find is treated as
+ `NULL` and refused, and logged by name.
**Set before, clear after: the serving barrier (codex R2-1).** Adoption
repoints the live symlink (`release/adopt.go:1751`), restarts
@@ -656,7 +672,10 @@ process, real unix sockets and a real cgroup check where the kernel allows
refused, though the caller holds A's grant.
- A platform-minted hostname of an internal route is refused publicly and
admits engine calls exactly as the owner does; a minted hostname of a
- public route keeps working across the upgrade.
+ public route keeps working across the upgrade; a static platform domain
+ and a static canary keep serving.
+- A `doc-engine` grant on a minted row of a non-declaring release makes the
+ owner and every minted row internal, through the barrier.
- `carlos engines arm` succeeds on a box with nested callers and a
unit-backed engine.
- A watch with a probe of `/healthz` reads it with a ticket; the same
@@ -750,3 +769,5 @@ it, not only over a private network.
| R5-1 platform-minted rows never classify | Accepted: execution owner's mark and epoch (§5.1) |
| R5-2 arming rejects unit-backed routes | Accepted: exec-backed routes by layout, unit-backed by backing (§6.2) |
| R5-3 no source for the probe path | Accepted: the ticket signs the watcher's probe path (§5.8) |
+| R6-1 grant on a minted row ignored | Accepted: grants anywhere in the group mark the group (§5.1) |
+| R6-2 static platform domains refused | Accepted: inheritance only for minted instance rows (§5.1) |
diff --git a/docs/superpowers/specs/CODEX-FINDINGS-ENGINES-R6.md b/docs/superpowers/specs/CODEX-FINDINGS-ENGINES-R6.md
new file mode 100644
index 000000000..12ed34a20
--- /dev/null
+++ b/docs/superpowers/specs/CODEX-FINDINGS-ENGINES-R6.md
@@ -0,0 +1,47 @@
+| Previous finding | Round 6 assessment |
+|---|---|
+| R1-1: flat tenant borrows a nested socket | Fixed by the peer-cgroup check (§5.4). |
+| R1-2: aliases and path routes remain public | Fixed by checking the final upstream (§5.1). |
+| R1-3: new box starts public | Fixed by classification before serving and refusal of `NULL` (§5.1). |
+| R1-4: revoked grants return after restart | Fixed for retained local state; fresh-box replay remains explicitly accepted (§5.3). |
+| R1-5: door exceptions fail across routing | Resolved by removing the owner exception and defining the identity transition (§5.4). |
+| R1-6: socket lifecycle conflicts | Fixed by instance-level listener ownership (§5.4). |
+| R1-7: transport and body limits | Resolved at spec level (§§5.4–5.5). |
+| R2-1: stamp follows serving | Fixed by the admission barrier (§5.1). |
+| R2-2: upgrade serves unclassified engines | Fixed by classification before listeners and refusal of `NULL` (§5.1). |
+| R2-3: flat callers borrow door credentials | Fixed by the door’s UID restriction (§§5.4, 6.2). |
+| R2-4: deployment verification fails | Fixed by watch tickets (§5.8). |
+| R2-5: port-80 refusal cannot work remotely | Resolved by the narrowed contract (§5.1). |
+| R3-1: previously admitted requests cross the mark | Fixed: acknowledgement waits for cancellation and completion (§5.1). |
+| R3-2: flat tenant injects into a nested caller | Fixed at spec level by excluding unisolated execution while armed (§6.2); historical compromise remains explicitly excluded. |
+| R3-3: grant-only routes lack watch tickets | Fixed: every deploy target receives a ticket (§5.8). |
+| R4-1: foreign instances and workers remain unisolated | Fixed by the armed-state prerequisite and launch refusals (§6.2). |
+| R4-2: path routing widens an engine grant | Fixed by exact-host engine dispatch (§5.4). |
+| R4-3: watch tickets expire mid-watch | Fixed by renewal every four minutes (§5.8). |
+| R5-1: platform-minted hostnames cannot classify | Fixed for the reported socket-backed instance case by execution-owner inheritance (§5.1). Two new conflicts in that rule follow below. |
+| R5-2: arming rejects isolated unit-backed routes | Fixed by separating execution backing from exec layout (§6.2). |
+| R5-3: home edge lacks the probe path | Fixed by signing the watcher’s probe path, including bucket mode (§5.8). |
+
+Reviewed spec `3829dada` against locally available amadan `origin/main` at `aaa6a949`. The implementation files cited below match that revision. No files changed.
+
+1. **P1 — Execution-owner inheritance ignores a platform row’s own `doc-engine` grant (§5.1).**
+
+ Start with a unit-backed instance whose release does not declare `doc_engine`. Its plain platform-minted hostname copies that instance’s backend. Grant `doc-engine` to the minted hostname, then upgrade the edge.
+
+ The source instance classifies public. The new rule says the minted row has no mark of its own and is internal **exactly when its owner is**. Consequently, the granted hostname remains public, violating G1 and the preceding requirement that a grant sets `1` regardless of the manifest.
+
+ This grant is reachable through the existing CLI: `grantRail` refuses `Platform && Canary`, but permits a plain platform row with instance kind and unit backing ([cli.go:1432](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/cli.go:1432)). The grant updates only the named row ([registry.go:1640](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/registry/registry.go:1640)). Minting copies the source’s kind, backing and socket, so that row satisfies the CLI’s checks ([reconcile.go:881](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/domains/reconcile.go:881)).
+
+ **Suggested fix:** Define how grants on minted rows affect the execution owner. Aggregate existing grants into the owner’s internal classification and admission barrier, and make subsequent grant/revoke operations use that same ownership rule. An inherited public classification must never override an existing `doc-engine` grant.
+
+2. **P2 — The new execution-owner requirement refuses ordinary static platform domains (§5.1).**
+
+ Start with a static app and its automatically minted platform hostname. Upgrade using the new platform-row rule. The required non-platform `instance` owner does not exist: the source is `static`. The specified missing-owner outcome is `NULL` and refusal, so the platform hostname stops serving indefinitely. Static canary hostnames have the same problem.
+
+ These are supported route shapes. `firstReadyUpstream` explicitly selects static sources with a channel ([reconcile.go:829](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/domains/reconcile.go:829)); `mintedRoute` preserves their static kind and channel ([reconcile.go:881](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/domains/reconcile.go:881)). Canary minting specifically creates static rows on their own selected channel ([reconcile.go:368](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/domains/reconcile.go:368)). The edge serves these through its static handler ([edge.go:789](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/edge/edge.go:789)).
+
+ The earlier “static and service are `0` by construction” rule conflicts with this new unconditional treatment of platform rows.
+
+ **Suggested fix:** Scope execution-owner inheritance and missing-owner refusal to platform-minted instance rows. Preserve the explicit classification for static and service rows, including static canaries whose channel differs from their source.
+
+**Overall verdict: reject.** The new inheritance rule can leave a granted hostname public and can disable supported static platform domains.
\ No newline at end of file