hertz -> todlando: H3 names (crates/spt/tests/peer_rig/mod.rs, NOT common/ — common compiles into 103 bins; consumers write `mod peer_rig;`): - peer_rig::signing — ReleaseSigner{seed,key_id,channel}: verifying_hex(), write_release_keys(home), policy(current_version), set(version) -> SetBuilder .artifact(triple,bytes,asset).current(bytes,asset).docs(asset,bytes).build() -> SignedUpdateSet (+ .json()). - peer_rig::adapter — MockAdapter::new(name,version).kind(k).signed_by(seed) .archive(scratch) -> MockAdapterArchive{bytes,sha256,sig_hex:Option,verifying_hex:Option,manifest}; .write_release_dir(dir) (adapter.spt + adapter.spt.sig for gh_fixture); .roster_row() -> RosterRowExpect{name,kind,version,sha256,signing_key} (W3 maps it onto its real record type). - peer_rig::bundle — MockBundle::new().member(&archive).build(scratch) -> BundleAsset{bytes,sha256}; shape = tar.gz: bundle.json {members:[{name,version,asset,sha256}]} + .spt. This is also the shape H2's release side will emit — shout if W5 wants different. - peer_rig::inproc — hermetic(), net_broker(), connect_retry(), InprocNode{name,cache}.node_id()/addr(), roster_for(peers). - peer_rig::wait — StreamCursor::snapshot(&mut brain).wait_new(&mut brain) (replaces wait_for_stream_except), wait_past(what, cursor, read) for any monotonic state (cache version, notif seq, io-events seq); bound = RIG_WAIT (rig-owned, early-exit, elapsed printed in the red), never a product constant. Real-daemon lift (DaemonGuard/seed_home/own_addr from webserve_cross_node_e2e, pump configurable) = follow-up PR once W7 says it needs real daemons. Objections in the next ~20 min, else I build it.