fix(blur): the heid code-review and bug-hunt panels on r2b merge 1, folded

Both panels ran 4/4 on 5ded5ff. They converged on the board and doc-page
gaps independently.

- A board holding files lost both blur controls (they sat inside the
  board suppression meant for the one-click wipe), while its items'
  "◉ booth" labels pointed at them. Only the wipe is board-suppressed now.
- A blurred doc's own full page rendered clear. Its body is blurred there
  too, with its own reveal and a Reveal all to put the blur back.
- set_booth_blurred followed a planted .blurbooth symlink (`touch`), and
  the new control made that a click away. Anything at the name already
  reads as fogged; otherwise it is created O_CREAT|O_EXCL|O_NOFOLLOW.
- The fog landing echoed `back` unchecked into the 303. It is now built
  from the review ring, as the mark routes do.
- The fog form is its own region, so an in-place save refreshes its
  label. Reveal all stays outside every region: its state lives in the
  tab.
- The review's Space-to-advance no longer swallows Space on a focused
  button or link.
- Top-bar controls stay on one line at phone width.
- Tests tightened:
  - method="post" on the fog forms;
  - exact blur values;
  - a storage READ that throws;
  - an item's own reveal carried across a swap;
  - reveal gated where it can act.

r2b.toml: 26/26 proved. 774 passed.
This commit is contained in:
vh
2026-09-23 18:41:32 -07:00
parent 5ded5ffe55
commit 75623c7dbc
9 changed files with 405 additions and 30 deletions
@@ -104,11 +104,15 @@ different kind of thing from the lifetime pill (state) and the controls
## D2 — Reveal all (blur ruling A)
- **One STATE per booth, shown by a control in two places: "👁 reveal all —
blur is cosmetic" / "🙈 blur again".** One instance is in the booth header,
one in the review's top bar, and both sit OUTSIDE every `data-region`, so no
in-place swap replaces them. The server puts the control in the markup only
when at least one item of the booth is blurred (`Item.blurred`), and always
with the `hidden` attribute. The script removes `hidden` and binds it. Without
blur is cosmetic" / "🙈 blur again".** It appears in the booth header, the
review's top bar and a blurred doc's own top bar. Every instance sits OUTSIDE
every `data-region`, so no in-place swap replaces it: its state lives in the
tab, and a swap must never reset it. Below 600px it reads "👁 reveal all";
its title still says the blur is cosmetic. The server puts the control in the markup only
where it can act, and always with the `hidden` attribute: in the header when
any item of the booth is blurred (`Item.blurred`), and in the review when any
item of the review RING is (a blurred doc is not on the review page, so a
control there would act on nothing). The script removes `hidden` and binds it. Without
JS it is in the markup but never shown.
- **State: `sessionStorage["booth.reveal:" + <booth name>] = "1"`.** Per booth,
per tab, gone when the tab closes, so a blurred booth is blurred again next
@@ -131,8 +135,15 @@ different kind of thing from the lifetime pill (state) and the controls
- Because every change of page is a full load, the class is re-decided per
page, from that page's `data-booth`. Booth A's reveal cannot follow you
into booth B.
- The index carries no `data-booth`, so **nothing on the index is revealed
by D2**, the Desk strip included.
- The index's `<html>` carries no `data-booth` (its rows' own `data-booth`
attributes are unrelated), so **nothing on the index is revealed by D2**,
the Desk strip included.
- **A board holding files gets both controls.** Only the one-click wipe is
board-suppressed; an item's "◉ booth" label points at the header control,
so the control must be there.
- **The full-page doc view is blurred honestly.** A blurred doc's own page
renders its body blurred, with its own JS-only reveal; Reveal all lifts it
by the same `<html>` class.
- **The per-item reveal defers to it, BY STYLESHEET.** Under `.reveal-all` the
per-tile and stage reveal buttons are `display: none`. That is a CSS
consequence of the class, so markup swapped in after a save obeys it with no
@@ -148,9 +159,22 @@ booth-dev landed the whole-booth marker and its route while the panel was
reading; this is the control the operator uses, which the blur ruling assumed.
- **"◌ blur booth" / "◉ booth blurred" in the booth header and the review's
tape bar**: a plain `<form method=post action=/b/<name>/blurbooth>` with
top bar (`.vbar`)**, each wrapped in its OWN region, `blur-booth`. Its label is
server state, so an in-place save refreshes it with everything else; a fog
set elsewhere since the page loaded would otherwise leave it saying "blur
booth". It is a plain `<form method=post action=/b/<name>/blurbooth>` with
`on=1|0`, so it works with scripts off (INV-2). From the review it carries
`back=<rel>` and lands back on the same item.
`back=<rel>`. The route lands on the review only when `back` is an item of
the review ring, and otherwise on the booth page; the landing is built from
the ring, never echoed.
- **Fogging never writes through a link.** booth-dev's `set_booth_blurred` used
`touch()`, which followed a planted `.blurbooth` symlink: a click of this
control rewrote an outside file's mtime, or created a dangling target. Any
entry already at the name reads as fogged, so nothing is written; otherwise
the marker is created with `O_CREAT | O_EXCL | O_NOFOLLOW`.
- **Space never hijacks a focused control.** The review's Space-to-advance
ignores a focused button, link or summary, so a keyboard can press these
controls.
- **Its state comes from the server**, never from the client:
`booth_blurred = is_booth_blurred(booth)` in both contexts. The label says
what IS, and pressing it flips it.
@@ -235,8 +259,9 @@ reading; this is the control the operator uses, which the blur ruling assumed.
preview image, the text column, the side column, the pill — is identical
with the cluster present or removed.
- **INV-4 — blur honesty (r2 INV-8).** Nothing on the index is revealed by D2.
- **INV-5 — autoescape.** The booth name reaches the page only as an escaped
attribute value.
- **INV-5 — autoescape.** The booth name reaches the reveal-state machinery
only as an escaped attribute value (`data-booth`), read by `getAttribute` and
never templated into a script.
- **INV-6 — no flash.** A forced theme and a set reveal are applied before
first paint.