carlos / platform Public

Plan: the replicator's authority as tasks (the roots a fleet pins, the predicate and the inventory on Dirs, required coverage, Part C's ledger changes after the model)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 36b4805c2946364a0a48b05c2050e0774d530e9e parent 0a52792
1 file changed, +33 −0
  • docs/superpowers/plans/2026-10-03-replicator-authority-plan.md +33 −0

CI passed — run details

diff --git a/docs/superpowers/plans/2026-10-03-replicator-authority-plan.md b/docs/superpowers/plans/2026-10-03-replicator-authority-plan.md
new file mode 100644
index 000000000..61aa37ec7
--- /dev/null
+++ b/docs/superpowers/plans/2026-10-03-replicator-authority-plan.md
@@ -0,0 +1,33 @@
+# The replicator's authority: the task plan for the policy-independent parts
+
+Date: 2026-10-03. For `docs/superpowers/specs/2026-10-03-replicator-pinned-roots-design.md` (revision 9). This is the plan's steps 1 to 3 as tasks, each its own reviewed commit on `design-replicator-pinned-root`, each with the full `internal/ops`, `internal/lease`, `internal/usage`, `internal/registry` and `internal/activator` run. Step 0's admission model and step 1's first task (`internal/authority`) are done and under their third code review; the VFS spike (step 0's other half) needs a box with amd64 and arm64 and gates Part B only. Decisions 10 to 13 and approval H are parameters: nothing below chooses them, and nothing below is wired into a running fleet until the design's support conditions are declared or checked.
+
+## Task 1 (done): `internal/authority`
+
+`Dir`, `Root`, `Walk`, `Confine`, `Result.Pin`, the Part A tests, descriptor accounting. Reviews one and two answered; review three running.
+
+## Task 2: the inventory on `Dir`s (Part A's second half)
+
+**Which roots a fleet pins.** The design says a root is built once per fleet from `/` and kept, and that a tenant root is reached from a platform root through the platform-link predicate; it does not list the roots. The rule for this task: for every spelled directory the inventory is asked about (a unit route's `db_path` tree, the activator's data directory, the registry's and console's directories), the pinned platform root is **the parent of the first link's directory** when the spelling contains a platform link (`/var/lib/carlos-app/<host>` is a link in `/var/lib/carlos-app`, so the root is `/var/lib`, and systemd's `../private/carlos-app/<host>` pops from `carlos-app` to the root and no further), and **the parent of the spelled directory** when it contains none (a plain tenant directory under the data directory pins the data directory). `OpenRoot(slash, root, platform)` requires every component from `/` to the root to pass the platform rule, so a tenant-owned or group-writable component above (Astra 2's layout) builds no root. Roots are keyed by path and shared across the fleet's spellings; `Pins` carries them all with the pinned `/`.
+
+**The platform-link predicate on descriptors.** `resolvePlatformLinks(dir string)` becomes `platformDir(pins, dir string) (*authority.Dir, string)`: from the root's `Dir`, each remaining component is `Child(name, nil)`; a component that is a link (`ErrLink`) is read with `Readlink` from its directory's `Dir` and must satisfy exactly today's predicate (the link's directory the platform's, the link itself the platform's by `Lookat`'s facts, the target walked with `Walk(target, pins)`: relative from the link's directory, absolute from the pinned `/`, with `..` only in the leading run, which `Walk` enforces, no further link, which `Walk`'s `Link` class refuses, ending at a directory whose parent is the platform's); the result's `Dir` is the next component's parent and the walk continues beneath it. A tenant root so reached is `Confine`d once by the inventory before anything walks from it. The predicate's restrictions do not change; its error strings stay, because the Accept list and the rendering compare them.
+
+**`strictTreeDBs` on a `Dir`.** `strictTreeDBs(root string)` keeps its signature and its three string lists (paths spelled as today, `root` joined with the names the listing gave, so the Accept list and every existing test compare unchanged) and becomes a walk on `Dir`s: `List` for the entries; a subdirectory by `Child(name, &entry.Facts)` (a changed entry, `ENOTDIR`, `ErrLink` or absent is churn, as a vanished entry is today; any other error is "cannot be read"); a regular file's header by `OpenRegular(name, entry.Facts)`; a link's target by `Readlink` and `Walk(target, pins)` from the directory that listed it, classified by the design's explicit classes and nothing silent: `Directory`, or a database-named link, is "a link that may lead to a database"; `Regular` within the tenant's root (`Result.Pin == nil`) is a skipped link entry, as today; `Regular` under another pin (`Result.Pin != nil`) is "a link out of the tree"; `Link` is "a link to a link that may lead to a database" (today's classification followed it; this refuses rather than follows); `Other` is "a link to something that is neither a file nor a directory"; `Absent` is churn; `ErrAscentPastRoot`, `ErrOutside` and `ErrNotPlatform` are "a link out of the tree"; `ErrAscentAfterName`, `ErrNotDirectory` and every other error are "a link whose target cannot be looked at". Depth and dot-directory rules are unchanged. `statTarget` and `linktarget_*.go` are deleted.
+
+**`checkOwnedFile` on a chain.** The chain is acquired downward from the platform root as `Dir`s (the root, the predicate's result, each component by `Child`), never by `Lstat` of a joined path; each check it makes today (no link, one filesystem, a regular file with one name, the owner rules by kind, the `-wal`/`-shm`/`-journal` siblings regular with one name, by `Lookat` from the file's directory) is made on the retained chain; `fileFacts` gains the file's directory `Dir` (the design: one descriptor stack per owned file, counted in the fleet's rendering), kept for the fleet's life so every later look runs `Recheck` on it and `Lookat` of the file's name, and so litestream's opens (Part B, later) take it. `fleetInventory` closes the chains of files it does not keep.
+
+**The namespace condition.** A route whose instance runs in its own mount namespace is classified in the agent's namespace and rendered as such; until the support condition is declared it is a refusal rule (a problem naming the route), not a silence.
+
+**Tests.** Every existing owners test keeps passing with its strings; added, from the design's Part A list at the inventory level: each link class rendered as written and none silent (a directory target, a database-named link, a regular file in the tree, a regular file under another pin, a link to a link, a FIFO target, an absent target, an ascent past the tenant root, an absolute target outside every pin, a non-platform component in an absolute target); a tenant root reached through systemd's relative link shape and through an absolute one; Astra 2's layout refused at the root; a swap of the tenant directory between the listing and the classification changing nothing; the retained chain's `Recheck` at the next look reporting a moved or replaced directory; the descriptor count per fleet equal to the retained stacks' total.
+
+## Task 3: required coverage (Part D)
+
+The platform's required databases as a list (the registry this process has open, the console database when the role configuration says console box, `CONSOLE_DB` when set), each resolved through its root like any claim; one unreachable through its root is a problem that makes the inventory incomplete and is written as a durable box-wide hold for the day with today's `DurabilityClient.Hold` (box-wide is the default; owner scope is decision 10), before and independent of whether a fleet is built. A read-only operator command (`carlos ops replication inventory`, name subject to the operator CLI's conventions) lists the inventory beside the external replicator's configuration for the cutover comparison. Tests: a required database missing, replaced by a link, and reachable; the hold written once per day; the command's output against a fixture.
+
+## Task 4: Part C's ledger changes (after the model)
+
+The `admissions`, `uncertainties`, `fleets`, `inherited` and `holds` tables, the request gate's admission with the discovery mutex, the barrier, the latch and the replay, construction backfill, acknowledgement, the producer fence and recovery, exactly as the model has them (the model is the executable contract; each ledger test names the model test it mirrors), with the kill-at-every-transition tests the design lists. Box-wide holds by default.
+
+## Later, each behind its gate
+
+Part D's uid lifecycle and the sleeping binding (the unit observer extended), claims by identity, the lineage record; Part B on the VFS spike's result; the parameter-dependent pieces last, each only after its decision.