Skip to content

Commit 26b189e

Browse files
author
gluck
committed
docs: the trunk singleton form is BUILT, with its deviations
1 parent 2476fe9 commit 26b189e

4 files changed

Lines changed: 97 additions & 17 deletions

File tree

‎plans/progress.md‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,3 +1302,52 @@ enough that either can be judged in ninety seconds:
13021302
box=$(mktemp -d); cp -a --reflink=auto ~/.local/state/figaro/arias $box/arias
13031303
FIGARO_PROBE_ROOT=$box/arias go test ./internal/store -run ListingCost -v
13041304
```
1305+
1306+
### Phase 8 landed: the hierarchy is a form
1307+
1308+
`internal/trunk` (296 lines) and `trunks.json` are gone. The presentation
1309+
hierarchy is `store.TopologyTree`, a `store.Form` on a reserved stump.
1310+
1311+
**Why a stump.** The design wanted an unbound form NODE with a well-known
1312+
id, which needs client-specified trunk ids, which figwal does not have (and
1313+
which Gluck has already asked for: `answers-forms.md` §2). A stump is the
1314+
one node figwal names by a caller-chosen string, so the form needs no marker
1315+
file and no lookup, cannot be forked and cannot be bound. `listStumps`
1316+
filters it out, or the hierarchy grows a row describing itself.
1317+
1318+
**What it buys, checked rather than claimed:**
1319+
1320+
- A promote is **one patch naming two edges**
1321+
(`TestTopologyForm_PromoteIsOneRecord`). The file it replaces rewrote the
1322+
whole document per edit and could half-land.
1323+
- Durability, versioning and the single writer are the form's: reduce, append,
1324+
fsync, publish. `Rev()` is the form version.
1325+
- `trunk.mu` is gone — the lock audit's fifth entry.
1326+
- **Parity is the old package's own test suite, ported verbatim**: same
1327+
diagram, same claims, same names. That is what makes "it behaves as the
1328+
file did" checkable.
1329+
1330+
**Migration**: a legacy `trunks.json` is folded in on first open and renamed
1331+
`.migrated`. Ordering rather than a journal — the fold is idempotent, so a
1332+
crash before the rename replays harmlessly, and a form already holding edges
1333+
is never migrated into.
1334+
1335+
**Live, on an isolated daemon**: `fig ls` draws parent→child, `promote`
1336+
swaps them, `ls -g` shows **no** `@topology` row, and the promote survives a
1337+
daemon restart (replayed from the channel, not re-read from a file).
1338+
1339+
**Deviation: retention is not built.** durable-forms §8 says the topology
1340+
form compacts to a single segment, which needs figwal's compacting channel
1341+
(phase 7). Until then it keeps every record: correct, and unbounded. Promotes
1342+
are rare so the growth is slow, but it IS growth, and phase 7 should point
1343+
here first.
1344+
1345+
| phase | state |
1346+
|---|---|
1347+
| 0,1,2,4,5 | done (session 1) |
1348+
| 3 | **wire half done**: outcome + version; `session`/`seq` deliberately not built |
1349+
| 6 | **done**: tombstone, `Reclaimable`, and the delete path calls both |
1350+
| 7 retention | not started (needs figwal) |
1351+
| 8 topology form | **done**, live-validated, `internal/trunk` deleted |
1352+
| 9 libretto | not started; §12.2.2 records a design bug found before it was built |
1353+
| 10 API refactor | not started |

‎skills/figaro/contributing/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Read the one you are inside. These describe internals, not usage.
3535
| File | When to read it |
3636
|---|---|
3737
| [trunks-substrate.md](trunks-substrate.md) | Changing `internal/store` or the fork handlers. |
38-
| [trunk-singleton-form.md](trunk-singleton-form.md) | Changing the presentation hierarchy, `trunks.json`, or figwal channel retention. Holds the slated design: the hierarchy as one form per store. |
38+
| [trunk-singleton-form.md](trunk-singleton-form.md) | Changing the presentation hierarchy or figwal channel retention. The hierarchy IS one form per store as of phase 8; holds the design and where the build differs from it. |
3939
| [forms-design.md](forms-design.md) | Changing the form primitive: the single writer, the hub, outfit resolution, observation. |
4040
| [roles-design.md](roles-design.md) | Changing roles, cast, or how a studied form renders into a model's context. |
4141
| [reclamation.md](reclamation.md) | Changing the hub, the sweep or the row caches: what a live aria costs and when the daemon reclaims one. |

‎skills/figaro/contributing/trunk-singleton-form.md‎

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
11
# The trunk state, as a singleton form
22

3-
**Status: designed, not built.** Slated after the presentation-hierarchy
4-
fixes it depends on. Read this before touching `internal/trunk`,
5-
`trunks.json`, or anything in figwal about channels and retention.
3+
**Status: BUILT** (`feat/incantations`, phase 8). `internal/trunk` and
4+
`trunks.json` are gone; the hierarchy is `store.TopologyTree`, a form on a
5+
reserved stump. Read this for the WHY; read `internal/store/topology_form.go`
6+
for what shipped, and the differences below before changing either.
7+
8+
## What shipped, and where it differs from this design
9+
10+
- **The home is a reserved STUMP** (`@topology`), not an unbound form node.
11+
A stump is the one node figwal names by a string the caller chooses, so
12+
the form needs no marker file and no lookup, and it cannot be forked or
13+
bound. An unbound form node would have needed client-specified trunk ids,
14+
which figwal does not have yet (and which Gluck wants for other reasons:
15+
see `plans/answers-forms.md` §2). `listStumps` filters it out, or the
16+
hierarchy grows a row describing itself.
17+
- **Retention is NOT built.** This document asks for a single rewritten
18+
segment, which needs figwal's compacting channel (phase 7). Until then the
19+
topology form keeps every record, which is correct and unbounded. A
20+
promote is rare, so the growth is slow, but it IS growth: whoever builds
21+
phase 7 should point it here first.
22+
- **The migration folds `trunks.json` in on first open** and renames it to
23+
`trunks.json.migrated`. Ordering, not a journal: the fold is idempotent and
24+
a form that already holds edges is never migrated into again.
25+
- **Parity is checked, not claimed.** `internal/trunk`'s own test suite was
26+
ported verbatim onto the replacement: same diagram, same claims, same
27+
names, in `internal/store/topology_form_test.go`.
628

729
## The claim
830

‎skills/figaro/reference/trunks.md‎

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ is not instant (it copies the prefix each promoted aria borrows).
238238
239239
Implementation: `runPromote` (`internal/cli/manage.go`), the `figaro.promote`
240240
RPC, `PromoteResponse{FigaroID, Climbed, AtStump}`, the boundary check in
241-
`XwalStore.Promote`, and the override state in `internal/trunk`. The listing
241+
`XwalStore.Promote`, and the override state in the topology form. The listing
242242
carries both edges: `parent` (history, what `status` prints as forked-from)
243243
and `present` (where the row is drawn, what the vector follows).
244244
@@ -261,16 +261,25 @@ and `present` (where the row is drawn, what the vector follows).
261261
A refused delete writes nothing at all: the count is taken before any
262262
repair, because a repair cannot be taken back.
263263
264-
## The trunk state, and where it is going
265-
266-
Today the presentation lives in `trunks.json` beside the store: one JSON
267-
object of overrides, rewritten whole on every edit, absent an override the
268-
topology answers.
269-
270-
**Slated:** move it into an unbound SINGLETON FORM, one per store and so
271-
1:1 with the angelus that owns it. A form is already this project's answer
272-
to durable, versioned, reducible state, and the trunk state is exactly that
273-
shape. The document, the patch stream, the migration, and what figwal must
274-
add for it (one segment, rewritten whole, because only the fold has value
275-
here) are in
264+
## The trunk state IS a form
265+
266+
The presentation lives in the **topology form**: a form on the reserved
267+
stump `@topology`, one per store and so 1:1 with the angelus that owns it.
268+
It holds OVERRIDES, never a full tree, so a lost topology form degrades to
269+
"draw every aria where its history puts it" rather than to a wrong tree.
270+
271+
- **A promote is ONE patch naming two edges**, so the pair lands together or
272+
not at all. The `trunks.json` it replaces rewrote the whole document per
273+
edit and could half-land.
274+
- **Durability, versioning and the single writer are the form's**, not
275+
bespoke: reduce purely, append, fsync, publish. `Rev()` is the form
276+
version, which is what a listing's snapshot check reads.
277+
- **It is never listed, never forked, never bound.** `listStumps` filters it
278+
out of the forest.
279+
- **A legacy `trunks.json` is folded in on first open** and renamed
280+
`trunks.json.migrated`.
281+
- **Retention is not built yet**: it keeps every record until figwal grows a
282+
compacting channel.
283+
284+
Design and the deviations from it:
276285
[contributing/trunk-singleton-form.md](../contributing/trunk-singleton-form.md).

0 commit comments

Comments
 (0)