carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1# Census: the offline move's harness fixes (Run 9, defects 6 to 8)
2
3Status: RULED. Every row carries `rev3=PROPOSED-moves-offline-fixes`. The
4ruling is asked of the census owner, platform-1c.
5
6The branch is `moves-offline-fixes`, from main after 54ae7fb9 (v0.28.5). It
7fixes three defects the deployment harness found in the offline operator move
8(harness RUNLOG, Run 9). It adds one census overlay,
9`internal/provision/testdata/plan14-root-reads-moves-offline-fixes.tsv`,
10loaded last in `TestPlan14RootReadCensus`, after armed-box-updates. The
11record-write census (`TestPlan9B8RecordWriteCensus`) does not change: no
12record write is added or moved.
13
14## The footing
15
16Every unit in the overlay runs in the box agent (`/opt/carlos/carlos agent`,
17carlos-edge.service, `User=carlos`). None is reached from a root process, and
18none makes a root decision. So each is proposed accepted legacy at the
19disposition main gives it or its siblings: J1 (root-route) for registry and
20route reads, J4 (root-input) for file reads, J1,J4 where a unit does both.
21That is the footing census-ruling-moves-offline accepted for the offline
22move's own units.
23
24## The units, by defect
25
26### Defect 6: config.env for a nested row whose instance directory is not made yet
27
28| unit | change | executing identity | disposition |
29|---|---|---|---|
30| `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 |
31| `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 |
32| `internal/host/agent.go` `configGenLoop` | changed legacy: the tick's body moved into `configGenTick`; the registry listing stays | the agent | re-frozen, J1 |
33| `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`) |
34| `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`) |
35
36Envelopes re-pinned: `internal/appconfig`, `internal/host`.
37
38### Defect 7: fresh reports at every door step
39
40No unit row. The re-assert (`movesWorker.offlineReassert`, run by
41`offlineReassertLoop` in the agent every 15 s or so) reads the record from the
42deployment store and calls the source and sealer steps
43census-ruling-moves-offline already classified (`offlineSourceStop`,
44`offlineKeepStop`); it has no root read of its own. The console's stale-report
45refusal (MV-O178) reads nothing new. Envelopes re-pinned: `internal/console`,
46`internal/host`.
47
48### Defect 8: the source's scheduler wrote the moved host's env file after open
49
50The schedule runner is built only by the agent (`armSchedule`, from
51`runAgent`); no root process makes one.
52
53| unit | change | executing identity | disposition |
54|---|---|---|---|
55| `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 |
56| `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) |
57| `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 |
58| `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 |
59
60Envelopes re-pinned: `internal/host`, `internal/schedule`.
61
62### Fix round 1 (Astra's review)
63
64| finding | unit | change | executing identity | disposition |
65|---|---|---|---|---|
66| 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 |
67| 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`) |
68| 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 |
69| 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 |
70| 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 |
71
72
73## The seal
74
75The accepted-legacy rows add frozen declarations, so the legacy seal moves,
76from `393e7f45…bec29` (main, after moves-offline and armed-box-updates) to
77`edc04f7349acf2b9ea98ffc8a1d3b71516a6ddb95505abfc2e38e49fd802ccc2` (after fix round 1). The test
78checks main's seal before it loads this overlay, so a change on main's side
79still shows on its own.
80
81## What the ruling is asked to decide
82
831. That every unit above runs only in the agent and makes no root decision,
84 so accepted legacy at main's disposition is the right footing.
852. That `Runner.fire` keeps its class and task (hint, E2): the change only
86 withholds a token and a record for a host `Skip` names.
873. That the re-assert of defect 7 needs no row: it calls only steps already
88 classified under census-ruling-moves-offline.
89
90## Ruling (platform-1c, 2026-10-20): census-ruling-moves-offline-fixes, ACCEPTED as proposed
91
92Accepted 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.
93- After merging main 21850356 (install-console-upgrade, loaded before this overlay): internal/host envelope re-pinned to the combined tree; seal unchanged.
94