tenant-iso-default-nested
Isolated exec: nested is the default layout on a box that is ready (#126)
One commit (2586c387) on top of tenant-iso-plan5 @ 5f9186b2 (so it carries plan 5 and lands after it). Paul's decision, 2026-10-06: nested becomes the default, not an opt-in. The reasoning is in the spec (§8.6 "Nested by default", revision 17, §13 R17) and summarised here. Round 3 after the re-check of e95ecf84 (approved, one low note): the startup kick, marked R3.
The design
- Effective intent when none is recorded (
control/layout.jsonabsent):nested, if and only if the box is ready. Ready means all of: the deployment's default is nested (CARLOS_LAYOUT_DEFAULTin host.env unset ornested); the running build is at or aboverelease.LayoutFloorwhen it can be placed (a build that evaluates this rule carries the pass by construction, so an unplaceable dev build passes, a mis-tagged release below the floor does not); and the nested gate answers:instancefs.SelfCheck, the threenosymfollowmounts, and the control service's probe verdict. It is the samenestedGatethe exec backend and the layout pass refuse nested work with. A box that is not ready behaves exactly as before the default (flat, mints flat) and says why in its status report. - Per-deployment switch:
CARLOS_LAYOUT_DEFAULT=nested|flatin host.env, default nested, read withgetenvlikeCARLOS_SYSTEM_CHANNEL. A typo stays flat and the status reason names it. - A recorded intent always wins: an explicit
flatis the fleet-wide opt-out, an explicitnestedbehaves as today,--boxscoping keeps box-by-box control. - Grace, holds, quarantine apply as under a recorded intent: the default converges with
Converge(nested, force=false), never forced. - Startup is fail-closed. At agent start the control service's probe has not run yet, so asking the gate there would say "not ready" on every start, and recovery under
""drops every hold marker and releases a completed revert. So under the nested defaultstartupLayoutIntentreturnsIntentUnreadablewithout asking the gate: holds and journals are kept, nothing is released flat. The opt-out keeps today's behaviour. - The first evaluation with the real gate answer does not wait for console traffic (R3). The leg is kicked once when it is built (
newLayoutLeg), whichfastConvergeLoopdoes afterstartActivatorhas returned, so the pass is armed by then; with no pass armed the kick reads nothing. And a run under the nested default that the gate refuses asks for the leg's own retry (awakeRetry, 10 minutes), so a quiet fleet re-asks the gate on its own; the opt-out and a typo wait on nothing and do not retry. Tests:TestNewLayoutLegKicksOnceWhenAPassIsArmed,TestLayoutLegRetriesWhileTheDefaultIsBlocked. No new strings. - The first mint after a restart. The reconciler's mint asks the gate; when the gate has not yet answered, a box whose registry already holds an activator-managed row at the nested paths counts as nested for mints (
mintLayoutIntentWith(ctx, store, reg.List)); the gate still guards every wake; a registry that cannot be listed defers the mint. - One resolver,
host.defaultLayoutIntent, for the serial leg and the mint;carlos addcannot reach the gate from an operator's shell, so with no intent it mints nested only when the registry already holds an activator-managed nested row; a recordedflatwins over that evidence. - Console guards: no new rule. They judge what a box reports (rows, running release), never the intent. Pinned by
TestLayoutGuardsTreatNestedByDefaultLikeAnIntent. - Status says which:
status.LayoutReportgainsdefaultanddefault_blocked(additive), carried by/api/cli/status/layout.carlos status --layoutmarks a boxkass-1 (nested by default)and printskass-2 is not nested by default: <reason>.carlos system layout statuswith no intent says what the default does and how to opt out or take control.
Rollout (also README's release-specific note for v0.25.0)
Migration starts unattended on the first serial move after v0.25.0 lands on a box and its isolation probe passes (and now also on the leg's startup kick and its 10-minute retry, so a quiet fleet migrates too). Asleep instances move at once; awake ones get an hour and are then stopped for their move. An instance whose move is refused for a reason a tenant could have planted is held down automatically. An operator who wants control acts BEFORE rolling: CARLOS_LAYOUT_DEFAULT=flat in host.env, or carlos system layout migrate --box <label>, or carlos system layout revert. A recorded intent always wins. v0.25.0 must be cut from a main that contains 7b7d3026.
Tests and gate
TestDefaultLayoutIntentRules; TestLayoutLegUsesTheDefaultWhenNoIntentIsRecorded; TestStartupAndMintReadTheDefault; TestNewLayoutPassArmsTheDefaultGate; TestNewLayoutLegKicksOnceWhenAPassIsArmed; TestLayoutLegRetriesWhileTheDefaultIsBlocked; TestAddMintsNestedFromTheBoxsOwnRowsWhenNoIntentIsRecorded; console TestLayoutGuardsTreatNestedByDefaultLikeAnIntent and API passthrough; CLI TestPrintStatusLayoutSaysNestedByDefaultAndWhyNot, TestPrintSystemLayoutStatus; the status contract test pins the two new keys. 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), which fail on main here too.
Deliberately not done
No console-written default (host.env is the switch). carlos add on a fresh box with no intent mints flat; the pass moves it. Nothing run on a box.
Copy for review: /home/paulca/.cache/tmp/claude-1001/tenant-audit/copy/default-nested.md (unchanged this round).
Discussions
- No discussions on this branch yet.
Tasks
- No tasks yet.
Activity
- No activity yet.