carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1# Census approval: edge-asset-cache-2
2
3Ruling `census-ruling-edge-asset-cache-2`. The rows carry it from the
4start (AGENTS.md, The census), so nothing flips after the approval.
5
6Status: APPROVED by Paul, as census owner, in the session on 2026-10-24
7(recorded on #280), on branch tip 7ab21e8f. Re-sealed at the merges with
8main b612e710 and 6c75ad81, which put wake-latency-2 and
9sec-mail-user-boundary in the chain first: the rows and fingerprints are
10unchanged, only the seal moved.
11
1217 changes need a decision (below), which `make census-propose` cannot
13write. They are written by hand, following the overlays in the chain. Each
14is the census owner's call, not an approval. There are no approvals
15(`body`, `sites`): no existing unit changed.
16
17## What changed
18
19The branch adds one new package, `internal/assetcache`: the edge asset
20cache's disk store. It keeps cached asset responses on a box's disk, under
21a budget and a free-space floor (spec
22`docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md`, §7).
23Nothing imports it yet. Plan 3 wires it into the agent
24(`/opt/carlos/carlos agent`, `carlos-edge.service`, user carlos) and opens
25it at `$CARLOS_DATA_DIR/asset-cache`.
26
27A `Store` reads only files it wrote itself, in the one directory it is
28opened over (`<id>.meta`, `<id>.<v>.body`, `<id>.<v>.gz` and their
29temporaries), plus a statfs of that directory. No unit reads a record, a
30registry, a unit file or anything another component writes. None makes a
31root decision. A `.meta` that does not parse is deleted with its files,
32never trusted.
33
34This card is refreshed for the final-review fix wave: admission order,
35the free-space sample race, the budget enforced at `Open`, and the retry
36of failed unlinks. Three units' bodies changed. Their reads did not:
37
38- `Fill.commit` releases its reservation through the helper that ticks
39 the release counter.
40- `Open` evicts down to the budget after the scan.
41- `Store.scan` indexes the oldest `StoredAt` first.
42
43Their digests and `@legacy` fingerprints, the envelope and the seal are
44recomputed. No read was added or removed. The 17 rows are otherwise as
45before.
46
47## Decisions (the census owner's call)
48
49Every row is class `new`. Proposed disposition for all 17: class `legacy`,
50task `accepted-legacy`, basis
51`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`.
52There is no `cache` class.
53
54The last column says whether each site really touches a file or only matches
55one of the scanner's read names. Name matches only, with no real read: `Open`,
56`Fill.commit` (`crypto/rand.Read`) and both `var Statfs`. `Fill.open`'s
57`Read` is also `crypto/rand.Read`.
58
59| unit | class | reads | what it reads | real read? |
60|---|---|---|---|---|
61| `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 |
62| `store.go` `Store.scan` | new | +file:ReadDir | lists the cache directory at `Open` | yes |
63| `store.go` `Store.loadMeta` | new | +file:ReadFile | one `<id>.meta` during the scan | yes |
64| `store.go` `Store.bodyMatches` | new | +file:Stat | a body file's size during the scan, checked against its `.meta` | yes |
65| `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 |
66| `store.go` `Reader.Read` | new | +file:Read ×2 | reads the file `Entry.Open` opened | one real; the other is the method's own name |
67| `store.go` `Reader.ReadAt` | new | +file:ReadAt ×2 | reads the file `Entry.Open` opened | one real; the other is the method's own name |
68| `store.go` `Reader.Stat` | new | +file:Stat ×2 | stats the file `Entry.Open` opened | one real; the other is the method's own name |
69| `fill.go` `Fill.open` | new | +file:OpenFile, +file:Read | creates the body temporary (O_EXCL, 0600) | `OpenFile` yes; `Read` is `crypto/rand.Read`, a name match |
70| `fill.go` `Fill.writeGzip` | new | +file:OpenFile | creates the gzip temporary (O_EXCL, 0600) | yes |
71| `fill.go` `Fill.commit` | new | +file:Read | `crypto/rand.Read`, the version drawn per commit | no, name match only |
72| `fill.go` `Fill.finish` | new | +file:Lstat | the size of a temporary it is about to remove | yes |
73| `fill.go` `writeSynced` | new | +file:OpenFile | creates the `.meta` temporary (O_EXCL, 0600) | yes |
74| `fill.go` `syncDir` | new | +file:Open | opens the cache directory to fsync it | yes |
75| `statfs_linux.go` `statfsFS.Space` | new | +file:Statfs | `unix.Statfs` of the cache directory, for the free-space floor | yes |
76| `statfs_linux.go` `var Statfs` | new | +file:Statfs | the variable's name | no, name match only |
77| `statfs_other.go` `var Statfs` | new | +file:Statfs | the variable's name; off Linux `Space` returns `ErrUnsupported` and reads nothing | no, name match only |
78
79Envelopes pinned: `internal/assetcache` (new,
80`93ba49fd3716984a753682f88739cdc3dc3efed459a0892c831a2232f7250ece`).
81
82Seal: `68ca9635da386f34ef483c790af19e954122c11edc406d64cde8d55d99d12de5`
83(sec-mail-user-boundary's) →
84`de15b849fcb93b76caca55be924cde41512f8c470f40b4ebdd77ec65ad7e7069`.
85Before the merge with 6c75ad81 it was `27b02059…ecd8` → `fb7ba7c4…f8a1`;
86before the merge with b612e710, `0ca3baaf…89f2` → `1fa408dd…6827`.
87
88Overlay: `internal/provision/testdata/plan14-root-reads-edge-asset-cache-2.tsv`,
89appended to `internal/provision/testdata/plan14-root-reads-chain.tsv` after
90`plan14-root-reads-sec-mail-user-boundary.tsv` (the last overlay on main
91at 6c75ad81), whose seal is checked first.
92
93Record-write census (9B8): unchanged; the package writes no record keys.
94Claim routes: unchanged. go.mod: unchanged.
95
96## The question
97
98Approve the 17 new rows as accepted legacy with the basis above, and the
99`internal/assetcache` envelope pin, or hold?
100