The operator ruled blur A, and made it urgent: "per booth blurring is now
important since we are showing up to 4 images."
- Reveal all: one control per booth, in the booth header and the review's
top bar, outside every data-region. It is in the markup only when
something is blurred, always `hidden` until the script shows it.
- The state is sessionStorage per booth, per tab, and nothing reaches
the server. It is carried as one `reveal-all` class on <html>, applied
before first paint from the page's own data-booth, so booth A's reveal
cannot follow you into booth B and the index is never revealed.
- Per-item reveal buttons stand down by stylesheet, and an item's own
reveal is never touched, so "blur again" restores each item as it was.
- A storage write that throws still applies the click.
- The booth blur control: a plain form to booth-dev's POST /blurbooth, so
it works with scripts off. Its label follows is_booth_blurred; from the
review it carries `back` and lands on the same item. A fogged booth's
Desk row says "◉ blurred".
- Found by rendering it: under a fogged booth every item reported
`blurred`, so an item blurred only by the booth offered an un-blur that
visibly did nothing. The gallery now carries `blurred_self`, and such an
item shows "◉ booth", a label rather than a control.
Contract docs/contracts/r2b_desk_reveal_theme.contract.md (heid contract
panel 4/4, folded). tests/mutations/r2b.toml: 14/14 proved. 765 passed.
140 lines
5.6 KiB
TOML
140 lines
5.6 KiB
TOML
# R2b — the Desk row, Reveal all, the theme toggle: every falsifier the
|
|
# contract claims (docs/contracts/r2b_desk_reveal_theme.contract.md), and the
|
|
# change each forbids. Merge 1 is D2 + D2b (the blur half); merge 2 adds D1 + D3.
|
|
|
|
unit = "reveal all, the booth blur toggle (merge 1)"
|
|
|
|
[[mutation]]
|
|
label = "D2 reveal all does not lift the tile's blur"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_reveals_every_blurred_surface_and_survives_the_next_page"
|
|
old = '''
|
|
.reveal-all .item.blurred img,.reveal-all .item.blurred video,'''
|
|
new = '''
|
|
.reveal-all-OFF .item.blurred img,.reveal-all .item.blurred video,'''
|
|
|
|
[[mutation]]
|
|
label = "D2 no pre-paint re-application: the next page of the reel is blurred again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_reveals_every_blurred_surface_and_survives_the_next_page"
|
|
old = '''
|
|
if (b !== null && sessionStorage.getItem('booth.reveal:' + b) === '1') d.classList.add('reveal-all');'''
|
|
new = '''
|
|
if (false) d.classList.add('reveal-all');'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the reveal is not scoped to the booth (any reveal in the tab reveals every booth)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_on_booth_a_does_not_reveal_booth_b_or_the_desk"
|
|
old = '''
|
|
if (b !== null && sessionStorage.getItem('booth.reveal:' + b) === '1') d.classList.add('reveal-all');'''
|
|
new = '''
|
|
if (b !== null && sessionStorage.length > 0) d.classList.add('reveal-all');'''
|
|
|
|
[[mutation]]
|
|
label = "D2 per-tile reveal buttons do not stand down under reveal all"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_survives_an_in_place_save"
|
|
old = '''
|
|
.reveal-all .item.blurred .reveal,.reveal-all #vreveal{display:none}'''
|
|
new = '''
|
|
.reveal-all-OFF .item.blurred .reveal,.reveal-all #vreveal{display:none}'''
|
|
|
|
[[mutation]]
|
|
label = "D2 blur again wipes each item's own reveal"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_blur_again_restores_each_items_own_reveal"
|
|
old = '''
|
|
var on = d.classList.toggle('reveal-all');
|
|
try {'''
|
|
new = '''
|
|
var on = d.classList.toggle('reveal-all');
|
|
document.querySelectorAll('.item.revealed').forEach(function (i) { i.classList.remove('revealed'); });
|
|
try {'''
|
|
|
|
[[mutation]]
|
|
label = "D2 a storage write that throws swallows the click"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_never_shows_without_js_and_a_storage_failure_still_applies_the_click"
|
|
old = '''
|
|
var on = d.classList.toggle('reveal-all');
|
|
try {'''
|
|
new = '''
|
|
sessionStorage.setItem(key, '1');
|
|
var on = d.classList.toggle('reveal-all');
|
|
try {'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the control shows without JS (server markup not hidden)"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow_browser.py::test_reveal_all_never_shows_without_js_and_a_storage_failure_still_applies_the_click"
|
|
old = '''
|
|
{% if all_items | selectattr('blurred') | list %}<button type="button" class="reveal-all-btn" data-reveal-all hidden>'''
|
|
new = '''
|
|
{% if all_items | selectattr('blurred') | list %}<button type="button" class="reveal-all-btn" data-reveal-all>'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the control is markup even when nothing is blurred"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_reveal_all_is_in_the_markup_only_when_something_is_blurred_and_always_hidden"
|
|
old = '''
|
|
{% if all_items | selectattr('blurred') | list %}<button'''
|
|
new = '''
|
|
{% if true %}<button'''
|
|
|
|
[[mutation]]
|
|
label = "D2 the review page does not carry data-booth"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_flow.py::test_reveal_all_is_in_the_markup_only_when_something_is_blurred_and_always_hidden"
|
|
old = '''
|
|
{% block html_attrs %} data-booth="{{ name }}"{% endblock %}'''
|
|
new = '''
|
|
{% block html_attrs %}{% endblock %}'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the header control's label does not follow the server's fog state"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
<input type="hidden" name="on" value="{{ '0' if booth_blurred else '1' }}">
|
|
<button title="{{ 'un-blur the whole booth'''
|
|
new = '''
|
|
<input type="hidden" name="on" value="1">
|
|
<button title="{{ 'un-blur the whole booth'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the review's control drops `back` (fogging ejects you from the review)"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
<input type="hidden" name="back" value="{{ file }}">'''
|
|
new = '''
|
|
'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the Desk row does not say a booth is fogged"
|
|
file = "booth/templates/index.html"
|
|
test = "tests/test_flow.py::test_the_booth_blur_toggle_works_without_js_and_lands_back_on_the_review"
|
|
old = '''
|
|
{% if b.booth_blurred %}<span class="badge badge-blur"'''
|
|
new = '''
|
|
{% if false %}<span class="badge badge-blur"'''
|
|
|
|
[[mutation]]
|
|
label = "D2b an item blurred only by the booth offers a per-item un-blur that does nothing"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_flow.py::test_under_a_fogged_booth_each_items_blur_control_tells_the_truth"
|
|
old = '''
|
|
{% if it.blurred and not it.blurred_self %}'''
|
|
new = '''
|
|
{% if false %}'''
|
|
|
|
[[mutation]]
|
|
label = "D2b the per-item control reads the composed blur, not the item's own"
|
|
file = "booth/app.py"
|
|
test = "tests/test_flow.py::test_under_a_fogged_booth_each_items_blur_control_tells_the_truth"
|
|
old = '''
|
|
"blurred_self": it.rel in own_blur,'''
|
|
new = '''
|
|
"blurred_self": it.blurred,'''
|