isolated-exec-layout
Plan 4 of #126: the box side of the layout move. It moves an activator-managed instance between the flat layout (uid carlos, shared /data) and the nested one (its own directory behind a mount namespace) and back, recoverably. Nothing on this branch makes a row nested without a recorded nested intent, and only plan 5's verb writes one, so merging changes nothing on any box.
What it adds
internal/layout: a per-host plan, a durable journal (O_EXCL, fsynced, replaced atomically), and preflight. Directories are created through openat2 fds with no symlink followed, and their mode and group come by inheritance and are checked.- The pass: - quiesces under a fence it shares with the #175 move worker; - completes a crashed move, then converges the host before releasing it; - is gated on the isolation probe; - defers awake hosts.
- The agent recovers at startup, after the unit sweep and before the activator starts, and runs a single-flight leg on each serial move. SyncExec, litestream and moves stay out of a journaled host. The intent is read from
control/layout.json, which the fleet store door now serves. - Status and console: - a per-box layout report on the private box snapshot; -
GET /api/cli/status/layout(operator only); - a Layout fact on the instance page; -carlos status --layout. - Downgrade guards:
system applyof a pre-layout release,carlos route --hibernate=false,carlos addand the reconciler all refuse a nested or journaled row.
How it was built
- 25 amendments from a drift audit against main (
docs/superpowers/plans/2026-09-25-isolated-exec-4-layout-amendments.md) take precedence over the 2026-09-12 plan. - Each task had a spec and quality review, with Opus on the security and concurrency tasks, then a whole-branch Fable review and one fix wave.
- The final review's Critical (EnsureDirs stripping setgid, because
carlosis not incarlos-sockets) was fixed and checked on dev ascarlosagainst the real/dataand/run/carlos. - CI passed on be185920.
Open before merge
internal/console/apistatuslayout.go:64still has an unreviewed error string with an em dash. The--layoutflag's one-line summary also awaits copy review.- After any agent restart, status reports layout mode
noneuntil the next serial bump. The fix is small: publish the intent asynchronously once the pass is armed.
Accepted residuals (spec §1.3/§3.3): during the transition, a same-uid flat tenant can release a nested neighbour flat by deleting or forging journals. It could already write the registry and read /data/.instances, so this gains it nothing.
#126 plan 4: the box side of layout migrate/revert (journal, CAS, fence, recovery, status field, downgrade guards). Nothing mints a nested row without a recorded intent.
Discussions
- No discussions on this branch yet.
Tasks 7/8 done
- Task 1: SetInstancePaths, Unfence, the intent object Done
- Task 2: the plan and the journal Done
- Task 3: preflight, directories, and the pass Done
- Task 4: agent wiring and the fenced consumers Done
- Task 5: status, console page, carlos status --layout Started
Activity
- claude agent, operated by paul@keymail.dev pushed 7a2e7904d Merge remote-tracking branch 'origin/main' into isolated-exec-layout
- task updated: Final whole-branch review
- claude agent, operated by paul@keymail.dev pushed be185920d host: the system apply header names what the layout guard reads under /data (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 4f967e70a provision: NestedPaths cleans both row paths before the prefix checks (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 8e518dd92 host: startup reads the layout intent only when a journal is there to recover (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 10a564edc layout: recovery at the row phase checks every destination before the CAS (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 6dd81eb60 cli, provision: the unflag and re-add guards also refuse a host with a layout journal (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed f0668be86 layout: preflight refuses a sidecar env another route owns as its instance env (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 41467752d layout: a revert completed while the isolation gate refuses is held, not released flat (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 006de0e17 layout: a fence kept after a failed handover is the pass's own, and retried (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed 9459d59b8 layout: a journal held under a move's fence says how to get out (plan 4 final review)
- claude agent, operated by paul@keymail.dev pushed ee6f2a6f6 layout: EnsureDirs relies on inheritance and verifies, never chmods or chowns (plan 4 final review)
- task updated: Task 6: the downgrade guards
- claude agent, operated by paul@keymail.dev pushed fa3c25f94 docs: carlos system names the pre-layout release refusal (plan 4, task 6)
- claude agent, operated by paul@keymail.dev pushed 53ee105e5 cli: route --hibernate=false and add refuse a host whose paths are nested (plan 4, task 6)
- claude agent, operated by paul@keymail.dev pushed d2686c252 host: system apply refuses a pre-layout release while a row is nested, fenced, in conflict or mid-move (plan 4, task 6)
- claude agent, operated by paul@keymail.dev pushed 70d7fd182 provision: NestedPaths, and the reconciler keeps a nested row flagged and calls its paths layout, not drift (plan 4, task 6)
- claude agent, operated by paul@keymail.dev pushed 80e1c69d8 cli: carlos status --layout, and its docs paragraph (plan 4, task 5, step 5)
- claude agent, operated by paul@keymail.dev pushed fddb8f846 console: the instance page's Layout fact (plan 4, task 5, step 4)
- claude agent, operated by paul@keymail.dev pushed 10db5c4b9 console: GET /api/cli/status/layout (plan 4, task 5, step 3)
- claude agent, operated by paul@keymail.dev pushed 08c4484f2 host: layoutStatusReport wires the armed pass into the status snapshot (plan 4, task 5, step 2)
- claude agent, operated by paul@keymail.dev pushed d16a8aeb2 status: the layout report on Box.Metrics (plan 4, task 5, step 1)
- task updated: Task 5: status, console page, carlos status --layout
- task updated: Task 4b: journal predicate in moves, store-door ACL for control/layout.json, unreadable intent marker
- claude agent, operated by paul@keymail.dev pushed 82d225452 host: published layout intent distinguishes unreadable from none
- claude agent, operated by paul@keymail.dev pushed 945acac37 edge: store door grants a read of the fleet's layout intent
- claude agent, operated by paul@keymail.dev pushed 7075fe198 host: moves worker uses the shared JournalPresent predicate
- task updated: Task 4: agent wiring and the fenced consumers
- claude agent, operated by paul@keymail.dev added task Task 4b: journal predicate in moves, store-door ACL for control/layout.json, unreadable intent marker
- claude agent, operated by paul@keymail.dev pushed 24240be25 agent: the layout pass at start and on every serial move