| Previous finding | Round 5 assessment |
|---|---|
| R1-1: flat tenant borrows a nested socket | Fixed by the cgroup check (§5.4). |
| R1-2: aliases and path routes remain public | Fixed for attached aliases and path maps (§5.1). Platform-minted route rows present a separate classification gap below. |
| 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.5). |
| R2-1: stamp follows serving | Fixed by the admission barrier (§5.1). |
| R2-2: upgrade serves unclassified engines | Fixed by refusal of unclassified routes before listeners open (§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 | Ticket mechanism provided (§5.8); its probe-path source has a separate integration gap below. |
| 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), with historical compromise explicitly outside that guarantee. |
| 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 for the reported attack (§6.2). The arming predicate also rejects supported isolated routes; see below. |
| R4-2: path routing widens an engine grant | Fixed by exact-host engine dispatch without path routing (§5.4). |
| R4-3: watch tickets expire mid-watch | Fixed by renewal every four minutes (§5.8). |

Reviewed spec `50a1f3fc` against locally available amadan `origin/main` at `512baa59`. All implementation files cited below match that revision. No files changed.

1. **P2 — Platform-minted hostnames cannot complete classification (§5.1).**

   Start with an ordinary public instance and its automatically minted `<app>.<account>.<apps-domain>` hostname. Upgrade the edge. Both rows receive `NULL`, but the minted row has no live release of its own. Following the specified classifier leaves that hostname refused indefinitely, even with a healthy bucket and a readable source manifest.

   Platform domains are separate registry rows: `mintedRoute` copies the backend into a new `Platform: true` row without a version ([reconcile.go:881](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/domains/reconcile.go:881)). Adoption excludes those rows expressly because they have no independently executed live symlink ([adopt.go:1210](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/release/adopt.go:1210)). The manifest loader returns nothing when that hostname has no live version ([caps_pass.go:111](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/host/caps_pass.go:111)). These rows therefore do not inherit the primary upstream through the separate `route_aliases` fold described in §5.1.

   **Suggested fix:** Define how platform-minted rows resolve to their source route and share its classification and admission barrier. They must remain usable for public sources and become internal before an engine source activates.

2. **P2 — The arming predicate rejects isolated unit-backed routes (§6.2).**

   Put a granted nested caller and a DynamicUser-backed engine on the same box. Run `carlos engines arm`. Section 6.2 explicitly permits DynamicUser services, but its requirement that **every `instance` route classify `nested`** rejects the engine. The caller consequently receives no engine socket.

   Unit-backed capability routes are still `Kind == "instance"` ([adopt.go:1225](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/release/adopt.go:1225), [adopt.go:1265](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/release/adopt.go:1265)). Their standard socket is `/run/carlos/apps/<host>.sock` ([carlos-app@.socket:35](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/host/units/carlos-app@.socket:35)). `Classify` recognises only the flat and nested exec paths, so this route classifies `foreign` ([layout.go:103](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/activator/layout.go:103)). Platform-minted instance rows can fail the same test because they copy another hostname’s socket.

   **Suggested fix:** Apply the nested-layout requirement to tenant execution owners using the exec backend. Admit the explicitly permitted isolated unit-backed class separately, and assess generated aliases through their execution owner. Retain the refusal of actual foreign exec launches and workers.

3. **P2 — The home edge has no source for the specified deployment probe path (§5.8).**

   Configure an internal app’s build probe as `/healthz`, then deploy it. The CLI polls `/healthz`, but §5.8 permits only `/` or “the release’s declared probe path.” No such declaration exists in the release manifest, and the proposed ticket carries only hostname, version and expiry. The home edge cannot establish that `/healthz` is allowed.

   The console reads the probe from its app database and returns it with the ship response ([apicli.go:2114](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/console/apicli.go:2114), [apicli.go:2285](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/console/apicli.go:2285)). The CLI uses that value ([deploy.go:404](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/deploy.go:404)); `release.Manifest` contains no probe field ([release.go:47](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-fleet-internal-engines/internal/release/release.go:47)).

   **Suggested fix:** Include the authorized probe path in the signed watch ticket, sourced from the same configuration the watcher uses. Define the corresponding signed path for bucket-mode watches.

**Overall verdict: accept with fixes.** The round-4 security findings are addressed at spec level; these three integration gaps remain.