Files
booth/persistent-memory.d/2026-09-22-u5-panels.md
T
Vuong Hoang f3193fb054 fix(probe): the disclosure-opening loop was manufacturing its own findings
`page.locator("details:not([open])").all()` hands back POSITIONAL locators
that re-resolve against the current DOM, and `:not([open])` stops matching
an element the moment it is opened — so opening them one at a time shrinks
the set underneath the indices and leaves some closed. Those then report
OCCLUDED, which is exactly the false-positive class the block was added to
remove. One on booth-redesign, three on cr123a-to-d-sleeve, one on
denoise-first-run, and invisible as a bug because a false positive is
shaped like a finding.

Measured both hypotheses rather than guessing between them: per-element
loop against a single document-wide evaluate, at 150 ms and 1000 ms settle.
The loop reports them at either wait; the single pass reports none at
either. The variable was the method, not the timing.

One evaluate over the whole document now. All three pages clean.

Also carries the ROADMAP U5 row, the two-panel record in
persistent-memory.d/, and the memory index line for it.
2026-09-22 01:39:43 -07:00

103 lines
5.5 KiB
Markdown

# U5's two cross-frontier panels — full triage
**Date:** 2026-09-22 · **Paraphrase:** thread `01M340PNVRS21HPASZT38PXQPN` ·
**Conformance:** thread `01M341E9XAPZEFBSPK9HPGAM0S` · **Shipped as:** `v0.3.0`
Two four-arm artifact-only rounds, dispatched ~30 minutes apart and correctly
firewalled: the paraphrase ran the **pre-seam-review** capture (073612), the
conformance round the **SR-amended** one (074901). Heid diffed the two at
intake and said so.
The conformance round's honest headline is Kimi's: **zero drift in the strict
sense — the code is a clause-for-clause implementation of the contract.** Both
rounds' weight landed one layer down, in test strength and contract finish.
## The result worth keeping
**A paraphrase panel reading nothing but prose reached a production outage two
modules away.** 3-of-4 flagged INV-2's "4 GB" case as *letter-compliant but
purpose-defeating* — the invariant constrained the RETURN, not the cost, so an
unbounded read "recreates the outage in slow motion". The conformance round then
found that exact unbounded read live in U5's shipped code. Walking it to the
sibling module found the same hole **live in released `v0.2.2`**: `marks.py`'s
`_read_raw` catches `(OSError, ValueError, UnicodeDecodeError)`, and
`json.loads` on a deeply nested document raises **RecursionError**, which is
none of them. A 400 KB file of nothing but brackets in any ONE booth returned
500 for `/` and `/healthz` across all 26.
**The v0.2.2 round had flagged this and I closed half of it.** Kimi's R5(c)
named RecursionError explicitly; I adopted "wrap `_hydrate` per-entry" and left
the `json.loads` above it unguarded. **A finding with two call sites is not
closed when one is.**
**The reusable instruction: walk a conformance finding to the sibling module
even when the sibling is formally out of scope.** Heid captured it as its own
lesson.
## The densest class was tests that could not fail
Five of ten adopted conformance findings were tests of mine that pass on the
regression they exist to catch. Three shared one shape — **asserting an
ARTIFACT of the property instead of the property**:
| test | asserted | should have asserted |
|---|---|---|
| `test_the_write_is_atomic` | no `*.tmp` survived | the inode changes (`write_text` leaves no temp file either) |
| INV-3 preservation | a stamp survived a window shorter than the stamp's own resolution | a stamp from 2019 |
| `test_announcing_is_activity` | age via the directory mtime, which the write bumps either way | the file's own mtime, directory clock restored |
That is the same shape as the marks round's guard-strength finding the night
before — **three nights running**. Proposed to heid as a standing
"green-tests-prove-nothing" direction for the skill; routed to the operator
alongside two other methodology proposals from the same night.
⚠ **My first replacement for the atomicity test was ALSO vacuous.** It spied on
`os.open` to prove the published path was never written directly — which passes
trivially, because `Path.write_text` reaches the syscall through `io.open` in C
and never touches the Python-level `os.open`. The dead end is recorded in the
test's own docstring rather than deleted.
## Two real bugs the tests were structurally blind to
**`booth new x --why "…"` then `booth add x out/*.png` erased the why.** Omitted
flags meant empty strings; empty strings overwrote. Two arms predicted it *from
the contract's wording alone* — "gains a manifest with no `why`" does not
distinguish a first write from a re-announce with the flags omitted. Every test
written for this module passed `--why` on both calls, so none could see it.
Omitted means unchanged now; `--why ""` still clears. The shell carries the
distinction by leaving the variable UNSET, not empty.
**`--title` was write-only** — stored, flag-surfaced, rendered nowhere. 4-of-4,
independently top-ranked by every arm of the paraphrase round. It renders on the
booth page heading with the directory name kept beside it, because the directory
name is the identity the operator navigates by and refers to positionally.
## Contract-finish, and why it mattered
**INV-1 contradicted its own falsifiable criterion** (4/4) — "the only place
`.booth.json` is opened" versus INV-3's read-back, which forces `write_manifest`
to open it. One half was already false of a correct implementation. Restated as
*one module knows the filename*, which is true, falsifiable and now tested.
**INV-5 named two different promises** (3/4) — the repo's atomic-write rule and
this unit's render rule. Repo-wide rules are named in words now, never by a bare
number that can collide with a local one.
Regin's meta-observation is the round's methodology keeper and was borne out:
**flags cluster where the same rule is re-voiced per signature**, and four of
eleven contract edits were reconciling a docstring against a prose section
saying the same thing slightly differently. A table-vs-signature consistency
pass would beat the format's prose bias.
## Declined / parked
- **Custom booth pages skip provenance** (hulda, solo, verified) — settled
independently as U3's seam ~20 minutes before the reply landed. Convergence,
not an adoption.
- **Empty-handle coercion misattributes to the service** — kept, documented. A
manifest naming no handle does not read back at all, and an unreadable file is
the worse outcome. Unreachable from the CLI.
- **`used`-set: `touches` versus SR-1 unreconciled** — the code adds the entry
as consistency with the equally-unreachable `UPLOAD_MARKER` entry that
predates this unit, and says so rather than claiming it prevents anything.