carlos / platform Public

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.json absent): nested, if and only if the box is ready. Ready means all of: the deployment's default is nested (CARLOS_LAYOUT_DEFAULT in host.env unset or nested); the running build is at or above release.LayoutFloor when 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 three nosymfollow mounts, and the control service's probe verdict. It is the same nestedGate the 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|flat in host.env, default nested, read with getenv like CARLOS_SYSTEM_CHANNEL. A typo stays flat and the status reason names it.
  • A recorded intent always wins: an explicit flat is the fleet-wide opt-out, an explicit nested behaves as today, --box scoping 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 default startupLayoutIntent returns IntentUnreadable without 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), which fastConvergeLoop does after startActivator has 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 add cannot 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 recorded flat wins 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.LayoutReport gains default and default_blocked (additive), carried by /api/cli/status/layout. carlos status --layout marks a box kass-1 (nested by default) and prints kass-2 is not nested by default: <reason>. carlos system layout status with 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).

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.