tenant-iso-plan5
Isolated exec, plan 5: the console door, carlos system layout, the downgrade guards, and nested minting (#126)
One commit (5f9186b2) on top of main 09814f7 (tenant-iso-hardening merged; its templates, instancectl and probe directives are untouched, the mountpoint inspection sits beside them). Round 3: the re-check approved ca4f13f7 with one fix, applied: unmanagedLayoutReport now reports a host with a layout journal or hold marker as fenced (it used to read a flat-pathed mid-move row as flat), with TestUnmanagedLayoutReportFencesAJournalledOrHeldHost; layout.HoldMarkerPresent is the new helper beside JournalPresent.
The floor (Paul's decision, 2026-10-06)
release.LayoutFloor = v0.25.0: the first release on which a nested row actually WAKES. v0.20.0 to v0.24.2 carry the instance mount units, so nested data is safe on them, but their carlos-edge.service still carries RestrictSUIDSGID=, which makes the agent's openat2 fail with ENOSYS, and a nested row never wakes there: an outage, not a safe state. Plan 4 (7b7d3026) dropped the line. No tag contains 7b7d3026 yet (latest v0.24.2), so v0.25.0 must be cut from a main that contains 7b7d3026. Pinned by TestLayoutFloorIsTheFirstReleaseWhereNestedRowsWake, which says why.
What the guards do
- Downgrade guard (
internal/console/layoutguard.go, both system doors): a named pre-floorupdateversion, or arollbackwhoseHistory[0]is pre-floor, is refused (409) while any box is stale, or reports a nested/fenced/conflict row, or is silent about its layout in a way the console cannot vouch for. Silence rule: a box with no layout field whose running release parses and is below v0.25.0 counts as flat (that build has no pass); silence from a sha/devrelease, or at or above the floor, blocks.TestTodaysFleetWithNoLayoutFieldKeepsRollbackAndUpdateseeds a v0.21.0–v0.24.2 fleet with no layout fields and rolls back and names an update. Hibernation-off boxes: a box with no activator publishes Modeunmanagedwith its instance rows judged by path shape (provision.NestedPaths), a journal or hold marker readingfenced; sound per layoutleg.go/agent.go:354-410 (the pass is armed only with an activator, nothing wakes a hibernate-flagged row without one, and a downgrade's hazard is about paths). - Migrate guard (
layoutMigrateBlocked):layout migrateis refused (409) while any in-scope box is stale, reports no release, runs a release below v0.25.0, runs an unplaceable one (sha/dev) and reports no layout, or (--box) has never reported. A sha box whose layout report is present passes.revertis never judged this way. - Box-side guard (
host/systemapply.go): with nested, fenced or conflict rows present, the candidate is refused if it lacksdata-instances.mountor its verifiedcarlos versionparses below v0.25.0, so a v0.20–v0.24.2--fileupload onto a nested box is refused at the box. An unparseable version is judged by its unit set alone;docs/site/cli.mdsays so. - Mints and the intent:
host.mintLayoutIntentreturns""with no error whencontrol/layout.jsonis absent, so a fleet with no intent mints flat; only a real read error, or an unreadable request, defers that pass's mints. Pinned byTestMintLayoutIntentAbsentIsFlatAndUnreadableIsAnError.
What changes
A. Plan 5: release.LayoutFloor, PreLayout, BelowFloor, RecordLayoutIntent; console door GET/POST /api/cli/system/layout (gate apiSystemRoller, bare 404 otherwise, empty role set, closedDoors 37 -> 39, audit, serial bump, force); #132 interlock on revert via console.Config.WorkerHeads (nil in production, TODO in layoutguard.go); carlos system layout migrate|revert|status [--box] [--force] [--yes]; docs/site/cli.md #### Instance layout; spec revision 16; instancectl Run seam and InspectMountpoints at start.
B. Mint nested on a nested box: provision.ReconcileConfig.Layout + routeFor(..., nested); carlos add nested defaults under a nested intent; carlos status --layout Mixed under a nested mode and the box-disagreement warning.
Region HA 1b note (#126)
The placer should refuse a relocation target whose status.layout.mode differs from the source's or the fleet intent, and the moves pass should treat a nested-to-non-nested landing as a refusal, not a flat mint. The reconciler-side mint is already right once the target is in scope.
How tested
Tests as named above and in the commit. gofmt -l . empty, go build ./..., go vet ./..., make test with no /tmp: 65 packages ok; failures only the known environment ones (socket path length in activator/edge/instanceexec; root package ~/.carlos/config tests), which fail on main here too.
Deliberately not done
Sidecar rows keep flat DBPaths; no placer-side refusal (1b not on main); no box-side revert refusal on a worker token (#132 has no store); layout-marks.json ruling stands. Nothing run on a box.
Copy for review: /home/paulca/.cache/tmp/claude-1001/tenant-audit/copy/plan5.md.
Discussions
- No discussions on this branch yet.
Tasks
- No tasks yet.
Activity
- No activity yet.