carlos / platform Public

Design: the replicator's authority, revision 3 (a VFS owning every file method; a barrier and an uncertainty, linked successors, recovery that terminates orphans; the retained stack for ascent, named-edge rechecks, repeatable listing, explicit link classes, the platform-link predicate kept apart; replication authority and lineage; a uid lifecycle from the unit observer; tests naming their events)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev b62b435a517fea7aca65fbeb72f9e4cb217e2ba4 parent ba681da
1 file changed, +62 −39
  • docs/superpowers/specs/2026-10-03-replicator-pinned-roots-design.md +62 −39

CI passed — run details

diff --git a/docs/superpowers/specs/2026-10-03-replicator-pinned-roots-design.md b/docs/superpowers/specs/2026-10-03-replicator-pinned-roots-design.md
index 4d6a213c8..635030881 100644
--- a/docs/superpowers/specs/2026-10-03-replicator-pinned-roots-design.md
+++ b/docs/superpowers/specs/2026-10-03-replicator-pinned-roots-design.md
@@ -1,6 +1,6 @@
# The replicator's authority: retained descriptors, a durable admission, claims by identity
-Date: 2026-10-03. Status: design, revision 2, for review (revision 1 was rejected by Astra on five P1s: SQLite canonicalises a `/proc` pathname before it opens anything and this driver passes no `nofollow`; `os.Root` confines but re-resolves every name, so a swap between a listing and an inspection still moves the answer; a `Start` row is not an admission, since the meter sends without one; the attempt-derived window lost a request completed before the change was noticed and the days between an admission and a finish; `closed_at` was not a handover; plus the directory open before `O_DIRECTORY`, per-owner holds the ledger cannot store, a uid with no producer, I3 against Part D, and tests). Branch `design-replicator-pinned-root`, off `feat/carloku-metered-replicator-20261001` at `e1280811`. It answers the eleven findings the twentieth review deferred (`DISPOSITIONS-metered-replicator.md`, review twenty) and keeps decisions 10 to 13 and approval H (`DECISIONS-FOR-PAUL.md`, section D, on the launch branch) as parameters. Nothing is built, wired or applied.
+Date: 2026-10-03. Status: design, revision 3, for review (revision 2 was rejected by Astra on three P1s: the VFS delegated SQLite's Unix file methods, which open the SHM and check moved files by pathname themselves; every settled admission wrote a permanent hold, so ordinary replication never read complete; a late owner-scoped extension did not reach successors that had already acknowledged; and six P2s: orphan admissions never terminated, `..` and chain edges unspecified, `dup` sharing the directory offset, the platform-link predicate not preserved and terminal links unclassified, the uid producer without a lifecycle, one billing owner not one replicator; each answered here. Revision 1 was rejected by Astra on five P1s: SQLite canonicalises a `/proc` pathname before it opens anything and this driver passes no `nofollow`; `os.Root` confines but re-resolves every name, so a swap between a listing and an inspection still moves the answer; a `Start` row is not an admission, since the meter sends without one; the attempt-derived window lost a request completed before the change was noticed and the days between an admission and a finish; `closed_at` was not a handover; plus the directory open before `O_DIRECTORY`, per-owner holds the ledger cannot store, a uid with no producer, I3 against Part D, and tests). Branch `design-replicator-pinned-root`, off `feat/carloku-metered-replicator-20261001` at `e1280811`. It answers the eleven findings the twentieth review deferred (`DISPOSITIONS-metered-replicator.md`, review twenty) and keeps decisions 10 to 13 and approval H (`DECISIONS-FOR-PAUL.md`, section D, on the launch branch) as parameters. Nothing is built, wired or applied.
## What stands today
@@ -8,79 +8,102 @@ The replicator (`internal/ops/litestream_metered.go`, `litestream_owners.go`; pa
## Three invariants, made precise
-**I1, identity through retained descriptors.** (a) *Containment*: no operation of the replicator or of litestream on a tenant's files resolves a pathname above the directory the fleet accepted for that file; (b) *retention*: the descriptor that listed a directory is the descriptor against which its entries are inspected, its links read, their targets classified and its files opened, for that look, so nothing between a listing and an inspection can move the answer; (c) *acceptance*: an owned file is opened by the descriptor of its accepted directory with no link followed in the last component, and the opened file's `(dev, ino)` equals the accepted facts before any use. What polling discovers later (a swap put back between two looks) is a change the fleet holds for; what (a) to (c) refuse is refused before any effect.
+**I1, identity through retained descriptors.** (a) *Containment*: no operation of the replicator or of litestream on a tenant's files resolves a pathname above the directory the fleet accepted for that file; (b) *retention*: the descriptor that listed a directory is the descriptor against which its entries are inspected, its links read, their targets classified and its files opened, for that look, so nothing between a listing and an inspection can move the answer; (c) *acceptance*: an owned file is opened by the descriptor of its accepted directory with no link followed in the last component, and the opened file's `(dev, ino)` equals the accepted facts before any use. Retention is authority over directories and checked identities, not a frozen inventory: entries inside a retained directory can change, and a swap put back between two looks is not detected by looking; what (a) to (c) promise is that no operation is steered by such a change, and that every change a look does see is held for. Ascent never uses the kernel's `..`: it pops the retained stack. Each acquisition compares what it opened with the facts of the entry it was acquired from, and each later look compares every named edge (parent descriptor, name) with the retained child's facts, so a moved or replaced component is seen as a change at the next look.
-**I2, a durable admission.** No request is sent until a row naming it (fleet, owner, admission instant) is durable; a day is not published complete while any admission that could intersect it is unsettled; the uncertainty interval of a change runs from the earlier of today's lower bound (the registry proof, the last clean look's start) and the earliest unsettled admission, minus the margin, until every admission of the fleet is settled, plus the margin; the hold a change creates is durable in the same transaction as its discovery; and a successor acknowledges a predecessor's window in a transaction of its own before it admits anything.
+**I2, a durable admission, two kinds of hold.** No request is sent until a row naming it (fleet, owner, admission instant) is durable. A *barrier* is temporary: a day is not published complete for an admission's owner while that admission is unsettled, and lifts when it settles. An *uncertainty* is permanent: an interval written when a fleet's authority is found changed, from the earlier of today's lower bound (the registry proof, the last clean look's start) and the earliest admission of the fleet then unsettled, minus the margin, open until every admission of the fleet is settled, then closed at the latest settlement plus the margin; it holds its days for the fleet's owners and for every owner linked to it (below). An admission that settles with no uncertainty open on its fleet writes nothing permanent: the ordinary day of an unchanged fleet becomes complete. Discovery and its first hold are recorded in one transaction, and if that transaction fails the fleet refuses every request until it succeeds (the barrier, not the uncertainty, covers the gap). A successor acknowledges a predecessor only when the predecessor is terminal, and the acknowledgement links the successor's owners to every uncertainty of the predecessor still open, so a late extension reaches them.
-**I3, one billing owner by file identity.** A file is replicated once and billed to one `(account, app)`; any number of routes of that one owner may claim it through any spelling; two owners on one `(dev, ino)`, whether the file is listed or skipped, whether a claimant is live or hibernating, make it unowned with every claimant named; every claimant's own authority check must pass; a claim with no identity yet (a spelling that resolves to nothing) is recorded as a claim and reconciled when it resolves; a required platform database that cannot be reached is an incomplete box.
+**I3, one billing owner and one replication authority by file identity.** A file is billed to one `(account, app)` and replicated by one authority (the external replicator, the activator's hibernation path, or this fleet; today the first two exist and the fleet is unwired); any number of routes of that one owner may claim it through any spelling; two owners on one `(dev, ino)`, or two replication authorities, whether the file is listed or skipped, whether a claimant is live or hibernating, make it unowned (or refused for this fleet) with every claimant named, until an explicit handover of authority exists; every claimant's own authority check must pass; a claim with no identity yet is recorded and reconciled when it resolves; identity grouping is a look, not a snapshot, and relaxes none of today's hard-link, sidecar or filesystem checks; a required platform database that cannot be reached is an incomplete box.
## Part A. Retained descriptors (Astra 2, 5, 6; Opus P2-2, P3-5)
**The primitive is a hand-walked, retained directory descriptor, not `os.Root`.** `os.Root` gives containment and re-resolves every name beneath its root; it follows links inside the root, `os.OpenRoot(path)` follows links in the path it is given, Go 1.26.5 walks per component with `openat` and there is no public constructor over a descriptor one has already verified. I1(b) and (c) need the descriptor itself. A small package, `internal/authority`:
-- `Dir`: a retained descriptor opened with `openat(parent, name, O_DIRECTORY|O_NOFOLLOW|O_RDONLY|O_CLOEXEC|O_NOCTTY)` (the kernel refuses a FIFO or device with `ENOTDIR` at lookup, before any open effect, which is the one existing directory-open test kept through the new shape), with its `(dev, ino, uid, mode)` read by `fstat` at acquisition and kept. Methods, each relative to this descriptor and none re-resolving a path: `Child(name) (*Dir, error)`; `List() ([]Entry, error)` (`fdopendir` on a `dup`, then `fstatat(fd, name, AT_SYMLINK_NOFOLLOW)` per entry); `Readlink(name)` (`readlinkat`); `Target(spelling)`, which classifies a captured link target by walking its components from this descriptor with `Child` (and `..` only while the walk stays at or beneath the root's depth, counted along the retained chain; a `..` that would leave the root is "a link out of the tree"), ending in `fstatat(..., AT_SYMLINK_NOFOLLOW)` of the last component, so a target that is itself a link is a link, not followed; `OpenRegular(name, looked)` (`openat(fd, name, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)` then `fstat`, refused unless regular and equal to `looked`'s `(dev, ino)`); `Facts()`.
+- `Dir`: a retained descriptor opened with `openat(parent, name, O_DIRECTORY|O_NOFOLLOW|O_RDONLY|O_CLOEXEC|O_NOCTTY)` (the kernel refuses a FIFO or device with `ENOTDIR` at lookup, before any open effect, which is the one existing directory-open test kept through the new shape), with its `(dev, ino, uid, mode)` read by `fstat` at acquisition and kept. Every method takes a basename (one component, not `.`, `..` or anything with a separator; anything else is refused before any syscall) and resolves it relative to this descriptor alone. `Child(name, expect) (*Dir, error)`: `openat` as above, then `fstat` compared with `expect` (the facts of the entry it is acquired from, when the caller has them); the child keeps a pointer to its parent `Dir` and its name, so the retained chain is a stack. `List() ([]Entry, error)`: a fresh open file description each time (`openat(fd, ".", O_DIRECTORY|O_RDONLY|O_CLOEXEC)`, `fstat`-compared with this descriptor, then `fdopendir` on it), never a `dup` (a `dup` shares the offset, so a second listing would start where the first ended); each entry's facts by `fstatat(fd, name, AT_SYMLINK_NOFOLLOW)`. `Readlink(name)`: `readlinkat`. `Walk(spelling)`: a captured link target's components, walked from this `Dir`: a leading run of `..` pops the retained stack (never `openat(fd, "..")`, whose answer follows a moved directory to its new parent) and is refused when the stack would pass the root; a `..` after a named component is refused; each named component is `Child`; the last component is `fstatat(..., AT_SYMLINK_NOFOLLOW)` and its kind is returned: directory, regular, link, other, absent, or error. `OpenRegular(name, looked)`: `openat(fd, name, O_RDONLY|O_NOFOLLOW|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)` then `fstat`, refused unless regular and equal to `looked`'s `(dev, ino)`. `Recheck()`: for this `Dir` and every ancestor on its stack, `fstatat(parent, name, AT_SYMLINK_NOFOLLOW)` compared with the retained child's facts; a difference anywhere is a changed edge. `Facts()`.
- `Root`: a `Dir` reached by a walk from `/` (`open("/")` then `Child` per component), each component required to be the platform's (root's or this process's user's), not writable by group or others; the walk's `(dev, ino)` list is the root's *ancestry*. A root is built once per fleet and kept; `lookNow` rebuilds the ancestry from `/` and compares it, and a difference is a change the fleet goes stale on.
-- Tenant roots: a unit route's tree is reached from a platform root through the link shape `resolvePlatformLinks` accepts today (a link whose own directory and whose target's parent are the platform's; the predicate is unchanged, it is only evaluated on descriptors: the link read with `Readlink` from its directory's `Dir`, the target walked with `Target` from a platform root, and the resulting `Dir` is the tenant root); a file claim's chain top is found as today (upward by ownership from the file's directory) but every directory of the chain is then acquired downward from the platform root as `Dir`s, and the chain's `(dev, ino)` list is kept with the file's facts. Astra 2's layout (a tenant-owned component above a platform-owned one) fails the platform walk; no root is built over it.
+- Tenant roots: a unit route's tree is reached from a platform root through the platform-link predicate exactly as `resolvePlatformLinks` has it today (the link itself the platform's, its directory the platform's, its target's `..` only in a leading run, the target's parent the platform's, no further link in the target), evaluated on descriptors: the link read with `Readlink` from its directory's `Dir`, its target walked with `Walk` from that directory, and the resulting `Dir` the tenant root; that predicate is one function, kept separate from the inventory's classification of links (below), and its restrictions do not change here. A file claim's chain top is found as today (upward by ownership from the file's directory) but every directory of the chain is then acquired downward from the platform root as `Dir`s, and the chain is the file's retained stack. Astra 2's layout (a tenant-owned component above a platform-owned one) fails the platform walk; no root is built over it.
-**Every inventory operation runs on `Dir`s**: `strictTreeDBs` takes a `*Dir`, lists with `List`, classifies a link's captured spelling with `Target` on the directory that listed it, descends with `Child`, and reads a header with `OpenRegular`. The `..` and namespace question for an isolated instance (its own mount namespace may resolve a spelling elsewhere) is unchanged in kind and stated in the inventory's rendering as before.
+**Every inventory operation runs on `Dir`s**: `strictTreeDBs` takes a `*Dir`, lists with `List`, descends with `Child(name, entry facts)`, reads a header with `OpenRegular`, and classifies a link's captured spelling with `Walk` on the directory that listed it. The classification is explicit and conservative, and nothing disappears through an unnamed case: a target that is a directory, or a link whose name is a database name, is "a link that may lead to a database" (a problem, as today); a regular file is a skipped link entry (as today); a target that is itself a link is "a link to a link that may lead to a database" (a problem; today's classification followed it, and the only honest replacement is to refuse rather than follow); a target outside the root is "a link out of the tree" (a problem); absent is churn (as today); any error is "a link whose target cannot be looked at" (as today). The namespace question for an isolated instance (its own mount namespace may resolve a spelling elsewhere) is a declared support condition before wiring: a route whose instance runs in its own mount namespace is classified in the agent's namespace and rendered as such, and until the condition is declared it is a refusal rule, not a silence.
-**Owned files keep their chain.** `fileFacts` gains the chain's `(dev, ino)` list and the retained `Dir` of the file's own directory lives for the fleet's life (one descriptor per owned file; a box has tens of databases, not thousands); every later look compares the chain through the retained descriptors and `fstatat` of the name, and litestream's opens (Part B) take that directory descriptor.
+**Owned files keep their chain.** `fileFacts` gains the retained `Dir` of the file's own directory, which lives for the fleet's life (one descriptor stack per owned file; a box has tens of databases, not thousands, and the count of retained descriptors is part of the fleet's rendering and a test's assertion); every later look runs `Recheck` on it and `fstatat` of the file's name, and litestream's opens (Part B) take that directory descriptor.
**What A does not claim.** A bind mount or a device node already inside a tenant's tree is reachable within containment; the design relies on unit routes having no `CAP_MKNOD` and no mount authority, which the bundled app template gives today and which is a stated property of supported units, not a proof for an arbitrary unit (a verification item and a line in the inventory's rendering per route). A swap put back between two looks is not detected by polling and is not claimed to be; what litestream has open meanwhile is bounded by Part B's identity checks.
## Part B. Litestream beneath the accepted directory (Astra 1)
-Two layers, and the second is the one revision 1 got wrong.
+Two layers.
-1. **The fork's own file operations** (`db.go`: the long-lived descriptor, WAL reads, shadow WAL, checkpoints, the `Stat`s of the database and its directory; `replica.go:186` and every LTX, temporary and cleanup path; enumerated in the plan's first task by reading, not by sampling) take two directory descriptors, `SetDataDir(*authority.Dir, name)` for the database's directory and `SetMetaDir(*authority.Dir)` for the platform's shadow-state directory, and become `openat`/`fstatat`/`renameat`/`unlinkat` relative to them with `O_NOFOLLOW`. `db.f` is opened first through `OpenRegular` against the accepted facts and its identity is the database's for the life of the `DB`; before every reopen or sidecar open the fork compares `fstatat(dirfd, name)` with that identity and refuses on a difference (an error the fleet treats as a change).
-2. **SQLite's own opens.** The library opens the database, journal, WAL and SHM by pathname through its VFS, after `xFullPathname` has canonicalised the pathname it was given; a `/proc/self/fd` spelling is canonicalised away, and the driver's URI handling passes no `nofollow`. So the connection is given a **descriptor-rooted VFS**: a VFS registered by the fork (the generated SQLite in `modernc.org/sqlite` exposes `sqlite3_vfs_register`; its `vfs` package already registers a Go-implemented VFS, which shows the route exists) whose `xFullPathname` returns the name unchanged, whose `xOpen` is `openat(dirfd, name, flags|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY)` for the main database, the journal, the WAL and the SHM (each derived name resolved against the same descriptor), whose `xAccess` and `xDelete` are `faccessat` and `unlinkat` on it, and whose locking, `xSync` and the rest delegate to the default Unix VFS's file methods on the descriptor it opened. The DSN is `file:<name>?vfs=carlos-dirfd-<id>`, and the `id` names the retained descriptor the fork registered for that `DB`. What this closes: every SQLite open of the database and its sidecars happens beneath the accepted directory with no link followed, including reopens, checkpoints and the first open's initialisation writes. What it leaves, stated: within its own directory the owner can still replace `<name>` or a sidecar with another regular file it owns between two of the library's opens; the fork's identity comparison before each of its own opens, and the VFS's `xOpen` comparing the opened file's `(dev, ino)` with the accepted facts for the main database (refusing otherwise), bound that to the sidecars, and a sidecar swapped under a live connection is a corruption the owner does to its own replica, which the design records as a verification item for litestream's own consistency checks rather than a billing question. Feasibility of the VFS on this driver is the plan's first task, a spike with a thrown-away result, before anything else of B is written.
+1. **The fork's own file operations** (`db.go`: the long-lived descriptor, WAL reads, shadow WAL, checkpoints, the `Stat`s of the database and its directory; `replica.go:186` and every LTX, temporary and cleanup path; enumerated in the plan's task by reading every call, not by sampling) take two retained directories, `SetDataDir(*authority.Dir, name)` for the database's directory and `SetMetaDir(*authority.Dir)` for the platform's shadow-state directory, and become `openat`/`fstatat`/`renameat`/`unlinkat` relative to them with `O_NOFOLLOW`; a sidecar is opened with `O_NONBLOCK` and refused unless `fstat` says regular (a FIFO put in a WAL's place is refused, not read). `db.f` is opened first through `OpenRegular` against the accepted facts and its identity is the database's for the life of the `DB`; before every reopen or sidecar open the fork compares `fstatat(dirfd, name)` with that identity and refuses on a difference (an error the fleet treats as a change).
-## Part C. The durable admission and the hold that survives exit (Astra 3, 4)
+2. **SQLite's own opens, through a VFS this design owns whole.** The library opens the database, journal, WAL and SHM by pathname through its VFS after `xFullPathname` has canonicalised what it was given, and the default Unix VFS's *file* methods also act by pathname on their own: `xShmMap` opens the `-shm` file by deriving its name from the file's stored path and calling `open` directly, the SHM's removal calls the syscall table directly, the moved-file check stats the stored path, and the directory sync opens the directory by path. So delegating file methods to the Unix VFS is not confinement, and revision 2's delegation is withdrawn. The connection is given a **descriptor-rooted VFS** whose `sqlite3_file` object and every method are this design's: `xFullPathname` returns the name unchanged; `xOpen` is `openat(dirfd, name, flags|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY)` for the main database and for each derived name (journal, WAL, SHM; `O_NONBLOCK` and a regular-file `fstat` for the sidecars), and for the main database compares the opened `(dev, ino)` with the accepted facts; `xAccess` and `xDelete` are `faccessat` and `unlinkat` on the descriptor; `xRead`, `xWrite`, `xTruncate`, `xSync`, `xFileSize` act on the descriptor; `xLock`, `xUnlock` and `xCheckReservedLock` are the POSIX advisory locks the Unix VFS uses, on the descriptor, with the same byte ranges, so the application's own connection and this one agree; `xShmMap`, `xShmLock`, `xShmBarrier` and `xShmUnmap` open the `-shm` through `openat` on the directory descriptor and `mmap` it, with the Unix VFS's lock byte layout, so the WAL index is shared correctly with the application; `xSync` of the directory is `fsync` of the retained directory descriptor; `xFileControl` answers the controls the library asks of a WAL-mode file (`SQLITE_FCNTL_PERSIST_WAL`, `SQLITE_FCNTL_POWERSAFE_OVERWRITE`, `SQLITE_FCNTL_SIZE_HINT`, `SQLITE_FCNTL_HAS_MOVED` answered from `fstatat(dirfd, name)` against the retained identity) and `SQLITE_NOTFOUND` for the rest; no method takes a pathname from the stored name after `xOpen`. The DSN is `file:<name>?vfs=carlos-dirfd-<id>` and the driver passes `vfs` through; the `id` names the retained descriptor the fork registered for that `DB`.
-**The admission is a row, written before the send.** The gate (`lease.RequestGate`) stops returning only an error: it returns an *admission*, `(fleet_id, owner, token, admitted_at)`, after committing a row in the durability ledger's own database (`admissions`: `token`, `fleet_id`, `owner account and app`, `admitted_at`, `settled_at` null, `how` null) with `synchronous=FULL`, within a bounded budget; if that write fails or times out, the request is refused (`ErrAdmissionNotDurable`), and litestream sees a failed upload and does not advance, as it does for a stale fleet. The meter's `Start` row references the token; `Finish` and `Abandon` settle the admission (`settled_at`, `how` = finished or abandoned) in the same transaction as the attempt's outcome. The transport's end is a settlement too: the SDK middleware's finalize step marks `transport_done_at` on the admission whether or not the recorder's workers are still running, and an admission is *settled* only when both the transport is done and the recorder has finished or abandoned. Admissions are the pending state the ledger already has for started attempts, moved to before the send and given an owner.
+What this closes: every open the library makes for the database and its sidecars, including reopens, checkpoints, the SHM and the first open's initialisation writes, happens beneath the accepted directory with no link followed and no pathname above it walked. What it leaves, stated: within its own directory a tenant can still replace `<name>` or a sidecar with another regular file it owns between two opens; the identity comparison at `xOpen` and before each of the fork's opens refuses the main database's replacement; a sidecar swapped under a live connection is a corruption of the replica, which litestream's own consistency checks are the place to catch and which the plan's task for the fork adds a test for. That residual is "the owner's own doing" only under decision 12 (a foreign user's directory inside a tenant's tree can supply sidecars today); until 12 is decided it is stated as a residual with two possible authors.
-**Completeness waits on admissions.** The ledger's completeness for a day already fails while a started attempt of that day is unfinished; an unsettled admission admitted on or before day `D` makes `D` not complete for its owner, and for the box when the hold is box-wide (Part C2), until it settles; a settled admission holds, for its owner, every UTC day from its `admitted_at` through its `transport_done_at` and `settled_at`, written at settlement in that transaction. The multiple-midnights sequence (admitted on the 2nd, sent on the 3rd, finished on the 4th) holds the 2nd, 3rd and 4th, because the 3rd was not publishable while the admission was unsettled and the settlement writes the whole interval.
+The VFS is the plan's first spike and it must prove, before anything else of Part B is written: registration from Go against this driver's generated API on amd64 and arm64; a database opened, written, checkpointed, closed and reopened through the VFS with a concurrent ordinary connection from the application side holding and releasing locks correctly; every file the library opened shown by `fstat` to be beneath the descriptor; SHM creation and removal through the VFS; the moved-file check; and the full list of the library's entry points that still take a pathname (expected: none for a connection opened with `SQLITE_OPEN_URI` and `vfs=`). The spike's result is a note, and if the spike fails on any of these the design's Part B is rewritten before the plan continues; Parts A, C and D do not wait on it.
-**The window of a change.** `goStaleFrom` keeps its lower bound (the earlier of the registry proof and the last clean look's start) and widens it: `from = min(that, earliest unsettled admitted_at of this fleet) - margin`; `to` is not a fixed instant but *open* until the fleet's admissions are all settled, and then `max(detection, latest transport_done_at and settled_at) + margin`. A request completed before the change was noticed (admitted at 23:58, finished at 23:58:20, the change at 23:58, detected at 00:02) is inside today's lower bound (the last clean look at 23:57 minus the margin) and is held as today; the design does not replace that bound, it widens it.
+## Part C. The durable admission, two kinds of hold, and a handover on disk (Astra 3, 4)
-**The fleet journal and the handover.** One row per fleet in the same database: `fleet_id`, `box`, `witness_generation`, `owners`, `opened_at`, `stale_from`, `stale_to` (null while open), `state` (`open`, `stale`, `closing`, `closed`), `predecessor`, `inherited_by` (null until a successor acknowledges). Transitions and what each writes, each a transaction: build writes the row `open` before any admission; `goStaleFrom` writes `stale` with `stale_from`, in the transaction that writes the recorders' holds for the days of `[from, now]`; `closeNow` writes `closing` when litestream has stopped, and `closed` only when every admission of the fleet is settled (workers quiesced: the recorder exposes a wait on its settlement, and `closeNow` waits, bounded, and if the bound passes the row stays `closing` with the late admissions unsettled, which recovery treats as open); a settlement that lands after the fleet is `stale` or `closing` widens `stale_to` and writes the interval's holds in its own transaction. A successor, at its build, reads every row of this box with `inherited_by` null (`closed` or not), holds each one's window (`[stale_from or opened_at - margin, stale_to or now + margin]`) for that fleet's owners and for its own, writes those holds and sets `inherited_by` to its own `fleet_id` in one transaction, and only then admits; a predecessor that is still `open` is also read at the successor's close, as today, and a window that grows after acknowledgement (a late settlement) is itself a row the next reader sees because the settlement writes the holds directly, not through the chain. Process start is the same reader with no predecessor pointer: every unacknowledged row is inherited. This closes Astra 4's exit and Astra 5-of-this-review's closed-but-undelivered row and late worker: the chain is on disk, acknowledgement is explicit, and settlements write holds themselves.
+**The admission is a row, written before the send.** The gate (`lease.RequestGate`) returns an *admission*, `(fleet_id, owner, token, admitted_at)`, after committing a row in the durability ledger's own database (`admissions`: `token`, `fleet_id`, `owner account and app`, `admitted_at`, `transport_done_at`, `settled_at`, `how`), `synchronous=FULL`, within a bounded budget; the gate waits for the commit. A commit that does not return within the budget refuses the request (`ErrAdmissionNotDurable`; litestream sees a failed upload and does not advance) and the goroutine that awaited it stays to see the commit land and then marks the row `how = unissued, settled_at = now` in its own transaction, so a late commit never authorises anything and never blocks a day; if the process dies between, recovery classifies the row as below. The meter's `Start` row carries the token (`Start` may still fail or be late, as today; what is now mandatory is the admission, not the `Start`). The transport's end marks `transport_done_at` from the SDK middleware's finalize step, whether or not the recorder's workers still run; `Finish` and `Abandon` write `settled_at` and `how` in the same transaction as the attempt's outcome; an admission is *settled* when both are present. Admissions are the ledger's pending state moved to before the send and given an owner.
-**Part C2, who is held.** The ledger's failure rows and `Incomplete` are box-wide today (`DurabilityClient.Incomplete` discards the client's identity; `CompletenessFor(account, …)` fails on any box failure). Per-owner holds are a ledger change: a `holds` table `(day, account, app or empty for the box, reason, written_at)`, the publisher's snapshot carrying them, and the reader treating a box-wide row as failing every owner and an owner row as failing that owner alone. The design specifies the table and the reader and keeps **the box-wide behaviour as the default**: decision 10 is whether a tenant's unacceptable file holds its own days or the box's, and until it is taken every hold this design writes is box-wide. It is not a switch today, and the design no longer says it is; it is the ledger change above plus the decision.
+**Two kinds of hold.** A *barrier* is the ledger's completeness rule: a day is not published complete for an admission's owner while an admission of that owner admitted on or before that day is unsettled (box-wide while Part C2's owner scope is not in use); it is a query over `admissions`, writes nothing, and lifts at settlement. An *uncertainty* is a row (`uncertainties`: `id`, `fleet_id`, `from`, `to` null while open, `reason`) written when a fleet's authority is found changed (by the witness, by `Recheck`, by a changed file), in the transaction that also writes the holds for the days of `[from, now]` for every owner the uncertainty reaches: `from = min(the registry proof, the last clean look's start, the earliest admitted_at of the fleet's admissions then unsettled) - margin`. While an uncertainty is open, settlements of that fleet's admissions extend it: each settlement, in its own transaction, writes the holds for the days of `[its admitted_at, its settled_at]` for every owner the uncertainty reaches, and the last settlement closes it (`to = that settlement + margin`). An admission that settles while no uncertainty of its fleet is open writes nothing permanent: the ordinary day of an unchanged fleet becomes complete when its barrier lifts. The multiple-midnights sequence (admitted on the 2nd, the change at 23:58:10, sent on the 3rd, finished on the 4th) holds the 2nd, 3rd and 4th through the settlement's interval; the request completed before the change was noticed is inside the lower bound as today. If the discovery transaction fails, the fleet refuses every request (`admit` answers stale) until it succeeds, and the barrier covers the gap.
-## Part D. Claims by identity and required coverage (Astra 7, 8, 10)
+**Who an uncertainty reaches.** Each uncertainty reaches its fleet's owners and every owner *linked* to it. A successor fleet, when it acknowledges a predecessor (below), links its own owners to every open uncertainty of that predecessor (`uncertainty_links`: `uncertainty_id`, `fleet_id`), in the acknowledgement's transaction; a later extension of that uncertainty writes holds for the linked fleet's owners too, and the barrier for a linked owner consults the predecessor's unsettled admissions as well as its own. That is Astra's October sequence under owner scope: Y, built at 23:58:20, links to A's open uncertainty; on the 3rd A's admission is unsettled and Y's day is barred through the link; on the 4th the settlement writes the 2nd to 4th for X and for Y.
-**Claims.** The inventory records claims as `(claimant route, spelling, kind)` and resolves each to an identity through the roots of Part A (a live unit's tree through its tenant root; a hibernating route's private spelling through the platform root with the same link predicate). Identity-bearing files (listed and skipped) are grouped by `(dev, ino)`; a skipped link contributes its own entry (for acceptance, as today) and, when its target resolves within a root, a claim on the target's identity. One identity with claimants of one `(account, app)` is owned by it and replicated once, every claimant's own authority check passing (as today); claimants of two owners make it unowned with all named; a claim whose spelling resolves to nothing is kept as a claim without identity, rendered, and reconciled on the look at which it resolves (it then conflicts or not like any other). This is I3 as written, and it keeps today's arrangement of several routes of one owner over one file.
+**The fleet journal and the handover.** One row per fleet (`fleets`: `fleet_id`, `box`, `witness_generation`, `owners`, `opened_at`, `state`, `predecessor`, `acknowledged_by`). States and the transaction each is written in: `open` at build, before any admission; `stale` when an uncertainty is opened; `closing` when litestream has stopped and the fleet has released its witness; `closed` when every admission of the fleet is settled (the recorder exposes a wait on settlement; `closeNow` waits, bounded, and past the bound the row stays `closing`, with its admissions still barring and its uncertainties still open: a late worker is a late settlement, and nothing about it is lost). A successor acknowledges a predecessor only when the predecessor is `closed`, or when the predecessor's process is gone (recovery, below); acknowledgement writes `acknowledged_by`, the links to the predecessor's open uncertainties, and holds for the predecessor's closed uncertainties the successor's owners have not yet been held for, in one transaction, before the successor admits anything. A `closed` predecessor with no uncertainty contributes nothing: routine replacement of a healthy fleet holds no day. A predecessor still `open` or `closing` when the successor is built is not acknowledged yet; the successor's barrier consults it (its unsettled admissions bar the successor's owners' days as linked), and acknowledgement happens when it closes, as `inheritHold` latches today, now on disk.
-**Required coverage.** The platform's required databases are a list: the registry this process has open, the console database when the box is a console box (the authoritative input is the agent's role configuration, not a glob), `CONSOLE_DB` when set. A required database unreachable through its root is a problem that makes the inventory incomplete and is written as a durable box-wide hold for the day, before and independent of whether a fleet is built. Before any cutover, a read-only operator command lists this inventory beside the external replicator's configuration.
+**Recovery at process start.** The ledger's writer lock (`flock`, already the ledger's) proves the previous process is gone. Then, in one transaction before any fleet is built: every admission of this box that is unsettled is classified `how = recovered-unknown, settled_at = now` and, since its fleet cannot settle it any other way, an uncertainty is opened and closed for it at once over `[admitted_at - margin, now + margin]` for its owner (box-wide while owner scope is not in use), so the day it could have touched is held and later days are not barred for ever; every fleet not `closed` is marked `closed` with an uncertainty over `[min(opened_at, its earliest admission) - margin, now + margin]` if it had none open, or its open uncertainty closed at `now + margin`; every fleet with no `acknowledged_by` is acknowledged by the first fleet the new process builds, with the links and holds above. Orphans therefore terminate, conservatively, and nothing blocks beyond its recovery.
-**Route identity (Astra 10, approval H).** Numeric uid equality is not authority; what is needed is a producer and a lifecycle. The design names them without choosing the policy: the activator, which starts units and knows the user each runs as, writes `route_uid` and `unit_incarnation` on the route row when a unit starts and clears them when it stops, under the ownership witness (the generation covers the new columns, so a change is a change); a tree or file claim is honoured only when the claim root's owning uid equals the route's recorded uid for a live incarnation; a hibernating route has none and claims only through the platform root's private spelling; which uids the platform's own workloads run as, and whether a root-run unit may claim, are `trustedUIDs` (empty) and approval H. The mechanism is design; the exceptions are the parameters.
+**Part C2, who is held.** The ledger's failure rows and `Incomplete` are box-wide today (`DurabilityClient.Incomplete` discards the client's identity; `CompletenessFor(account, …)` fails on any box failure). Owner-scoped holds are a ledger change: a `holds` table `(day, account, app or empty for the box, uncertainty_id, written_at)`, the publisher's snapshot carrying them, the reader treating a box-wide row as failing every owner and an owner row as failing that owner alone, and older readers of a published day seeing a box-wide incompleteness marker whenever any hold exists (so an older console never reads a held day as complete). The design specifies the table, the reader and the marker and keeps **box-wide the default**: every hold this design writes names the box until decision 10 is taken. Decision 10's implementation boundary is also stated, so it is not mistaken for a switch: per-tenant refusal means per-owner fleets (a fleet per `(account, app)`, each with its own witness view, uncertainties and holds, and a tenant's unacceptable file refusing only its fleet), which is a change to `MeteredFleetStore`'s shape beyond the holds table.
+
+## Part D. Claims, replication authority, required coverage, route identity (Astra 7, 8, 10)
+
+**Claims and owners.** The inventory records claims as `(claimant route, spelling, kind)` and resolves each to an identity through the roots of Part A (a live unit's tree through its tenant root; a hibernating route's private spelling through the platform root with the platform-link predicate). Identity-bearing files (listed and skipped) are grouped by `(dev, ino)`; a skipped link contributes its own entry (for acceptance, as today) and, when `Walk` resolves its target to a regular file within a root, a claim on that identity. One identity whose claimants are one `(account, app)` has that billing owner, every claimant's authority check passing (as today); claimants of two owners make it unowned with all named; a claim that resolves to nothing is kept as a claim without identity, rendered, and reconciled on the look at which it resolves.
+
+**Replication authority.** Separately from the owner, each identity has at most one replication authority: the external replicator (the box today), the activator's hibernation path (which replicates a hibernating exec route's database and holds its own stream), or this fleet. The fleet replicates an identity only when no other authority has it: a hibernating exec route whose database resolves to the same identity as a live unit tree's listed file is a conflict of authorities, refused for this fleet with both named, exactly as today's live/hibernating conflict is, until an explicit handover (a route's hibernation path releasing the database to the fleet) exists, which is not designed here. Deduplicating two spellings of one identity within the fleet is allowed only when both claimants are routes this fleet would replicate.
+
+**Lineage.** A replica key today is `(account, path)`. Under identity grouping the key is bound to `(owner, identity)` with the accepted spelling recorded beside it: another accepted spelling of the same identity reuses the key (one stream, as the identity is one file); a different identity under a previously accepted spelling is a new database and a new lineage (a new prefix) after the hold the change causes, never a continuation; the shadow state's key follows the same rule.
+
+**Required coverage.** The platform's required databases are a list: the registry this process has open, the console database when the agent's role configuration says the box is a console box, `CONSOLE_DB` when set. A required database unreachable through its root is a problem that makes the inventory incomplete and is written as a durable box-wide hold for the day before and independent of whether a fleet is built. Before any cutover, a read-only operator command lists this inventory beside the external replicator's configuration.
+
+**Route identity (Astra 10, approval H): a producer and a lifecycle, not a number.** The current whole-app backend starts a unit and checks its health; it reads no uid or invocation, units restart on their own (`Restart=always`, socket activation), and a stale pair would survive an autonomous restart. The design names the mechanism: the identity of a route's running workload is read from systemd, not inferred: the unit observer the activator already runs for isolated exec is extended to every unit route and reads, at every start, stop and restart it is told of (D-Bus `PropertiesChanged` on the unit, with a poll of `systemctl show -p InvocationID,MainPID,ActiveState` as the fallback), the `InvocationID` and the main process's uid from `/proc/<MainPID>/status`; it writes `route_uid` and `invocation_id` on the route row, under the ownership witness (the generation covers the columns), as a conditional write keyed on the previously recorded invocation (a write that finds another invocation recorded clears both and lets the next observation set them); it clears both at stop. A claim is honoured only when the route's recorded invocation is current (the observer's last reading agrees with systemd now) and the claim root's owning uid equals `route_uid`; unknown identity refuses the claim. Hibernation capability is a route property; a hibernating route that is asleep has no invocation and claims only through the platform root's private spelling; one that is awake has one and claims as a live unit. An exec or named-file claim of a non-unit route (the activator's own processes) is claimed under the activator's identity, which is a trusted workload and so a parameter. Which uids are the platform's own workloads, and whether a root-run unit may claim, are `trustedUIDs` (empty) and approval H.
## The parameters this design keeps open
| Parameter | Decision | What the build does until decided |
| --- | --- | --- |
-| A tenant's unacceptable file or link: refuse that tenant's replication and hold its days, or the box's. | 10 | Box-wide, as today; Part C2's owner holds are built so either answer is implementable, and the design does not call the change small. |
-| A tenant's database in a platform-owned directory. | 11 | Unowned and refused, as today; an operator `Accept` applies to skipped entries today, not to unowned ones, so acceptance by name is new mechanism to build if 11 says so. |
-| Another user's directory inside a tenant's tree. | 12 | Today's tree behaviour (walked; its databases listed under the tenant's claim); refusing it is a change decision 12 makes, not this design. |
-| Which uids are the platform's workloads; a root-run unit's claims. | 13, approval H | `trustedUIDs` empty: refused. |
-| The link shapes a tenant root may be reached through. | compatibility, not policy | Today's predicate, unchanged. |
-| An isolated instance's own mount namespace. | open (isolated exec, #126) | Classified in the agent's namespace through the root, stated per route. |
-
-## Tests, named against review twenty's counterfactuals (Astra 11)
-
-Each surviving counterfactual becomes an observable assertion with a controlled hook: the watch's `lookAgain` removed is caught by a test that advances a controlled clock through a watch tick and asserts the look ran (a counter on the fake clock's tick, not a direct call); shutdown is asserted by the recorder's settlement wait returning and by the count of open descriptors under `/proc/self/fd` matching the fleet's retained set before and after; both inode comparisons by a rename under the look at each of the two sites, through a hook between `List` and `OpenRegular`; the admission and latch interleavings by two goroutines on a barrier; a synchronised concurrent `Close`; the SQLite identity by a write through the connection followed by a checkpoint and a read through `db.f`, not by expecting bytes in the main file before a checkpoint. Part A: a platform ancestry with a tenant-owned, group-writable or linked component refused; a directory swapped between `List` and `Target` changes nothing; a listed subdirectory replaced by a FIFO fails `Child` with `ENOTDIR` and nothing blocks; a `..` out of the root refused. Part B: the VFS spike's own tests (every derived name opened beneath the descriptor; a WAL replaced by a link refused; a database replaced within its directory refused at reopen). Part C: an admission write that times out refuses the request and sends nothing; a `Start`-less send is impossible by construction (the middleware order); completeness of a day with an unsettled admission; the three-midnight interval; the fleet rows across build, stale, closing with a late settlement, closed, and inheritance after a kill at each transition, with the ledger reopened by a second process. Part D: the identity cases; a required database missing writes the hold without a fleet. Mutants in a tree copy with the killing test named, per part, after the assertions above exist.
+| A tenant's unacceptable file or link: refuse that tenant's replication and hold its days, or the box's. | 10 | Box-wide, as today. The owner-scoped holds (C2) are specified; per-tenant refusal also means per-owner fleets, a change to the fleet's shape, and the design says so rather than calling it a switch. |
+| A tenant's database in a platform-owned directory. | 11 | Unowned and refused, as today; `Accept` applies to skipped entries today, so acceptance by name of an unowned file is new mechanism if 11 says so. |
+| Another user's directory inside a tenant's tree. | 12 | Today's tree behaviour (walked; its databases listed under the tenant's claim); refusing it is 12's change, not this design's; Part B's sidecar residual has two possible authors until then. |
+| Which uids are the platform's workloads; a root-run unit's claims; the activator's own claims. | 13, approval H | `trustedUIDs` empty: refused. |
+| The link shapes a tenant root may be reached through. | compatibility, not policy | Today's predicate, kept as one function, unchanged. |
+| An isolated instance's own mount namespace; bind mounts and device nodes inside a tenant tree. | declared support conditions before wiring | A route outside the declared conditions is refused, not classified silently; the conditions are written in the inventory's rendering per route. |
+| Handover of a database from the activator's hibernation path to the fleet. | not designed | Refused as a conflict of authorities, as today. |
+
+## Tests, each naming the production event it observes and the mutation it kills (Astra 11)
+
+- **The watch looks.** A hook at the entry of `lookAgain` (a counter the fleet exposes to tests) with a controlled clock advanced through one watch interval: the counter moves. Kills: the watch's `lookAgain` call removed.
+- **The clean look's start.** A controlled clock pinned at a named instant for the look's start and a later instant for the change; `staleWindow().from` equals the start minus the margin. Kills: the start replaced by the end of the look.
+- **Both inode comparisons.** A barrier at each of the two sites by name, the cross-claim comparison (`litestream_owners.go:194` today: a second claim check reading another file) and the kept-facts grouping (`:217`: two owned paths that became one file), with a rename performed between the look and the comparison; each refuses with its own message. Kills: either comparison removed.
+- **Shadow state's root.** The shadow-state directory's platform walk refused on a tenant-owned, group-writable or linked component, in a test that touches no data directory. Kills: the walk skipped for the shadow root.
+- **Shutdown.** The recorder's settlement wait returns, the fork's `db.f` and every retained `Dir` are closed (asserted by identity: the fleet exposes its retained descriptors' `(dev, ino)` and the test confirms each is gone from `/proc/self/fd` by identity, not by count), and a request after `Close` is refused. Kills: a retained descriptor leaked; a worker not awaited.
+- **Interleavings.** `admit` against `lookAgain`, and `latch` against `inheritHold`, each on a two-goroutine barrier; a synchronised concurrent `Close`. Kills: the lock dropped at either site.
+- **Admission before send.** The middleware order makes an admission-less dispatch impossible: a fake gate that refuses sees no request on the wire; a gate whose commit is held past the budget refuses, the request is not sent, and the late commit's row is marked unissued. (A `Start`-less send remains possible, as today, and is not claimed otherwise.)
+- **Part A.** A platform ancestry with a tenant-owned, group-writable or linked component refused; a directory swapped between `List` and `Walk` changes nothing; a listed subdirectory replaced by a FIFO fails `Child` with `ENOTDIR` and nothing blocks; a `..` past the root, and a `..` after a named component, refused; a retained child moved under another parent is a changed edge at `Recheck`; `List` twice on one `Dir` gives the same entries; `Child(name, expect)` refuses when the entry changed between the listing and the acquisition; each link class classified as written and none silent.
+- **Part B.** The spike's own tests, then the fork's suite under the roots; a WAL replaced by a link or a FIFO refused; a database replaced within its directory refused at reopen; a concurrent application connection's locks honoured; the SQLite identity asserted by a write through the connection, a checkpoint, and a read through `db.f`.
+- **Part C.** A settled admission on an unchanged fleet writes no permanent hold and its day becomes complete; a change with an unsettled admission opens an uncertainty from the earlier bound; the three-midnight interval; a linked successor held by a late extension; the fleet rows across build, stale, closing with a late settlement, closed, and acknowledgement, with a kill at each transition and the ledger reopened by a second process, orphans classified and later days completing; a `closed` healthy predecessor contributing nothing.
+- **Part D.** The identity cases, the authority conflict (live tree and hibernating exec route on one identity), the lineage rule, a required database missing writing the hold without a fleet, a claim refused while the route's invocation is unknown or stale.
+- **Mutants** in a tree copy with the killing test named, per part, after the assertions above exist.
## Plan
-0. **Two spikes, results kept as notes and thrown-away code:** the descriptor-rooted VFS on `modernc.org/sqlite` (register, open a database and WAL through a `dirfd`, checkpoint, reopen; what the generated API allows and costs), and the admission protocol's cost on the request path (a `synchronous=FULL` commit per request against the ledger's current write rate). Each a day, each reviewed as a note.
-1. `internal/authority` (`Dir`, `Root`, the walk, the tests above) and the inventory on it (Parts A and D's identity grouping), the header read through `OpenRegular`.
-2. The admission and the fleet journal (Part C), the holds table and reader (C2, box-wide by default), the settlement wait at close.
-3. Claims by identity and required coverage (Part D).
-4. The fork beneath the accepted directories (Part B), on the spike's result.
-5. The route uid producer (the activator's columns under the witness), the parameter-dependent pieces last.
+0. **Two spikes, results kept as notes and thrown-away code:** the descriptor-rooted VFS on `modernc.org/sqlite` v1.55.0 proving registration on amd64 and arm64, a database and WAL opened, written, checkpointed, closed and reopened through it beside an ordinary application connection with correct locking, SHM created and removed through it, the moved-file check, every file `fstat`-shown beneath the descriptor, and the list of pathname entry points that remain; and the admission protocol's state transitions as a model (an ordinary complete day; a change with an unsettled admission; a late settlement after acknowledgement; a kill at each boundary) with the ledger's commit latency on a box's disk under the replicator's request rate. The VFS spike gates Part B only; the admission spike gates Part C.
+1. `internal/authority` (`Dir`, `Root`, the platform walk, the platform-link predicate on descriptors, `Walk`'s classes, the tests above) and the inventory on it, with the header read through `OpenRegular` (Part A).
+2. The admission, the two kinds of hold, the fleet journal, acknowledgement with links, recovery, and the holds table and reader with the older-reader marker (Part C and C2, box-wide by default).
+3. The uid lifecycle (the unit observer's columns under the witness) and the replication-authority and lineage rules (Part D's contracts), then claims by identity and required coverage on them.
+4. The fork beneath the accepted directories with the VFS (Part B), on the spike's result.
+5. The parameter-dependent pieces last, each only after its decision.
-Each task is its own reviewed commit with the full `internal/ops`, `internal/lease`, `internal/usage` and `internal/registry` run; the branch is reviewed by both readers; approval H stands before any wiring. Nothing is wired by this plan.
+Each task is its own reviewed commit with the full `internal/ops`, `internal/lease`, `internal/usage`, `internal/registry` and `internal/activator` run; the branch is reviewed by both readers; approval H stands before any wiring, and neither a spike nor a task is that approval. Nothing is wired by this plan.
## Questions for the reviewer
-A. Is the `Dir`/`Root` contract (retained descriptors, `Target` by component walk, `..` bounded by the chain's depth) sufficient for I1, and is anything in it a re-resolution in disguise? B. The descriptor-rooted VFS: is the method set (`xFullPathname` identity, `xOpen`/`xAccess`/`xDelete` on the descriptor, locking delegated) complete for SQLite's WAL mode on Linux, and does anything in the library's open sequence still take a pathname outside the VFS? C. Part C: is "admission before send, settlement after transport and recording, completeness waits on unsettled admissions, settlements write their own holds, successors acknowledge" closed under a kill at any instant, or name the UTC sequence it misses. D. Part C2: is the owner-scoped `holds` table the right shape for the reader, given box-wide failures must still fail every owner? E. Part D: a case the identity grouping misreads. F. The plan's order, and whether spike 0 should gate the rest.
+A. The `Dir` contract: is popping the retained stack for a leading `..`, refusing `..` after a name, `Child(name, expect)` and `Recheck` on named edges enough for I1 as now worded, or is there a re-resolution left? B. The VFS: is the method set complete for WAL mode beside an application connection on Linux, and is anything in the library's open sequence still a pathname outside it? C. Part C: the barrier, the uncertainty, the links and the recovery: name a kill instant or an owner-scoped sequence that leaves a day unheld or barred for ever. D. Part D: the replication-authority rule and the lineage rule: a case misread. E. The uid lifecycle: is the observer's conditional write and "unknown refuses" enough across autonomous restarts, or is there a window between a restart and the observation in which a claim is honoured under a stale pair? F. Anything in the parameters table that is mechanics, or the reverse. G. The order.