carlos / platform Public

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-floor update version, or a rollback whose History[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/dev release, or at or above the floor, blocks. TestTodaysFleetWithNoLayoutFieldKeepsRollbackAndUpdate seeds 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 Mode unmanaged with its instance rows judged by path shape (provision.NestedPaths), a journal or hold marker reading fenced; 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 migrate is 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. revert is never judged this way.
  • Box-side guard (host/systemapply.go): with nested, fenced or conflict rows present, the candidate is refused if it lacks data-instances.mount or its verified carlos version parses below v0.25.0, so a v0.20–v0.24.2 --file upload onto a nested box is refused at the box. An unparseable version is judged by its unit set alone; docs/site/cli.md says so.
  • Mints and the intent: host.mintLayoutIntent returns "" with no error when control/layout.json is absent, so a fleet with no intent mints flat; only a real read error, or an unreadable request, defers that pass's mints. Pinned by TestMintLayoutIntentAbsentIsFlatAndUnreadableIsAnError.

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.

Commits 0
Discussions 0 0 open
Tasks 0/0 done

Discussions

  • No discussions on this branch yet.

Tasks

  • No tasks yet.

Activity

  • No activity yet.