Files
booth/persistent-memory.d/2026-09-22-u6-benches-landed.md
T
vh c5ac49356f memory: snapshot — U6 released at v0.6.0, six of seven v1 units landed
Nothing in flight. The in-flight section is rewritten to the post-release
state and carries the five things a fresh session must not do: push (main is 8
ahead of origin/main), seed the registry, send the 17-handle note, run either
dated prediction early, or start U7 without re-counting the booths first.

Two new detail files: the release itself, and what each of the five review
passes could only see alone -- the strongest evidence this repo has for running
all of them rather than picking one. The earlier U6 entry is reconciled; it was
written while the gates were still out and said NOT TAGGED.

Restored in the rewrite: the warning that the 17 handles were never told `keep`
stopped meaning "waiting on an answer", which is load-bearing for how the
2026-10-06 re-count reads, and the fact that a remote now exists.
2026-09-22 14:24:12 -07:00

68 lines
3.6 KiB
Markdown

# U6 landed — three surfaces, three jobs, one predicate
_2026-09-22 · booth_
**The sixth of seven v1 units. Only U7 is left.** 444 → 555 tests, suite green,
deployed and verified live: 23/23 booths 200, and the board renders **156 dead
of 221 rows** — the exact count an independent shell measurement produced before
a line of code was written, from two different implementations.
## What shipped
- **`booth/benches.py`** (new, stdlib-only AND sibling-free): `Bench`,
`normalize_bench_url`, lenient `read_benches`, strict `upsert_bench`,
`set_bench_state`, `remove_bench`, `order_benches`. Registry at
`~/booth-data/.benches.json` — a dotfile at the DATA ROOT, keyed by id, so two
rows with one identity are impossible by construction.
- **`links.booth_target`** — ONE predicate for "is this a booth URL", consumed
by three callers (the CLI refusal, the board's dead marker, `bench import`).
Host-agnostic and path-shaped; percent-decodes the name.
- **`booth link` refuses a booth URL**, names `booth new --why`, and writes
nothing — not even the board directory.
- **The board marks dead rows.** Removal stays the operator's two clicks through
the bulk control that already existed. Nothing in the unit deletes a row.
- **`booth bench add|ls|state|rm|import`**; `import` writes nothing without
`--apply` and never touches `links.md`.
- `docs/archive/links-2026-09-22.md` — the board archived verbatim into git.
## The decision that mattered most, and it was measured
**Identity is the FULL normalized URL, not the origin.** Collapsing the 43
non-booth rows by origin gives 19 groups; by full URL, 35. The difference is not
duplication — it is **eight distinct gitea repos merged into one**, three
unrelated HuggingFace model cards merged into one, and **the two LRPG surfaces
on `10.100.10.50:8321`, which are the IA doc's own example of two real benches**,
merged into one. Origin identity destroys more than it dedups. Full-URL identity
still collapses both cases the doc names (talk 5→1, Peedlar 3→1).
Query is IN the identity (three ShutterChute rows differ only by `?token=` and
are three real links); fragment is OUT; credentials are REFUSED, not stripped.
## The seam review earned it again — three real contract defects
Run in-session against the real `.py` files, after the cold panel was dispatched:
- **SR-1** — the contract claimed `test_stdlib_only` already forbids sibling
imports. **It does not**: its failure set is `{r for r in roots if r !=
"booth" and ...}`, which exempts `booth` on purpose. Only test_manifest.py has
the strict copy. INV-9 would have shipped untested.
- **SR-2** — the contract named `resolve_booth` as the dead marker's existence
check. That function is a closure inside `create_app` and **raises
HTTPException(404)** — per row, one swept booth would 404 the whole board page.
- **SR-7** — booth links are emitted through `quote(name, safe="")`, so a
predicate comparing the raw segment marks every encoded-name booth dead
forever.
SR-4 and SR-5 were **verified rather than assumed**: both `list_booths` and
`sweep_once` skip a child that is not a directory AND one whose name starts with
a dot, so the registry is safe from the sweeper by two guards, not one. Had
either been absent the design would have eaten its own registry on tick one.
## How it closed
All three cold gates came back and were folded in full, with exactly one finding
declined. Released as `v0.6.0` — see [[2026-09-22-u6-benches-released]] and
[[2026-09-22-three-cold-panels-on-one-unit]]. The tag waited for the gates, per
the v0.2.0 lesson, and that sequencing was right: the panels produced ten code
fixes after this entry was first written.