From 75623c7dbcc3532b987c99b4dfa895875c7558ce Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Wed, 23 Sep 2026 18:41:32 -0700 Subject: [PATCH] fix(blur): the heid code-review and bug-hunt panels on r2b merge 1, folded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- booth/app.py | 21 ++- booth/templates/base.html | 8 +- booth/templates/booth.html | 16 ++- booth/templates/doc.html | 25 ++++ booth/templates/view.html | 11 +- .../r2b_desk_reveal_theme.contract.md | 47 +++++-- tests/mutations/r2b.toml | 129 +++++++++++++++++- tests/test_flow.py | 81 ++++++++++- tests/test_flow_browser.py | 97 ++++++++++++- 9 files changed, 405 insertions(+), 30 deletions(-) diff --git a/booth/app.py b/booth/app.py index 5f88a82..b72f794 100644 --- a/booth/app.py +++ b/booth/app.py @@ -136,7 +136,21 @@ def set_booth_blurred(booth: Path, on: bool) -> bool: state the caller asked for, exactly as unflagging an unflagged item is.""" marker = booth / BOOTH_BLUR_FILE if on: - marker.touch(exist_ok=True) + # NEVER through a link (r2b, heid bug-hunt). `touch()` followed a + # planted `.blurbooth` symlink: a click rewrote an outside file's + # mtime, or created a dangling target — the class `record_view` was + # hardened against. Anything already at the name, a link included, + # already reads as fogged (`is_booth_blurred`), so there is nothing to + # write; otherwise create exclusively, never following a link. + try: + os.lstat(marker) + return True + except FileNotFoundError: + pass + try: + os.close(os.open(marker, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o644)) + except FileExistsError: + pass # lost a race to another fog: still fogged return True try: marker.unlink() @@ -2143,7 +2157,10 @@ def create_app( booth = resolve_booth(name) set_booth_blurred(booth, on not in ("0", "false", "")) landing = f"/b/{quote(name, safe='')}/" - if back: + # The review only for an item of the review ring (r2b, heid bug-hunt), + # exactly as the mark routes' back=view: a stale or foreign `back` + # would otherwise land on a 404. Built from the ring, never echoed. + if back and back in review_chain(booth_items(booth)): landing += f"view?f={quote(back, safe='/')}" return RedirectResponse(url=landing, status_code=303) diff --git a/booth/templates/base.html b/booth/templates/base.html index cbc6e78..a1ccf47 100644 --- a/booth/templates/base.html +++ b/booth/templates/base.html @@ -616,6 +616,11 @@ .blur-all button:hover,.reveal-all-btn:hover{color:var(--text-body);border-color:var(--border-strong)} .blur-all.is-on button{color:var(--text-body);border-color:var(--border-strong)} .reveal-all-btn[aria-pressed="true"]{color:var(--text-body);border-color:var(--border-strong)} + /* One line each, always: a top bar at phone width squeezed these into + four-line stacks. Below 600px the reveal drops its "— blur is cosmetic" + tail; the title still says it, as does every per-item reveal. */ + .blur-all button,.reveal-all-btn{white-space:nowrap} + @media (max-width:600px){.reveal-all-btn .ra-note{display:none}} .badge-blur{color:var(--text-muted)} /* ---- inline docs ------------------------------------------------------ @@ -1082,7 +1087,8 @@ var key = 'booth.reveal:' + b; function show(btn) { var on = d.classList.contains('reveal-all'); - btn.textContent = on ? '🙈 blur again' : '👁 reveal all — blur is cosmetic'; + btn.querySelector('.ra-label').textContent = on ? '🙈 blur again' : '👁 reveal all'; + btn.querySelector('.ra-note').hidden = on; btn.setAttribute('aria-pressed', on ? 'true' : 'false'); } ctl.forEach(function (btn) { diff --git a/booth/templates/booth.html b/booth/templates/booth.html index 2591a88..d6cd1ff 100644 --- a/booth/templates/booth.html +++ b/booth/templates/booth.html @@ -106,13 +106,19 @@ {# r2b D2b + D2: the booth-wide blur controls, outside every data-region. The fog is server state for every viewer and a plain form (works with scripts off); its label says what IS. Reveal all lifts it for this tab - only, and is markup only when something here is blurred. #} - {% if not board %} -
+ only, and is markup only when something here is blurred. A BOARD gets + them too when it holds files: only the one-click wipe is board-suppressed, + and an item's "◉ booth" label points here. #} + {% if all_items %} + {# The fog form IS a region: its label is server state, so an in-place save + refreshes it with everything else (a fog set elsewhere since this page + loaded would otherwise leave it saying "blur booth"). Reveal all is not: + its state lives in this tab, and a swap must never reset it. #} + - - {% if all_items | selectattr('blurred') | list %}{% endif %} +
+ {% if all_items | selectattr('blurred') | list %}{% endif %} {% endif %} {% if not board %}
✕ {{ file }} + {# Reveal all can lift this page's blur, so this page must be able to put it + back (r2b, heid bug-hunt). #} + {% if blurred %}{% endif %} ⬇ {# Same record, same reason as the image viewer: the sidecar that says what @@ -17,11 +20,17 @@ {% for m in marks if m.shape == 'note' %}
{{ m.text }}
{% endfor %} {% endif %} + {# Blur honesty reaches the full page too (r2b, heid code-review): a blurred + doc's own page rendered clear. Its reveal is per-page and JS-only, like the + review stage's; Reveal all lifts it by the same class. #} +
+ {% if blurred %}{% endif %} {% if is_html %}
{{ body|safe }}
{% else %}
{{ body }}
{% endif %} +