From the anti-slop run (design-dev, 2026-09-28). A rendered doc ran 110-120 characters a line and its h3 sat at 1.08x its body. Prose blocks in .markdown-body are capped at 72ch (pre and tables keep the full width, where they scroll), and h3/h2/h1 step at 1.2/1.44/1.73em. Measured in a real browser: a long paragraph now reads under 76 characters across, and every heading step is >= 1.18. Contract: as_antislop S4. Falsifiers: antislop.toml 43/43 proved (S1-S4); all 12 tables 323/323 proved on this tree.
332 lines
14 KiB
TOML
332 lines
14 KiB
TOML
# The anti-slop fix slices: every falsifier the contract claims
|
|
# (docs/contracts/as_antislop.contract.md), and the change each forbids.
|
|
|
|
unit = "anti-slop fix slices (the house clock, and the slices after it)"
|
|
|
|
# ---- S1: the house clock
|
|
|
|
[[mutation]]
|
|
label = "S1 clock renders HH:MM"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_clock_forms"
|
|
old = ''' hhmm = time.strftime("%H%M", time.localtime(epoch))'''
|
|
new = ''' hhmm = time.strftime("%H:%M", time.localtime(epoch))'''
|
|
|
|
[[mutation]]
|
|
label = "S1 clock raises on a stamp it cannot read"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_clock_never_raises"
|
|
old = ''' if epoch is None:
|
|
return value if isinstance(value, str) else ""'''
|
|
new = ''' if epoch is None:
|
|
raise ValueError(value)'''
|
|
|
|
[[mutation]]
|
|
label = "S1 byline passes an address through"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_byline_hides_addresses"
|
|
old = ''' return "" if _is_address(bare) else who'''
|
|
new = ''' return who'''
|
|
|
|
[[mutation]]
|
|
label = "S1 the date tooltips keep HH:MM"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_date_stamp_is_house_form"
|
|
old = ''' return time.strftime("%Y-%m-%d %H%M", time.localtime(epoch))'''
|
|
new = ''' return time.strftime("%Y-%m-%d %H:%M", time.localtime(epoch))'''
|
|
|
|
[[mutation]]
|
|
label = "S1 a pick's answer line shows the raw stamp"
|
|
file = "booth/templates/_marks.html"
|
|
test = "tests/test_antislop.py::test_rendered_marks_use_the_house_clock"
|
|
old = '''{{ a.answer.answered_at|clock }}'''
|
|
new = '''{{ a.answer.answered_at }}'''
|
|
|
|
[[mutation]]
|
|
label = "S1 a memo line shows the raw stamp"
|
|
file = "booth/templates/_marks.html"
|
|
test = "tests/test_antislop.py::test_rendered_marks_use_the_house_clock"
|
|
old = '''{{ a.created|clock }}'''
|
|
new = '''{{ a.created }}'''
|
|
|
|
[[mutation]]
|
|
label = "S1 a memo line shows the poster's address"
|
|
file = "booth/templates/_marks.html"
|
|
test = "tests/test_antislop.py::test_rendered_marks_use_the_house_clock"
|
|
old = '''{% if a.by|byline %} · {{ a.by|byline }}{% endif %}'''
|
|
new = '''{% if a.by %} · {{ a.by }}{% endif %}'''
|
|
|
|
[[mutation]]
|
|
label = "S1 an answer line shows the answerer's address"
|
|
file = "booth/templates/_marks.html"
|
|
test = "tests/test_antislop.py::test_rendered_marks_use_the_house_clock"
|
|
old = '''{% if a.answer.answered_by|byline %} · {{ a.answer.answered_by|byline }}{% endif %}'''
|
|
new = '''{% if a.answer.answered_by %} · {{ a.answer.answered_by }}{% endif %}'''
|
|
|
|
[[mutation]]
|
|
label = "S1 the inline ask's state tag shows the raw stamp"
|
|
file = "booth/templates/_ask_inline.html"
|
|
test = "tests/test_antislop.py::test_embed_fragment_uses_the_house_clock"
|
|
old = '''✓ answered <time datetime="{{ a.answer.answered_at }}">{{ a.answer.answered_at|clock }}</time>'''
|
|
new = '''✓ answered {{ a.answer.answered_at }}'''
|
|
|
|
[[mutation]]
|
|
label = "S1 a board row shows HH:MM"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_antislop.py::test_board_rows_use_the_house_clock"
|
|
old = '''{{ e.when|clock }}'''
|
|
new = '''{{ e.when }}'''
|
|
|
|
# ---- S1, folded from the heid bug-hunt (thread 01M3MGPFKWBX0SJK5HFE0P3AFM)
|
|
|
|
[[mutation]]
|
|
label = "S1 clock raises OverflowError on an int past float range (Q1)"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_clock_never_raises"
|
|
old = ''' try:
|
|
f = float(value)
|
|
except (OverflowError, ValueError):
|
|
return None
|
|
return f if math.isfinite(f) else None'''
|
|
new = ''' return float(value) if math.isfinite(value) else None'''
|
|
|
|
[[mutation]]
|
|
label = "S1 a date-only stamp prints an invented 0000 (Q8)"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_clock_forms"
|
|
old = ''' if isinstance(value, str) and ":" not in value:'''
|
|
new = ''' if False:'''
|
|
|
|
[[mutation]]
|
|
label = "S1 an address with a port prints (Q7)"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_byline_hides_addresses"
|
|
old = ''' if s.count(":") == 1:
|
|
candidates.add(s.split(":", 1)[0])'''
|
|
new = ''''''
|
|
|
|
[[mutation]]
|
|
label = "S1 a zero-width character disguises an address (Q7)"
|
|
file = "booth/app.py"
|
|
test = "tests/test_antislop.py::test_byline_hides_addresses"
|
|
old = ''' bare = "".join(ch for ch in who if unicodedata.category(ch) not in ("Cf", "Cc")).strip()'''
|
|
new = ''' bare = who.strip()'''
|
|
|
|
[[mutation]]
|
|
label = "S1 a board row's author is not bylined (Q5)"
|
|
file = "booth/templates/booth.html"
|
|
test = "tests/test_antislop.py::test_board_rows_use_the_house_clock"
|
|
old = '''{% if e.who|byline %}<span class="board-who">{{ e.who|byline }}</span>{% endif %}'''
|
|
new = '''{% if e.who %}<span class="board-who">{{ e.who }}</span>{% endif %}'''
|
|
|
|
# ---- S2: legibility
|
|
|
|
[[mutation]]
|
|
label = "S2 the review arrows' chip lets a light stage through (60%)"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_antislop.py::test_review_arrows_hold_over_a_white_stage"
|
|
old = '''background:oklch(0.17 0.01 250 / .82);'''
|
|
new = '''background:oklch(0.17 0.01 250 / .6);'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the filmstrip numbers back at 9.5px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop.py::test_film_numbers_meet_the_label_floor"
|
|
old = ''' .film-ord{position:absolute;left:3px;top:3px;padding:1px 4px;border-radius:var(--radius-sm);
|
|
font:600 var(--size-micro)/1.2 var(--font-mono);background:oklch(0.17 0.01 250 / .85);'''
|
|
new = ''' .film-ord{position:absolute;left:3px;top:3px;padding:1px 4px;border-radius:var(--radius-sm);
|
|
font:600 9.5px/1.2 var(--font-mono);background:oklch(0.17 0.01 250 / .85);'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the marks' state stamp back at 10.5px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop.py::test_mark_state_meets_the_label_floor"
|
|
old = ''' .mark-state{font-family:var(--font-mono);font-size:var(--size-micro);'''
|
|
new = ''' .mark-state{font-family:var(--font-mono);font-size:10.5px;'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the Desk's section rules back at the label size"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop.py::test_hint_lines_meet_the_sentence_floor"
|
|
old = ''' .desk-rule{font-size:var(--size-caption);font-weight:400;'''
|
|
new = ''' .desk-rule{font-weight:400;'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the board note back at 11px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop.py::test_hint_lines_meet_the_sentence_floor"
|
|
old = ''' .board-note{font-family:var(--font-mono);font-size:var(--size-caption);'''
|
|
new = ''' .board-note{font-family:var(--font-mono);font-size:var(--size-micro);'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the bench note back at 11px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop.py::test_hint_lines_meet_the_sentence_floor"
|
|
old = ''' .bench-note{font-family:var(--font-mono);font-size:var(--size-caption);'''
|
|
new = ''' .bench-note{font-family:var(--font-mono);font-size:var(--size-micro);'''
|
|
|
|
[[mutation]]
|
|
label = "S2 retired benches faded again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop.py::test_retired_benches_are_not_faded"
|
|
old = ''' .bench-row.is-retired .bench-link,.bench-row.is-retired .bench-url{color:var(--text-muted)}'''
|
|
new = ''' .bench-row.is-retired{opacity:.5}'''
|
|
|
|
[[mutation]]
|
|
label = "S2 an answered ask's option details faded again"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop.py::test_embed_fades_nothing"
|
|
old = ''' ".bk-ask-det{font-size:.82rem}",'''
|
|
new = ''' ".bk-ask-det{font-size:.82rem;opacity:.68}",'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the recorded line faded again"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop.py::test_embed_fades_nothing"
|
|
old = ''' ".bk-ask-was{margin:.15rem 0 .55rem;font-size:.86rem}",'''
|
|
new = ''' ".bk-ask-was{margin:.15rem 0 .55rem;font-size:.86rem;opacity:.8}",'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the notes placeholder back to the browser's grey"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop.py::test_embed_fades_nothing"
|
|
old = ''' ".bk-ask-notes::placeholder{color:inherit;opacity:.75}",'''
|
|
new = ''''''
|
|
|
|
[[mutation]]
|
|
label = "S2 the inline ask's state tag back at 10.5px"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop.py::test_the_ask_tag_meets_the_label_floor"
|
|
old = """ "font:600 11px/1.3 'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;","""
|
|
new = """ "font:600 10.5px/1.3 'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace;","""
|
|
|
|
# ---- S2, folded from the heid bug-hunt guard grid: what the COMPUTED style shows
|
|
|
|
[[mutation]]
|
|
label = "S2 the ask title fades (Q9)"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop_s2_browser.py::test_nothing_fades"
|
|
old = """ "letter-spacing:.12em;text-transform:uppercase}","""
|
|
new = """ "letter-spacing:.12em;text-transform:uppercase;opacity:.62}","""
|
|
|
|
[[mutation]]
|
|
label = "S2 a later rule shrinks the film numbers (cascade, not shorthand)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_s2_browser.py::test_labels_and_sentences_render_at_their_floors"
|
|
old = """ .film-ord{position:absolute;left:3px;top:3px;padding:1px 4px;border-radius:var(--radius-sm);
|
|
font:600 var(--size-micro)/1.2 var(--font-mono);background:oklch(0.17 0.01 250 / .85);color:oklch(0.91 0.008 216)}"""
|
|
new = """ .film-ord{position:absolute;left:3px;top:3px;padding:1px 4px;border-radius:var(--radius-sm);
|
|
font:600 var(--size-micro)/1.2 var(--font-mono);background:oklch(0.17 0.01 250 / .85);color:oklch(0.91 0.008 216);font-size:1px}"""
|
|
|
|
[[mutation]]
|
|
label = "S2 the details go transparent without any opacity"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop_s2_browser.py::test_nothing_fades"
|
|
old = """ ".bk-ask-det{font-size:.82rem}","""
|
|
new = """ ".bk-ask-det{font-size:.82rem;color:transparent}","""
|
|
|
|
[[mutation]]
|
|
label = "S2 the placeholder vanishes (opacity 0) while keeping color:inherit"
|
|
file = "booth/static/embed.js"
|
|
test = "tests/test_antislop_s2_browser.py::test_nothing_fades"
|
|
old = """ ".bk-ask-notes::placeholder{color:inherit;opacity:.75}","""
|
|
new = """ ".bk-ask-notes::placeholder{color:inherit;opacity:0}","""
|
|
|
|
[[mutation]]
|
|
label = "S2 retired benches greyed by a filter instead of opacity"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_s2_browser.py::test_nothing_fades"
|
|
old = """ .bench-row.is-retired .bench-link,.bench-row.is-retired .bench-url{color:var(--text-muted)}"""
|
|
new = """ .bench-row.is-retired .bench-link,.bench-row.is-retired .bench-url{color:var(--text-muted)}
|
|
.bench-row.is-retired{filter:grayscale(.6) opacity(.5)}"""
|
|
|
|
[[mutation]]
|
|
label = "S2 the flagged tray's number back at 10px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_s2_browser.py::test_labels_and_sentences_render_at_their_floors"
|
|
old = ''' .tray-ord{position:absolute;left:3px;bottom:3px;padding:1px 4px;border-radius:var(--radius-sm);
|
|
font:600 var(--size-micro)/1.2 var(--font-mono);'''
|
|
new = ''' .tray-ord{position:absolute;left:3px;bottom:3px;padding:1px 4px;border-radius:var(--radius-sm);
|
|
font:600 10px/1.2 var(--font-mono);'''
|
|
|
|
[[mutation]]
|
|
label = "S2 the tile's flagged stamp back at 10.5px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_s2_browser.py::test_labels_and_sentences_render_at_their_floors"
|
|
old = ''' font:600 var(--size-micro)/1.3 var(--font-mono);letter-spacing:var(--tracking-caps);text-transform:uppercase;'''
|
|
new = ''' font:600 10.5px/1.3 var(--font-mono);letter-spacing:var(--tracking-caps);text-transform:uppercase;'''
|
|
|
|
[[mutation]]
|
|
label = "S2 compare's A/B badge back at 9.5px"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_s2_browser.py::test_labels_and_sentences_render_at_their_floors"
|
|
old = ''' font:700 var(--size-micro)/1.2 var(--font-mono);background:var(--accent);color:var(--accent-contrast)}'''
|
|
new = ''' font:700 9.5px/1.2 var(--font-mono);background:var(--accent);color:var(--accent-contrast)}'''
|
|
|
|
# ---- S3: phone layouts (measured in a real browser at 390x844)
|
|
|
|
[[mutation]]
|
|
label = "S3 bench rows squeeze instead of wrapping"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_bench_rows_do_not_overprint_on_a_phone"
|
|
old = ''' .bench-row{flex-wrap:wrap;row-gap:4px}'''
|
|
new = ''' .bench-row{row-gap:4px}'''
|
|
|
|
[[mutation]]
|
|
label = "S3 the board head's phone rule gone (the count wraps)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_board_head_stays_compact_on_a_phone"
|
|
old = ''' @media (max-width:600px){.board-head{flex-wrap:wrap}.board-title{white-space:nowrap}'''
|
|
new = ''' @media (max-width:1px){.board-head{flex-wrap:wrap}.board-title{white-space:nowrap}'''
|
|
|
|
[[mutation]]
|
|
label = "S3 the doc bar squeezes the name again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_doc_name_keeps_a_readable_line_on_a_phone"
|
|
old = ''' @media (max-width:600px){.doc-inline > .doc-bar{flex-wrap:wrap;row-gap:4px}'''
|
|
new = ''' @media (max-width:1px){.doc-inline > .doc-bar{flex-wrap:wrap;row-gap:4px}'''
|
|
|
|
[[mutation]]
|
|
label = "S3 a file tile's link starts under the number again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_file_tile_number_clears_the_download_link"
|
|
old = ''' .item > .ord ~ .dl{padding-top:44px}'''
|
|
new = ''''''
|
|
|
|
[[mutation]]
|
|
label = "S3 the review keeps its tagline on a phone"
|
|
file = "booth/templates/view.html"
|
|
test = "tests/test_antislop_browser.py::test_review_header_is_one_line_on_a_phone"
|
|
old = '''{% block body_attrs %} class="page-stage"{% endblock %}'''
|
|
new = ''''''
|
|
|
|
[[mutation]]
|
|
label = "S3 the tagline hidden on every page (the Desk's negative control)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_review_header_is_one_line_on_a_phone"
|
|
old = ''' @media (max-width:600px){body.page-stage .topbar .tagline{display:none}}'''
|
|
new = ''' @media (max-width:600px){body .topbar .tagline{display:none}}'''
|
|
|
|
[[mutation]]
|
|
label = "S3 the benches head stacks its count again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_board_head_stays_compact_on_a_phone"
|
|
old = """ .bench-head{flex-wrap:wrap}.bench-title{white-space:nowrap}.bench-note{flex:1 1 100%}}"""
|
|
new = """ }"""
|
|
|
|
# ---- S4: reading measure
|
|
|
|
[[mutation]]
|
|
label = "S4 prose runs the full width again"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_doc_prose_reads_at_a_book_measure"
|
|
old = """ .markdown-body > :is(p,ul,ol,blockquote,dl,h1,h2,h3,h4,h5,h6){max-width:72ch}"""
|
|
new = """"""
|
|
|
|
[[mutation]]
|
|
label = "S4 h3 flat against its body again (1.08em)"
|
|
file = "booth/templates/base.html"
|
|
test = "tests/test_antislop_browser.py::test_doc_headings_step_by_size"
|
|
old = """.markdown-body h3{font-size:1.2em;font-weight:600}"""
|
|
new = """.markdown-body h3{font-size:1.08em;font-weight:600}"""
|