carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

Census: the offline move's harness fixes (Run 9, defects 6 to 8)

Status: RULED. Every row carries rev3=PROPOSED-moves-offline-fixes. The ruling is asked of the census owner, platform-1c.

The branch is moves-offline-fixes, from main after 54ae7fb9 (v0.28.5). It fixes three defects the deployment harness found in the offline operator move (harness RUNLOG, Run 9). It adds one census overlay, internal/provision/testdata/plan14-root-reads-moves-offline-fixes.tsv, loaded last in TestPlan14RootReadCensus, after armed-box-updates. The record-write census (TestPlan9B8RecordWriteCensus) does not change: no record write is added or moved.

The footing

Every unit in the overlay runs in the box agent (/opt/carlos/carlos agent, carlos-edge.service, User=carlos). None is reached from a root process, and none makes a root decision. So each is proposed accepted legacy at the disposition main gives it or its siblings: J1 (root-route) for registry and route reads, J4 (root-input) for file reads, J1,J4 where a unit does both. That is the footing census-ruling-moves-offline accepted for the offline move's own units.

The units, by defect

Defect 6: config.env for a nested row whose instance directory is not made yet

| unit | change | executing identity | disposition | |---|---|---|---| | internal/appconfig/syncexec.go SyncExecWithCallbacks | changed legacy: a write that found no instance directory is named and skipped (errInstanceDirAbsent, WhenInstanceDirAbsent), and the pass goes on; no new read site | the agent, through syncExecSerialized (config loops) | re-frozen, J1,J4 | | internal/appconfig/syncexec.go renderExecConfigBefore | changed legacy: one Lstat of the nested row's instance directory after its write failed, to tell "not made yet" from any other failure; follows no link | the agent: config sync and the moves worker's held render | re-frozen, J1,J4 | | internal/host/agent.go configGenLoop | changed legacy: the tick's body moved into configGenTick; the registry listing stays | the agent | re-frozen, J1 | | internal/host/agent.go configGenTick | new: configGenLoop's tick over the routes it listed; also runs the agent's own config pass once a directory the last pass waited for exists | the agent | accepted legacy, J1 (as configGenLoop) | | internal/host/agent.go pendingDirs.appeared | new: an Lstat (never follows a link) of the instance directories the last config pass could not write into | the agent | accepted legacy, J4 (as the moves units' isDir, lexists) |

Envelopes re-pinned: internal/appconfig, internal/host.

Defect 7: fresh reports at every door step

No unit row. The re-assert (movesWorker.offlineReassert, run by offlineReassertLoop in the agent every 15 s or so) reads the record from the deployment store and calls the source and sealer steps census-ruling-moves-offline already classified (offlineSourceStop, offlineKeepStop); it has no root read of its own. The console's stale-report refusal (MV-O178) reads nothing new. Envelopes re-pinned: internal/console, internal/host.

Defect 8: the source's scheduler wrote the moved host's env file after open

The schedule runner is built only by the agent (armSchedule, from runAgent); no root process makes one.

| unit | change | executing identity | disposition | |---|---|---|---| | internal/host/schedule_wiring.go newScheduleDeps | changed legacy: the runner's Skip is set to scheduleSkip; no new read site | the agent | re-frozen, J1 | | internal/host/schedule_wiring.go scheduleSkip | new: reads a row's status (any hold) and host (the armed offline view says the record names another region) to tell the runner to leave the host alone; it only withholds a tick | the agent's schedule runner | accepted legacy, J1 (as the runner's own hold checks) | | internal/schedule/runner.go Runner.Tick | changed legacy: a host Skip names gets no tick and no bookkeeping at the pre-filter | the agent's schedule runner | re-frozen at census-ruling-seeded-instances' disposition | | internal/schedule/runner.go Runner.fire | re-pinned: with Skip set, the row is read again before the token, and a skipped host gets no token and no record | the agent's schedule runner (overlay e names the service controller and root callbacks for the claim design; neither sets Skip) | hint, E2, unchanged |

Envelopes re-pinned: internal/host, internal/schedule.

Fix round 1 (Astra's review)

| finding | unit | change | executing identity | disposition | |---|---|---|---|---| | 1 | internal/schedule/runner.go Runner.Tick | re-pinned: its due query moved into Runner.dueRows | the agent's schedule runner | re-frozen, as above | | 1 | internal/schedule/runner.go Runner.dueRows | new: held hosts left out by the query when Skip is set, and hosts Skip names paged past before the limit (one row read per host in the batch) | the agent's schedule runner | accepted legacy, J1 (as Runner.Tick) | | 2 | none | the refresh calls offlineSealerRefresh (seal, lease and source reports read, only the report written, the lease never), no root read of its own | the agent | envelope internal/host only | | 3 | internal/appconfig/syncexec.go SyncExecWithCallbacks | re-pinned: names each in-scope host done or not once the pass has gone through every route (WithHostOutcome); no new read site | the agent | re-frozen, J1,J4 | | 3 | internal/host/agent.go pendingDirs.appeared | re-pinned: the same Lstat, with a retry backoff for a host a pass left undone | the agent | re-frozen, J4 |

The seal

The accepted-legacy rows add frozen declarations, so the legacy seal moves, from 393e7f45…bec29 (main, after moves-offline and armed-box-updates) to edc04f7349acf2b9ea98ffc8a1d3b71516a6ddb95505abfc2e38e49fd802ccc2 (after fix round 1). The test checks main's seal before it loads this overlay, so a change on main's side still shows on its own.

What the ruling is asked to decide

  1. That every unit above runs only in the agent and makes no root decision, so accepted legacy at main's disposition is the right footing.
  2. That Runner.fire keeps its class and task (hint, E2): the change only withholds a token and a record for a host Skip names.
  3. That the re-assert of defect 7 needs no row: it calls only steps already classified under census-ruling-moves-offline.

Ruling (platform-1c, 2026-10-20): census-ruling-moves-offline-fixes, ACCEPTED as proposed

Accepted at d75b7e0b (F1 to F4) and re-ruled for fix round 1 at 7cd5db4d (F5 to F7). After Astra's scoped re-review, the backoff counter saturates (agent.go pendingDirs.record): an internal/host envelope re-pin only. The rev3 tag was rewritten to the ruling's name, so the seal moves to 826c54be…a62f.

  • After merging main 21850356 (install-console-upgrade, loaded before this overlay): internal/host envelope re-pinned to the combined tree; seal unchanged.