carlos / platform Public
Census approval: edge-asset-cache-2
Ruling census-ruling-edge-asset-cache-2. The rows carry it from the start (AGENTS.md, The census), so nothing flips after the approval.
Status: APPROVED by Paul, as census owner, in the session on 2026-10-24 (recorded on #280), on branch tip 7ab21e8f. Re-sealed at the merges with main b612e710 and 6c75ad81, which put wake-latency-2 and sec-mail-user-boundary in the chain first: the rows and fingerprints are unchanged, only the seal moved.
17 changes need a decision (below), which make census-propose cannot write. They are written by hand, following the overlays in the chain. Each is the census owner's call, not an approval. There are no approvals (body, sites): no existing unit changed.
What changed
The branch adds one new package, internal/assetcache: the edge asset cache's disk store. It keeps cached asset responses on a box's disk, under a budget and a free-space floor (spec docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md, §7). Nothing imports it yet. Plan 3 wires it into the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos) and opens it at $CARLOS_DATA_DIR/asset-cache.
A Store reads only files it wrote itself, in the one directory it is opened over (<id>.meta, <id>.<v>.body, <id>.<v>.gz and their temporaries), plus a statfs of that directory. No unit reads a record, a registry, a unit file or anything another component writes. None makes a root decision. A .meta that does not parse is deleted with its files, never trusted.
This card is refreshed for the final-review fix wave: admission order, the free-space sample race, the budget enforced at Open, and the retry of failed unlinks. Three units' bodies changed. Their reads did not:
Fill.commitreleases its reservation through the helper that ticks the release counter.Openevicts down to the budget after the scan.Store.scanindexes the oldestStoredAtfirst.
Their digests and @legacy fingerprints, the envelope and the seal are recomputed. No read was added or removed. The 17 rows are otherwise as before.
Decisions (the census owner's call)
Every row is class new. Proposed disposition for all 17: class legacy, task accepted-legacy, basis accepted-legacy;rev3=census-ruling-edge-asset-cache-2;asset cache files under $CARLOS_DATA_DIR/asset-cache, written and read only by this package. There is no cache class.
The last column says whether each site really touches a file or only matches one of the scanner's read names. Name matches only, with no real read: Open, Fill.commit (crypto/rand.Read) and both var Statfs. Fill.open's Read is also crypto/rand.Read.
| unit | class | reads | what it reads | real read? | |---|---|---|---|---| | store.go Open | new | +file:Open, +file:Statfs | nothing itself: Open is the function's own name, and Statfs is the variable it sets as the default FS. The listing is Store.scan | no, both name matches | | store.go Store.scan | new | +file:ReadDir | lists the cache directory at Open | yes | | store.go Store.loadMeta | new | +file:ReadFile | one <id>.meta during the scan | yes | | store.go Store.bodyMatches | new | +file:Stat | a body file's size during the scan, checked against its .meta | yes | | store.go Entry.Open | new | +file:Open ×2 | os.Open of a committed body (identity or gzip) to serve it | one real; the other is the method's own name | | store.go Reader.Read | new | +file:Read ×2 | reads the file Entry.Open opened | one real; the other is the method's own name | | store.go Reader.ReadAt | new | +file:ReadAt ×2 | reads the file Entry.Open opened | one real; the other is the method's own name | | store.go Reader.Stat | new | +file:Stat ×2 | stats the file Entry.Open opened | one real; the other is the method's own name | | fill.go Fill.open | new | +file:OpenFile, +file:Read | creates the body temporary (OEXCL, 0600) | OpenFile yes; Read is crypto/rand.Read, a name match | | fill.go Fill.writeGzip | new | +file:OpenFile | creates the gzip temporary (OEXCL, 0600) | yes | | fill.go Fill.commit | new | +file:Read | crypto/rand.Read, the version drawn per commit | no, name match only | | fill.go Fill.finish | new | +file:Lstat | the size of a temporary it is about to remove | yes | | fill.go writeSynced | new | +file:OpenFile | creates the .meta temporary (OEXCL, 0600) | yes | | fill.go syncDir | new | +file:Open | opens the cache directory to fsync it | yes | | `statfslinux.go statfsFS.Space | new | +file:Statfs | unix.Statfs of the cache directory, for the free-space floor | yes | | statfslinux.go var Statfs | new | +file:Statfs | the variable's name | no, name match only | | statfsother.go var Statfs | new | +file:Statfs | the variable's name; off Linux Space returns ErrUnsupported` and reads nothing | no, name match only |
Envelopes pinned: internal/assetcache (new, 93ba49fd3716984a753682f88739cdc3dc3efed459a0892c831a2232f7250ece).
Seal: 68ca9635da386f34ef483c790af19e954122c11edc406d64cde8d55d99d12de5 (sec-mail-user-boundary's) → de15b849fcb93b76caca55be924cde41512f8c470f40b4ebdd77ec65ad7e7069. Before the merge with 6c75ad81 it was 27b02059…ecd8 → fb7ba7c4…f8a1; before the merge with b612e710, 0ca3baaf…89f2 → 1fa408dd…6827.
Overlay: internal/provision/testdata/plan14-root-reads-edge-asset-cache-2.tsv, appended to internal/provision/testdata/plan14-root-reads-chain.tsv after plan14-root-reads-sec-mail-user-boundary.tsv (the last overlay on main at 6c75ad81), whose seal is checked first.
Record-write census (9B8): unchanged; the package writes no record keys. Claim routes: unchanged. go.mod: unchanged.
The question
Approve the 17 new rows as accepted legacy with the basis above, and the internal/assetcache envelope pin, or hold?