Files
booth/persistent-memory.d/2026-09-22-u5-panels.md
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

5.5 KiB

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.