# R2 — the review flow: falsifiers the round claims, and the change each forbids. # # Every row was proved RED under its mutation in the session that wrote it, # then committed here so the proof is an artifact rather than scrollback. The # browser rows need the Playwright Chromium the browser tests already use. # # Deliberately ABSENT: single guards inside a defence in depth, each of which # stays green when removed alone because another layer still holds — so a row # for any one of them would be a vacuous proof, and this table's own first run # said so. `.seen`'s O_NOFOLLOW, O_NONBLOCK and S_ISREG (the FIFO/symlink test # covers them together); and `flagged_targets`' `error is None`, since # hydration already strips the target from a damaged mark. # # RETIRED (r2c S3, 2026-09-23): the row on the next arrow's 360px rail offset — # the arrows now sit at the drawn picture, clamped inside the stage; the test was # replaced as declared in r2c's contract, and its successors are in r2c.toml. # # RETIRED (r2b D1, 2026-09-23): four rows proving the facts-line row controls # (visible at rest, compact, on the facts line) — the operator ruled those # controls hover-revealed over the preview strip, and their tests were replaced # as declared in r2b's contract. Their successors are in r2b.toml. # # The serialization row is only a falsifier because its test HOLDS the first # refresh in the client: localhost alone never lost the race, and the first # draft of that test stayed green with serialization deleted. unit = "the Desk, the lightbox, the review, and the in-place client" [[mutation]] label = 'C1 ordinals count from 0, not 1' file = "booth/items.py" test = "tests/test_flow.py::test_a_filtered_tile_keeps_its_number_in_the_whole_set" old = '''ordinal=len(items) + 1,''' new = '''ordinal=len(items),''' [[mutation]] label = 'C2 .seen: a nested-too-deep marker escapes the never-raises read' file = "booth/items.py" test = "tests/test_flow.py::test_a_deeply_nested_seen_marker_reads_as_nothing_seen" old = '''except (UnicodeDecodeError, ValueError, RecursionError):''' new = '''except (UnicodeDecodeError, ValueError):''' [[mutation]] label = 'C3 a non-finite q is accepted as a q-value' file = "booth/app.py" test = "tests/test_flow.py::test_a_non_finite_q_is_malformed" old = ''' raise ValueError("non-finite q")''' new = ''' pass''' [[mutation]] label = 'C3 204 on an explicit JSON Accept becomes the 303' file = "booth/app.py" test = "tests/test_flow.py::test_an_explicit_json_accept_gets_204_and_the_write_still_lands" old = ''' return Response(status_code=204)''' new = ''' pass''' [[mutation]] label = 'C3 back=view lands on the review for a doc too (ring check dropped)' file = "booth/app.py" test = "tests/test_flow.py::test_back_view_lands_on_the_review_only_for_a_media_item" old = ''' if f in ring:''' new = ''' if True:''' [[mutation]] label = 'C4 the Desk counts orphan flags' file = "booth/app.py" test = "tests/test_flow.py::test_a_flag_on_a_file_that_is_gone_stays_visible_and_withdrawable" old = '''"flags": len(flagged_targets(marks) & {it.rel for it in items}),''' new = '''"flags": len(flagged_targets(marks)),''' [[mutation]] label = 'C4 landed_at follows symlinks' file = "booth/app.py" test = "tests/test_flow.py::test_the_content_clock_reads_the_booth_not_what_its_links_point_at" old = ''' st = p.lstat()''' new = ''' st = p.stat()''' [[mutation]] label = 'C4 one unreadable entry reads the whole booth as landed NOW' file = "booth/app.py" test = "tests/test_flow.py::test_one_unreadable_entry_costs_that_entry_not_the_booth" old = '''pin it in "new" forever. continue''' new = '''pin it in "new" forever. return time.time()''' [[mutation]] label = 'C4 a non-web bookmark URL becomes a link' file = "booth/templates/index.html" test = "tests/test_flow.py::test_the_desk_never_makes_a_non_web_url_clickable" old = '''{% set web = e.url.lower().startswith(('http://', 'https://')) %}''' new = '''{% set web = true %}''' [[mutation]] label = 'C4 a non-web bench URL becomes a link' file = "booth/templates/index.html" test = "tests/test_flow.py::test_the_desk_never_makes_a_non_web_url_clickable" old = '''{% set web = b.url.lower().startswith(('http://', 'https://')) %}''' new = '''{% set web = true %}''' [[mutation]] label = 'C5 audio/video tiles lose their review link' file = "booth/templates/booth.html" test = "tests/test_flow.py::test_a_sound_only_booth_can_open_the_review" old = '''{% if it.kind in ('video', 'audio') %}''' new = '''
''' [[mutation]] label = "resolver: an entry that cannot be stat'd raises out of booth_items" file = "booth/items.py" test = "tests/test_items.py::test_a_folder_that_lists_but_cannot_be_searched_costs_its_files_not_the_index" old = ''' if not p.is_file(): continue except OSError: continue''' new = ''' if not p.is_file(): continue except FileNotFoundError: continue''' [[mutation]] label = "the stacked Desk column is a bare 1fr (content sets its minimum)" file = "booth/templates/base.html" test = "tests/test_flow_browser.py::test_the_desk_never_scrolls_sideways_at_any_width" old = ''' @media (max-width:1000px){.desk{grid-template-columns:minmax(0,1fr)}}''' new = ''' @media (max-width:1000px){.desk{grid-template-columns:1fr}}''' [[mutation]] label = "a long unbreakable install path in scrolls the page sideways" file = "booth/templates/base.html" test = "tests/test_flow_browser.py::test_the_desk_never_scrolls_sideways_at_any_width" old = ''' padding:1px 6px;border-radius:var(--radius-sm);border:1px solid var(--border-subtle);overflow-wrap:anywhere}''' new = ''' padding:1px 6px;border-radius:var(--radius-sm);border:1px solid var(--border-subtle)}''' [[mutation]] label = "the row's text column cannot shrink (the 700-1000px window overflows)" file = "booth/templates/base.html" test = "tests/test_flow_browser.py::test_the_desk_never_scrolls_sideways_at_any_width" old = ''' .desk-main{flex:1 1 auto;min-width:0}''' new = ''' .desk-main{flex:1 1 auto}''' [[mutation]] label = "the wipe dialog shows the agent-made name raw (bidi, newline)" file = "booth/templates/index.html" test = "tests/test_flow_browser.py::test_the_wipe_dialog_shows_what_is_being_wiped_and_never_fails_open" old = ''' if (!confirm(word(shown(form.getAttribute('data-booth') || '')))) ev.preventDefault();''' new = ''' if (!confirm(word(form.getAttribute('data-booth') || ''))) ev.preventDefault();''' [[mutation]] label = "an unknown data-confirm word submits with no prompt (fail open)" file = "booth/templates/index.html" test = "tests/test_flow_browser.py::test_the_wipe_dialog_shows_what_is_being_wiped_and_never_fails_open" old = ''' var word = WORDS[form.getAttribute('data-confirm')] || ASK; if (!confirm(''' new = ''' var word = WORDS[form.getAttribute('data-confirm')]; if (word && !confirm(''' [[mutation]] label = "everything else in activity order again (a look moves a booth up)" file = "booth/app.py" test = "tests/test_flow.py::test_everything_else_is_ordered_by_last_update_not_by_looking" old = ''' rest.sort(key=lambda b: (-b["landed_at"], b["name"]))''' new = ''' pass''' [[mutation]] label = "everything else breaks an update tie by name reversed" file = "booth/app.py" test = "tests/test_flow.py::test_everything_else_breaks_an_update_tie_by_name" old = ''' rest.sort(key=lambda b: (-b["landed_at"], b["name"]))''' new = ''' rest.sort(key=lambda b: (b["landed_at"], b["name"]), reverse=True)'''