Tests that found things reading did not

The testing pass: 2140 tests to 2283, and four bugs that no amount of
reading had turned up. Three came from driving the JavaScript under a
Node DOM stub, which is the practice CLAUDE.md sets out and this is the
reason it does.

The terminal dropped every keystroke after a reconnect. `onclose` closed
over the module-level socket rather than its own, and close() queues its
event -- so the old socket's close arrived after a new one was assigned
and nulled the live one. Output kept coming, because onmessage is bound
to the object, while every send gates on the variable. It also announced
"Disconnected" about a shell that had just reconnected.

Two scripts were loaded twice on /messages, once by base.html and again
by the page. Each is an IIFE with its own state, so four keyboard
shortcuts toggled their panel twice and therefore did nothing, /help
opened two dialogs, and an @ mention attached its file twice. A sweep
refuses any template re-loading what base.html has.

The microphone had no guard while the permission prompt was up, so each
click opened another stream and only the last was ever stopped. And a
skill shared with you took its name out of your own library: create
checked uniqueness against what is *visible* rather than what is owned,
against a (owner_id, name) constraint, and told you to edit a row you
cannot edit.

--ink-faint failed the contrast minimum in both themes -- 3.85 and 3.19
against 4.5 -- so the smallest text on every screen was the hardest to
read. Measured in a headless browser rather than judged by eye.

And the suite runs on 3.11 and 3.12 now as well as 3.14. It had only ever
run on 3.14 while the image ships 3.12 and the packaging claimed 3.11:
the interpreter most people would run was the one nothing had tested.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-07 14:41:45 +02:00
parent 25fe81a224
commit 0514568df0
33 changed files with 2859 additions and 13 deletions
+106
View File
@@ -300,6 +300,112 @@ def control_named(html: str, name: str) -> dict[str, str]:
return found[0]
def script(name: str) -> str:
"""One of the shipped browser files, as text.
There is no JavaScript test runner here -- hard rule 1 keeps Node out of the
project -- so behaviour is driven by hand under a DOM stub and what the
suite pins is what the source says about itself.
"""
import lembas
return (Path(lembas.__file__).parent / "web/static/js" / name).read_text(encoding="utf-8")
def js_code(source: str) -> str:
"""The same source with its comments blanked out.
These files are heavily commented, and every comment names the thing it is
explaining -- so `"list" in refresh` is true of a paragraph saying that
writing to `list` too early was the bug. An invariant about the code must
not be satisfiable by prose describing it. String literals are left intact,
because the assertions are usually about an event name inside one.
"""
out: list[str] = []
at, end = 0, len(source)
while at < end:
char = source[at]
if char in "\"'`":
quote = char
out.append(char)
at += 1
while at < end:
if source[at] == "\\":
out.append(source[at : at + 2])
at += 2
continue
out.append(source[at])
at += 1
if source[at - 1] == quote:
break
continue
if char == "/" and source[at : at + 2] in ("//", "/*"):
stop = (
source.find("\n", at)
if source[at + 1] == "/"
else source.find("*/", at) + 2
)
if stop <= at:
stop = end
# Blanked rather than removed, so every offset still lines up.
out.append("".join(" " if c != "\n" else "\n" for c in source[at:stop]))
at = stop
continue
out.append(char)
at += 1
return "".join(out)
def js_says(text: str, *pieces: str) -> bool:
"""Whether the pieces appear, in order, whatever sits between them.
Asserting a line verbatim makes a test that fails on reindentation, which is
noise; asserting only that two words appear somewhere makes one that never
fails at all. This is the middle: the shape, not the spacing.
"""
at = 0
for piece in pieces:
at = text.find(piece, at)
if at == -1:
return False
at += len(piece)
return True
def js_function(source: str, name: str) -> str:
"""The text of one named function, braces matched.
Lets a test ask about the inside of a handler rather than about the file --
"is `build()` called before anything writes to `list`" is a question about
`refresh`, and asking it of the whole source answers yes for the wrong
reason.
"""
code = js_code(source)
# The parenthesis is load-bearing: `token` is a prefix of `tokenAt`, and
# asking about the wrong function is a test that passes for no reason.
start = code.index(f"function {name}(")
at = code.index("{", start)
depth, quote = 0, ""
while at < len(code):
char = code[at]
if quote:
if char == "\\":
at += 2
continue
if char == quote:
quote = ""
elif char in "\"'`":
quote = char
elif char == "{":
depth += 1
elif char == "}":
depth -= 1
if depth == 0:
return code[start : at + 1]
at += 1
raise AssertionError(f"no closing brace for {name}()")
@pytest.fixture
def user_id(db: Session, registered: dict[str, str]) -> str:
"""The registered user's id.