Summary
deferredwork._one_line (added in #305) guards line breaks and documents a stronger contract
than it delivers:
Sanitizes; never raises. The close paths call these writers bare (sweep._close_resolved,
decisions.apply_pre_answer), so a ValueError here would end the sweep as crashed.
A lone surrogate defeats that without ever being a line break. Verified chain:
json.loads on a session result.json containing "\ud800" yields the surrogate.
validate_triage returns errors == [] and carries it into ResolvedEntry.evidence.
LINE_BREAK_RE.search is False, so _one_line passes it through untouched.
- The write raises
UnicodeEncodeError — a ValueError subclass — at sweep.py:942
(_close_resolved), sweep.py:1071, or decisions.py:147.
That is precisely the outcome the sanitizer exists to prevent: a bare call on a close path taking
down the run. It compounds with the bare write_text issue, where the same call both raises and
truncates the ledger to zero bytes.
Pre-existing — the writers always encoded UTF-8 — but #305 introduced the "never raises" claim, so
either the claim or the code should change.
Fix shape
Either narrow the docstring to "never raises on a line break", or make it true:
value.encode("utf-8", "replace").decode("utf-8") before the break collapse. The latter keeps the
close paths genuinely crash-free, which is the doctrine #305 settled on.
Also worth checking: tui/app.py:_record_decision now catches ValueError, so the TUI degrades —
but the sweep close path has no such guard.
Found during the #305 review.
Summary
deferredwork._one_line(added in #305) guards line breaks and documents a stronger contractthan it delivers:
A lone surrogate defeats that without ever being a line break. Verified chain:
json.loadson a sessionresult.jsoncontaining"\ud800"yields the surrogate.validate_triagereturnserrors == []and carries it intoResolvedEntry.evidence.LINE_BREAK_RE.searchisFalse, so_one_linepasses it through untouched.UnicodeEncodeError— aValueErrorsubclass — atsweep.py:942(
_close_resolved),sweep.py:1071, ordecisions.py:147.That is precisely the outcome the sanitizer exists to prevent: a bare call on a close path taking
down the run. It compounds with the bare
write_textissue, where the same call both raises andtruncates the ledger to zero bytes.
Pre-existing — the writers always encoded UTF-8 — but #305 introduced the "never raises" claim, so
either the claim or the code should change.
Fix shape
Either narrow the docstring to "never raises on a line break", or make it true:
value.encode("utf-8", "replace").decode("utf-8")before the break collapse. The latter keeps theclose paths genuinely crash-free, which is the doctrine #305 settled on.
Also worth checking:
tui/app.py:_record_decisionnow catchesValueError, so the TUI degrades —but the sweep close path has no such guard.
Found during the #305 review.