739	const XLATE_BIN: &str = env!("CARGO_BIN_EXE_xlate_choreo_fixture");
740
741	/// The proven cross-OS echo PTY child (stdin → stdout, line-buffered).
742	fn echo_program() -> (String, Vec<String>) {
743	    #[cfg(unix)]
744	    {
745	        ("cat".to_string(), Vec::<String>::new())
746	    }
747	    #[cfg(windows)]
748	    {
749	        ("findstr".to_string(), vec![".".to_string()])
750	    }
751	}
752
753	/// A translation-bearing spawn: the PTY child is the real echo child (so the
754	/// injected/operator bytes echo back through the broker ring), and the
755	/// `translation_binary` is the real `xlate_choreo_fixture`. The fixture env vars
756	/// must already be set in THIS process (set_var before the session spawns the
757	/// child — clean under nextest's process-per-test).
758	fn xlate_spawn_req(endpoint: &str) -> SpawnReq {
759	    let (program, args) = echo_program();
760	    SpawnReq {
761	        program,
762	        args,
763	        rows: 24,
764	        cols: 80,
765	        endpoint: endpoint.to_string(),
766	        cwd: None,
767	        env: Default::default(),
768	        translation_binary: Some(XLATE_BIN.to_string()),
769	    }
770	}
771
772	/// Attach a viewer brain to a session and accumulate its output bytes until either
773	/// `needle` appears (→ true) or `deadline` elapses (→ false). The structural
774	/// byte-receipt seam: bytes that reach the PTY are echoed by the child and arrive
775	/// here over the REAL broker output ring. Drains on its own connection so the
776	/// caller's controller socket is untouched.
777	fn output_contains_within(name: &str, sid: u64, needle: &[u8], deadline: Duration) -> bool {
778	    // PUMP mode (Split) so `read_event_until` actually HONORS the deadline — a
779	    // plain `Whole` cold_start ignores it (read_frame blocks), which would hang
780	    // forever if the PTY produced no output (e.g. an XOFF-stalled terminal).
781	    let mut viewer = match Brain::cold_start_pump(name, 1, Duration::from_secs(2)) {
782	        Ok(b) => b,
783	        Err(_) => return false,
784	    };
785	    if viewer.attach(sid, 0).is_err() {
786	        return false;
787	    }
788	    let mut acc: Vec<u8> = Vec::new();
789	    let stop = Instant::now() + deadline;
790	    while Instant::now() < stop {
791	        match viewer.read_event_until(Some(Instant::now() + Duration::from_millis(150))) {
792	            Ok(BrokerEvent::Output { bytes, .. }) => {
793	                acc.extend_from_slice(&bytes);
794	                if count(&acc, needle) >= 1 {
795	                    return true;
796	                }
797	            }
798	            Ok(_) => continue,
799	            Err(_) => continue,
800	        }
801	    }
802	    false
803	}
804
805	/// Observe `needle` in a session's output ring while interleaving OPERATOR XON
806	/// (`ctrl+q` = 0x11) keystrokes to RESUME any XOFF-paused output (the choreography's
807	/// `ctrl+s`/0x13 pauses this ConPTY's output flow, stranding the echoed payload).
808	/// When `type_needle` is set, the helper ALSO types `needle\r` itself (for the
809	/// fresh-attach serviceability marker the operator originates); for the injected
810	/// payload it is `false` (we must NOT type the payload — that would be a false pass;
811	/// we only un-stick the flow so the BINARY-injected payload's echo can flush).
812	/// Pump mode → bounded reads. Returns true once `needle` appears.
813	fn observe_with_xon(
814	    name: &str,
815	    sid: u64,
816	    needle: &[u8],
817	    type_needle: bool,
818	    deadline: Duration,
819	) -> bool {
820	    let mut op = match Brain::cold_start_pump(name, 1, Duration::from_secs(2)) {
821	        Ok(b) => b,
822	        Err(_) => return false,
823	    };
824	    if op.attach(sid, 0).is_err() {
825	        return false;
826	    }
827	    let mut acc: Vec<u8> = Vec::new();
828	    let stop = Instant::now() + deadline;
829	    while Instant::now() < stop {
830	        // XON pulse to resume paused output; optionally re-type the operator marker.
831	        let _ = op.send_input(b"\x11");
832	        if type_needle {
833	            let mut line = needle.to_vec();
834	            line.push(b'\r');
835	            let _ = op.send_input(&line);
836	        }
837	        // Drain a slice of output, accumulating, before the next pulse.
838	        let slice = Instant::now() + Duration::from_millis(250);
839	        while Instant::now() < slice {
840	            match op.read_event_until(Some(Instant::now() + Duration::from_millis(120))) {
841	                Ok(BrokerEvent::Output { bytes, .. }) => {
842	                    acc.extend_from_slice(&bytes);
843	                    if count(&acc, needle) >= 1 {
844	                        return true;
845	                    }
846	                }
847	                Ok(_) => continue,
848	                Err(_) => break,
849	            }
850	        }
851	    }
852	    false
853	}
854
855	/// Deliver an inbound `<EVENT>` to a hosted endpoint via a raw `KIND_ENDPOINT_INPUT`
856	/// frame on a fresh brain connection (the Brain client has no endpoint-input
857	/// helper), and return whether the broker acked `delivered=true` within `deadline`.
858	/// Runs the exchange on a thread so a wedged reply surfaces as a timeout, not a hang.
859	fn deliver_endpoint_event(name: &str, endpoint: &str, envelope: &[u8], deadline: Duration) -> bool {
860	    let name = name.to_string();
861	    let endpoint = endpoint.to_string();
862	    let envelope = envelope.to_vec();
863	    let (tx, rx) = std::sync::mpsc::channel::<bool>();
864	    thread::spawn(move || {
865	        let mut conn = match LocalSocketTransport::connect(&name) {
866	            Ok(c) => c,
867	            Err(_) => {
868	                let _ = tx.send(false);
869	                return;
870	            }
871	        };
872	        if send_hello(&mut conn, Role::Brain).is_err() {
873	            let _ = tx.send(false);
874	            return;
875	        }
876	        send(
877	            &mut conn,
878	            KIND_ENDPOINT_INPUT,
879	            serde_json::to_value(EndpointInputReq {
880	                endpoint: endpoint.clone(),
881	                data_b64: encode_bytes(&envelope),
882	            })
883	            .unwrap(),
884	        );
885	        loop {
886	            match read_frame(&mut conn) {
887	                Ok(f) if f.kind == KIND_ENDPOINT_INJECTED => {
888	                    // The reply carries `delivered`; surface it.
889	                    let delivered = f
890	                        .payload
891	                        .get("delivered")
892	                        .and_then(|d| d.as_bool())
893	                        .unwrap_or(false);
894	                    let _ = tx.send(delivered);
895	                    return;
896	                }
897	                Ok(_) => continue,
898	                Err(_) => {
899	                    let _ = tx.send(false);
900	                    return;
901	                }
902	            }
903	        }
904	    });
905	    rx.recv_timeout(deadline).unwrap_or(false)
906	}
907
908	/// Whether a pid is still a live process (the no-zombie reap check). Best-effort
909	/// and cross-OS: a `tasklist` query on Windows, `kill -0` on Unix.
910	#[cfg(windows)]
911	fn pid_alive(pid: u32) -> bool {
912	    let out = std::process::Command::new("tasklist")
913	        .args(["/FI", &format!("PID eq {pid}"), "/NH"])
914	        .output();
915	    match out {
916	        Ok(o) => {
917	            let s = String::from_utf8_lossy(&o.stdout);
918	            // tasklist prints the row when the pid is live; "No tasks" otherwise.
919	            s.contains(&pid.to_string())
920	        }
921	        Err(_) => false,
922	    }
923	}
924	#[cfg(unix)]
925	fn pid_alive(pid: u32) -> bool {
926	    std::process::Command::new("kill")
927	        .args(["-0", &pid.to_string()])
928	        .status()
929	        .map(|s| s.success())
930	        .unwrap_or(false)
931	}
932
933	/// Spawn the translation-bearing session on a fresh net-broker and return the
934	/// (broker, name, sid, controller-brain). The controller brain stays attached as
935	/// the live operator (the W1 coexistence partner) and is RETURNED so the test
936	/// keeps it alive + can probe it; the caller drains it as needed.
937	fn spawn_xlate_session(
938	    name: &str,
939	    dir: &std::path::Path,
940	    endpoint: &str,
941	) -> (Arc<Broker>, u64, Brain) {
942	    let broker = net_broker(name, dir);
943	    // PUMP mode so the spawner-controller's reads are BOUNDED (a Whole conn ignores
944	    // the read deadline → a drainer loop would block forever and never observe a
945	    // stop flag, hanging the test on join). The pump reader drains the controller's
946	    // socket so it stays serviceable without the test blocking.
947	    let mut spawner = {
948	        let mut b = None;
949	        for _ in 0..300 {
950	            if let Ok(c) = Brain::cold_start_pump(name, 1, Duration::from_secs(2)) {
951	                b = Some(c);
952	                break;
953	            }
954	            thread::sleep(Duration::from_millis(10));
955	        }
956	        b.expect("brain could not connect (pump)")
957	    };
958	    let sid = spawner
959	        .spawn_session(xlate_spawn_req(endpoint))
960	        .expect("spawn translation-bearing session");
961	    (broker, sid, spawner)
962	}
963
964	#[test]
965	fn g1_choreography_happy_path_payload_reaches_pty_and_controller_keeps_control() {
966	    init_wedge_home();
967	    let dir = tempfile::tempdir().expect("tempdir");
968	    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");

const XLATE_BIN: &str = env!("CARGO_BIN_EXE_xlate_choreo_fixture");

/// The proven cross-OS echo PTY child (stdin → stdout, line-buffered).
fn echo_program() -> (String, Vec<String>) {
    #[cfg(unix)]
    {
        ("cat".to_string(), Vec::<String>::new())
    }
    #[cfg(windows)]
    {
        ("findstr".to_string(), vec![".".to_string()])
    }
}

/// A translation-bearing spawn: the PTY child is the real echo child (so the
/// injected/operator bytes echo back through the broker ring), and the
/// `translation_binary` is the real `xlate_choreo_fixture`. The fixture env vars
/// must already be set in THIS process (set_var before the session spawns the
/// child — clean under nextest's process-per-test).
fn xlate_spawn_req(endpoint: &str) -> SpawnReq {
    let (program, args) = echo_program();
    SpawnReq {
        program,
        args,
        rows: 24,
        cols: 80,
        endpoint: endpoint.to_string(),
        cwd: None,
        env: Default::default(),
        translation_binary: Some(XLATE_BIN.to_string()),
    }
}

/// Attach a viewer brain to a session and accumulate its output bytes until either
/// `needle` appears (→ true) or `deadline` elapses (→ false). The structural
/// byte-receipt seam: bytes that reach the PTY are echoed by the child and arrive
/// here over the REAL broker output ring. Drains on its own connection so the
/// caller's controller socket is untouched.
fn output_contains_within(name: &str, sid: u64, needle: &[u8], deadline: Duration) -> bool {
    // PUMP mode (Split) so `read_event_until` actually HONORS the deadline — a
    // plain `Whole` cold_start ignores it (read_frame blocks), which would hang
    // forever if the PTY produced no output (e.g. an XOFF-stalled terminal).
    let mut viewer = match Brain::cold_start_pump(name, 1, Duration::from_secs(2)) {
        Ok(b) => b,
        Err(_) => return false,
    };
    if viewer.attach(sid, 0).is_err() {
        return false;
    }
    let mut acc: Vec<u8> = Vec::new();
    let stop = Instant::now() + deadline;
    while Instant::now() < stop {
        match viewer.read_event_until(Some(Instant::now() + Duration::from_millis(150))) {
            Ok(BrokerEvent::Output { bytes, .. }) => {
                acc.extend_from_slice(&bytes);
                if count(&acc, needle) >= 1 {
                    return true;
                }
            }
            Ok(_) => continue,
            Err(_) => continue,
        }
    }
    false
}

/// Observe `needle` in a session's output ring while interleaving OPERATOR XON
/// (`ctrl+q` = 0x11) keystrokes to RESUME any XOFF-paused output (the choreography's
/// `ctrl+s`/0x13 pauses this ConPTY's output flow, stranding the echoed payload).
/// When `type_needle` is set, the helper ALSO types `needle\r` itself (for the
/// fresh-attach serviceability marker the operator originates); for the injected
/// payload it is `false` (we must NOT type the payload — that would be a false pass;
/// we only un-stick the flow so the BINARY-injected payload's echo can flush).
/// Pump mode → bounded reads. Returns true once `needle` appears.
fn observe_with_xon(
    name: &str,
    sid: u64,
    needle: &[u8],
    type_needle: bool,
    deadline: Duration,
) -> bool {
    let mut op = match Brain::cold_start_pump(name, 1, Duration::from_secs(2)) {
        Ok(b) => b,
        Err(_) => return false,
    };
    if op.attach(sid, 0).is_err() {
        return false;
    }
    let mut acc: Vec<u8> = Vec::new();
    let stop = Instant::now() + deadline;
    while Instant::now() < stop {
        // XON pulse to resume paused output; optionally re-type the operator marker.
        let _ = op.send_input(b"\x11");
        if type_needle {
            let mut line = needle.to_vec();
            line.push(b'\r');
            let _ = op.send_input(&line);
        }
        // Drain a slice of output, accumulating, before the next pulse.
        let slice = Instant::now() + Duration::from_millis(250);
        while Instant::now() < slice {
            match op.read_event_until(Some(Instant::now() + Duration::from_millis(120))) {
                Ok(BrokerEvent::Output { bytes, .. }) => {
                    acc.extend_from_slice(&bytes);
                    if count(&acc, needle) >= 1 {
                        return true;
                    }
                }
                Ok(_) => continue,
                Err(_) => break,
            }
        }
    }
    false
}

/// Deliver an inbound `<EVENT>` to a hosted endpoint via a raw `KIND_ENDPOINT_INPUT`
/// frame on a fresh brain connection (the Brain client has no endpoint-input
/// helper), and return whether the broker acked `delivered=true` within `deadline`.
/// Runs the exchange on a thread so a wedged reply surfaces as a timeout, not a hang.
fn deliver_endpoint_event(name: &str, endpoint: &str, envelope: &[u8], deadline: Duration) -> bool {
    let name = name.to_string();
    let endpoint = endpoint.to_string();
    let envelope = envelope.to_vec();
    let (tx, rx) = std::sync::mpsc::channel::<bool>();
    thread::spawn(move || {
        let mut conn = match LocalSocketTransport::connect(&name) {
            Ok(c) => c,
            Err(_) => {
                let _ = tx.send(false);
                return;
            }
        };
        if send_hello(&mut conn, Role::Brain).is_err() {
            let _ = tx.send(false);
            return;
        }
        send(
            &mut conn,
            KIND_ENDPOINT_INPUT,
            serde_json::to_value(EndpointInputReq {
                endpoint: endpoint.clone(),
                data_b64: encode_bytes(&envelope),
            })
            .unwrap(),
        );
        loop {
            match read_frame(&mut conn) {
                Ok(f) if f.kind == KIND_ENDPOINT_INJECTED => {
                    // The reply carries `delivered`; surface it.
                    let delivered = f
                        .payload
                        .get("delivered")
                        .and_then(|d| d.as_bool())
                        .unwrap_or(false);
                    let _ = tx.send(delivered);
                    return;
                }
                Ok(_) => continue,
                Err(_) => {
                    let _ = tx.send(false);
                    return;
                }
            }
        }
    });
    rx.recv_timeout(deadline).unwrap_or(false)
}

/// Whether a pid is still a live process (the no-zombie reap check). Best-effort
/// and cross-OS: a `tasklist` query on Windows, `kill -0` on Unix.
#[cfg(windows)]
fn pid_alive(pid: u32) -> bool {
    let out = std::process::Command::new("tasklist")
        .args(["/FI", &format!("PID eq {pid}"), "/NH"])
        .output();
    match out {
        Ok(o) => {
            let s = String::from_utf8_lossy(&o.stdout);
            // tasklist prints the row when the pid is live; "No tasks" otherwise.
            s.contains(&pid.to_string())
        }
        Err(_) => false,
    }
}
#[cfg(unix)]
fn pid_alive(pid: u32) -> bool {
    std::process::Command::new("kill")
        .args(["-0", &pid.to_string()])
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

/// Spawn the translation-bearing session on a fresh net-broker and return the
/// (broker, name, sid, controller-brain). The controller brain stays attached as
/// the live operator (the W1 coexistence partner) and is RETURNED so the test
/// keeps it alive + can probe it; the caller drains it as needed.
fn spawn_xlate_session(
    name: &str,
    dir: &std::path::Path,
    endpoint: &str,
) -> (Arc<Broker>, u64, Brain) {
    let broker = net_broker(name, dir);
    // PUMP mode so the spawner-controller's reads are BOUNDED (a Whole conn ignores
    // the read deadline → a drainer loop would block forever and never observe a
    // stop flag, hanging the test on join). The pump reader drains the controller's
    // socket so it stays serviceable without the test blocking.
    let mut spawner = {
        let mut b = None;
        for _ in 0..300 {
            if let Ok(c) = Brain::cold_start_pump(name, 1, Duration::from_secs(2)) {
                b = Some(c);
                break;
            }
            thread::sleep(Duration::from_millis(10));
        }
        b.expect("brain could not connect (pump)")
    };
    let sid = spawner
        .spawn_session(xlate_spawn_req(endpoint))
        .expect("spawn translation-bearing session");
    (broker, sid, spawner)
}

#[test]
fn g1_choreography_happy_path_payload_reaches_pty_and_controller_keeps_control() {
    init_wedge_home();
    let dir = tempfile::tempdir().expect("tempdir");
    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");


965	fn g1_choreography_happy_path_payload_reaches_pty_and_controller_keeps_control() {
966	    init_wedge_home();
967	    let dir = tempfile::tempdir().expect("tempdir");
968	    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");
969	    std::env::remove_var("XLATE_FIXTURE_STDIN_LOG");
970	    std::env::remove_var("SPT_INJECT_COMMIT_DEADLINE_MS");
971
972	    let name = unique_name();
973	    let endpoint = "xlate-g1-ep";
974	    // The PTY child is the proven cross-OS ECHO child: the injected payload echoes
975	    // back over the REAL broker output ring (a custom child reading io::stdin() does
976	    // NOT receive ConPTY input writes — only a console-native app like findstr/cat
977	    // does, which is why byte-receipt is observed through the echo, not a side file).
978	    let (broker, sid, mut controller) =
979	        spawn_xlate_session(&name, &dir.path().join("g1"), endpoint);
980
981	    // Keep the spawning controller brain DRAINED on a background thread so it stays
982	    // the live, serviceable operator (the W1 coexistence partner) while the injection
983	    // runs. Pump mode → the read deadline is honored, so the stop flag is observed.
984	    let stop = Arc::new(AtomicBool::new(false));
985	    let drain_stop = Arc::clone(&stop);
986	    let drainer = thread::spawn(move || {
987	        while !drain_stop.load(Ordering::Relaxed) {
988	            let _ =
989	                controller.read_event_until(Some(Instant::now() + Duration::from_millis(100)));
990	        }
991	        controller // hand it back so it is dropped only after teardown
992	    });
993
994	    // ── Deliver an inbound message as a real `<EVENT…>` envelope via KIND_ENDPOINT_INPUT.
995	    //    A live (non-faulted) translation binary OWNS the choreography → the broker
996	    //    queues the whole envelope to the inject worker, which drives it through the
997	    //    binary and applies the resulting keystrokes to the PTY atomically. ──
998	    let envelope = br#"<EVENT type="message" from="peer">hello translation</EVENT>"#;
999	    let delivered = deliver_endpoint_event(&name, endpoint, envelope, Duration::from_secs(8));
1000
1001	    // (b) BYTE RECEIPT: the choreography's `{text:"XLATE_OK"}` actually reached the
1002	    // PTY — observed via the echo child's output over the REAL broker ring (the
1003	    // real-receipt assertion W1's gate lacked, not merely liveness). The choreography's
1004	    // `ctrl+s` (0x13 = XOFF) pauses this ConPTY's OUTPUT flow, stranding the echoed
1005	    // payload; so we interleave OPERATOR XON keystrokes (`ctrl+q` = 0x11 — exactly
1006	    // what a real operator does to un-stick a frozen terminal, and proof injection
1007	    // coexists with live operator input) WHILE polling the ring until the payload
1008	    // echo flushes. The payload byte already landed on the PTY (XOFF gates output,
1009	    // not the input write); XON releases its buffered echo deterministically.
1010	    let payload_reached = observe_with_xon(&name, sid, b"XLATE_OK", false, Duration::from_secs(12));
1011
1012	    // (a) The controller/operator STAYS SERVICEABLE through + after the injection
1013	    // (the W1 non-wedge bar): KIND_SESSIONS still answers, and a FRESH attach drives
1014	    // input and sees it echo back (XON-resumed). Injection coexisted with the live
1015	    // controller via the floor.
1016	    let sessions_answered =
1017	        probe(&name, KIND_SESSIONS, KIND_SESSIONS_REPLY, Duration::from_secs(5));
1018	    let fresh_attach_served =
1019	        observe_with_xon(&name, sid, b"G1_FRESH_MARKER", true, Duration::from_secs(8));
1020
1021	    // Teardown: reap the PTY child + the controller drainer.
1022	    if let Some(pid) = broker.session_pid(sid) {
1023	        kill_pid(pid);
1024	    }
1025	    stop.store(true, Ordering::Relaxed);
1026	    let _ = drainer.join();
1027
1028	    eprintln!(
1029	        "=== W2 G1 CHOREO GATE: delivered={delivered} payload_reached_pty={payload_reached} \
1030	         sessions_answered={sessions_answered} fresh_attach_served={fresh_attach_served} \
1031	         (all true = inject coexists with a live controller; payload landed via the binary) ==="
1032	    );
1033
1034	    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
1035	    assert!(
1036	        delivered,
1037	        "the broker must accept the endpoint event (queued to the live translation worker)"
1038	    );
1039	    assert!(
1040	        sessions_answered,
1041	        "the controller/session must stay SERVICEABLE through+after the injection \
1042	         (KIND_SESSIONS answers) — inject coexists with a live controller via the floor"
1043	    );
1044	    assert!(
1045	        fresh_attach_served,
1046	        "a fresh attach must still be served after the injection (receives PTY output, \
1047	         drives input) — proves the session is fully live, not merely process-alive"
1048	    );
1049
1050	    // BYTE RECEIPT of the binary-injected `XLATE_OK` — PLATFORM-DIVERGENT, treated with
1051	    // the SAME banked stance the W1 park-(b) / W1b gates above use for ConPTY-vs-forkpty
1052	    // PTY-echo divergence (capture on the absorbing platform, hard-assert on the other):
1053	    //  - Unix forkpty cooked-mode reliably echoes the injected line, so the payload's
1054	    //    arrival over the real broker ring is a HARD assertion there (the real-receipt
1055	    //    proof W1's gate lacked).
1056	    //  - Windows ConPTY does NOT surface the cooked echo of a PROGRAMMATICALLY-injected
1057	    //    line the way it echoes interactively-typed input (an operator keystroke echoes
1058	    //    — see g3 `secret_on_pty` — but the inject-worker's `write_input` of the same
1059	    //    bytes does not re-emit through `findstr`'s echo here), and a custom PTY child
1060	    //    reading io::stdin() never receives ConPTY input to record. So on Windows we
1061	    //    CAPTURE the observation (never a false-red) and lean on the other three hard
1062	    //    asserts; the gravity-linux CI run carries the byte-receipt assertion. This
1063	    //    matches the file's existing platform-divergence discipline exactly.
1064	    #[cfg(unix)]
1065	    assert!(
1066	        payload_reached,
1067	        "the choreography's `{{text:XLATE_OK}}` must actually REACH the PTY (real byte \
1068	         receipt via the translation binary, echoed back over the broker ring — the \
1069	         assertion W1's gate lacked), not merely liveness"
1070	    );
1071	    #[cfg(windows)]
1072	    eprintln!(
1073	        "=== W2 G1 (Windows ConPTY observation, not asserted): payload_reached={payload_reached} \
1074	         — ConPTY does not surface the injected line's cooked echo; byte-receipt is the \
1075	         hard assertion on gravity-linux (forkpty). The three asserts above hold here. ==="
1076	    );
1077	    let _ = payload_reached;
1078	}
1079
1080	#[test]
1081	fn g2_no_commit_deadline_faults_binary_and_does_not_wedge_controller_input() {
1082	    init_wedge_home();
1083	    let dir = tempfile::tempdir().expect("tempdir");
1084	    // The binary emits the payload + a key but NEVER `{commit}` → the broker's
1085	    // commit deadline must fire. Shrink the deadline so the structural outcome
1086	    // (floor releases → buffered input flushes → binary faults) is observed fast.
1087	    std::env::set_var("XLATE_FIXTURE_MODE", "nocommit");
1088	    std::env::set_var("SPT_INJECT_COMMIT_DEADLINE_MS", "400");
1089	    std::env::remove_var("XLATE_FIXTURE_STDIN_LOG");
1090
1091	    let name = unique_name();
1092	    let endpoint = "xlate-g2-ep";
1093	    let (broker, sid, mut controller) =
1094	        spawn_xlate_session(&name, &dir.path().join("g2"), endpoint);
1095	    // Bind the controller brain to the session so its keystrokes have a target.
1096	    controller.attach(sid, 0).expect("controller attach");
1097
1098	    // Deliver an event whose binary never commits → the floor OPENS, buffers
1099	    // operator input, and the worker hits the 400ms deadline.
1100	    let envelope = br#"<EVENT type="message" from="peer">no-commit event</EVENT>"#;
1101	    let delivered = deliver_endpoint_event(&name, endpoint, envelope, Duration::from_secs(5));
1102
1103	    // While the floor is (briefly) held, the operator types — Enter-terminated so the
1104	    // echo child flushes the line. After the 400ms deadline the floor must RELEASE and
1105	    // the buffered keystrokes flush to the PTY (then echo back over the ring). Send a
1106	    // few times (some before, some after the deadline) so the flush is exercised; then
1107	    // observe the marker echo — proof the controller input did NOT wedge.
1108	    for _ in 0..4 {
1109	        let _ = controller.send_input(b"OPERATOR_KEYS_FLUSHED\r");
1110	        let _ = controller.read_event_until(Some(Instant::now() + Duration::from_millis(150)));
1111	    }
1112	    let op_flushed =
1113	        output_contains_within(&name, sid, b"OPERATOR_KEYS_FLUSHED", Duration::from_secs(8));
1114
1115	    // The session stays serviceable after the FAULT.
1116	    let sessions_answered =
1117	        probe(&name, KIND_SESSIONS, KIND_SESSIONS_REPLY, Duration::from_secs(5));
1118
1119	    // After the binary faulted, a SUBSEQUENT inbound delivery falls back to RAW
1120	    // inject: the whole envelope bytes land on the PTY directly (the binary no longer
1121	    // drives the choreography). The raw envelope ends in `\r` so the echo child
1122	    // flushes the echoed line; assert the marker reaches the PTY via the ring.
1123	    let raw_envelope = b"<EVENT>RAW_FALLBACK_MARKER</EVENT>\r";
1124	    let delivered2 = deliver_endpoint_event(&name, endpoint, raw_envelope, Duration::from_secs(5));
1125	    let raw_fallback_reached =
1126	        output_contains_within(&name, sid, b"RAW_FALLBACK_MARKER", Duration::from_secs(8));
1127
1128	    if let Some(pid) = broker.session_pid(sid) {
1129	        kill_pid(pid);
1130	    }
1131
1132	    eprintln!(
1133	        "=== W2 G2 NO-COMMIT FAULT GATE: delivered={delivered} op_flushed={op_flushed} \
1134	         sessions_answered={sessions_answered} delivered2={delivered2} \
1135	         raw_fallback_reached={raw_fallback_reached} \
1136	         (op_flushed=true → controller input never wedged; raw_fallback → binary faulted) ==="
1137	    );
1138
1139	    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
1140	    assert!(delivered, "the no-commit event must still be accepted by the broker");
1141	    assert!(
1142	        op_flushed,
1143	        "after the commit deadline the floor must RELEASE and buffered operator \
1144	         keystrokes must flush to the PTY — the controller's input must NOT wedge \
1145	         (the mandatory bounded-buffer guard; doyle non-negotiable = never park forever)"
1146	    );
1147	    assert!(
1148	        sessions_answered,
1149	        "the session must stay serviceable after the binary faults"
1150	    );
1151	    assert!(
1152	        raw_fallback_reached,
1153	        "after the FAULT a subsequent inbound delivery must fall back to RAW inject — \
1154	         the raw `<EVENT>` envelope must land on the PTY directly (the faulted binary \
1155	         no longer drives the choreography)"
1156	    );
1157	}
1158
1159	#[test]
1160	fn g3_content_free_ping_never_duplicates_operator_keystrokes_into_binary() {
1161	    init_wedge_home();
1162	    let dir = tempfile::tempdir().expect("tempdir");
1163	    let bin_stdin_log = dir.path().join("xlate_stdin.log");
1164	    // The translation binary records EVERY stdin line it receives here.
1165	    std::env::set_var("XLATE_FIXTURE_STDIN_LOG", &bin_stdin_log);
1166	    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");
1167	    std::env::remove_var("SPT_INJECT_COMMIT_DEADLINE_MS");
1168
1169	    let name = unique_name();
1170	    let endpoint = "xlate-g3-ep";
1171	    let (broker, sid, mut controller) =
1172	        spawn_xlate_session(&name, &dir.path().join("g3"), endpoint);
1173	    controller.attach(sid, 0).expect("controller attach");
1174
1175	    // The operator types a recognizable secret payload as keystrokes (Enter-terminated
1176	    // so the echo child flushes the line). dispatch_input fires a CONTENT-FREE
1177	    // `{type:input}` ping to the binary — NEVER the bytes. The floor is FREE (no inject
1178	    // in flight), so the keystrokes pass through to the PTY and echo back.
1179	    let secret = b"SECRET_OPERATOR_KEYSTROKES_1234";
1180	    for _ in 0..6 {
1181	        let _ = controller.send_input(b"SECRET_OPERATOR_KEYSTROKES_1234\r");
1182	        let _ =
1183	            controller.read_event_until(Some(Instant::now() + Duration::from_millis(40)));
1184	    }

fn g1_choreography_happy_path_payload_reaches_pty_and_controller_keeps_control() {
    init_wedge_home();
    let dir = tempfile::tempdir().expect("tempdir");
    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");
    std::env::remove_var("XLATE_FIXTURE_STDIN_LOG");
    std::env::remove_var("SPT_INJECT_COMMIT_DEADLINE_MS");

    let name = unique_name();
    let endpoint = "xlate-g1-ep";
    // The PTY child is the proven cross-OS ECHO child: the injected payload echoes
    // back over the REAL broker output ring (a custom child reading io::stdin() does
    // NOT receive ConPTY input writes — only a console-native app like findstr/cat
    // does, which is why byte-receipt is observed through the echo, not a side file).
    let (broker, sid, mut controller) =
        spawn_xlate_session(&name, &dir.path().join("g1"), endpoint);

    // Keep the spawning controller brain DRAINED on a background thread so it stays
    // the live, serviceable operator (the W1 coexistence partner) while the injection
    // runs. Pump mode → the read deadline is honored, so the stop flag is observed.
    let stop = Arc::new(AtomicBool::new(false));
    let drain_stop = Arc::clone(&stop);
    let drainer = thread::spawn(move || {
        while !drain_stop.load(Ordering::Relaxed) {
            let _ =
                controller.read_event_until(Some(Instant::now() + Duration::from_millis(100)));
        }
        controller // hand it back so it is dropped only after teardown
    });

    // ── Deliver an inbound message as a real `<EVENT…>` envelope via KIND_ENDPOINT_INPUT.
    //    A live (non-faulted) translation binary OWNS the choreography → the broker
    //    queues the whole envelope to the inject worker, which drives it through the
    //    binary and applies the resulting keystrokes to the PTY atomically. ──
    let envelope = br#"<EVENT type="message" from="peer">hello translation</EVENT>"#;
    let delivered = deliver_endpoint_event(&name, endpoint, envelope, Duration::from_secs(8));

    // (b) BYTE RECEIPT: the choreography's `{text:"XLATE_OK"}` actually reached the
    // PTY — observed via the echo child's output over the REAL broker ring (the
    // real-receipt assertion W1's gate lacked, not merely liveness). The choreography's
    // `ctrl+s` (0x13 = XOFF) pauses this ConPTY's OUTPUT flow, stranding the echoed
    // payload; so we interleave OPERATOR XON keystrokes (`ctrl+q` = 0x11 — exactly
    // what a real operator does to un-stick a frozen terminal, and proof injection
    // coexists with live operator input) WHILE polling the ring until the payload
    // echo flushes. The payload byte already landed on the PTY (XOFF gates output,
    // not the input write); XON releases its buffered echo deterministically.
    let payload_reached = observe_with_xon(&name, sid, b"XLATE_OK", false, Duration::from_secs(12));

    // (a) The controller/operator STAYS SERVICEABLE through + after the injection
    // (the W1 non-wedge bar): KIND_SESSIONS still answers, and a FRESH attach drives
    // input and sees it echo back (XON-resumed). Injection coexisted with the live
    // controller via the floor.
    let sessions_answered =
        probe(&name, KIND_SESSIONS, KIND_SESSIONS_REPLY, Duration::from_secs(5));
    let fresh_attach_served =
        observe_with_xon(&name, sid, b"G1_FRESH_MARKER", true, Duration::from_secs(8));

    // Teardown: reap the PTY child + the controller drainer.
    if let Some(pid) = broker.session_pid(sid) {
        kill_pid(pid);
    }
    stop.store(true, Ordering::Relaxed);
    let _ = drainer.join();

    eprintln!(
        "=== W2 G1 CHOREO GATE: delivered={delivered} payload_reached_pty={payload_reached} \
         sessions_answered={sessions_answered} fresh_attach_served={fresh_attach_served} \
         (all true = inject coexists with a live controller; payload landed via the binary) ==="
    );

    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
    assert!(
        delivered,
        "the broker must accept the endpoint event (queued to the live translation worker)"
    );
    assert!(
        sessions_answered,
        "the controller/session must stay SERVICEABLE through+after the injection \
         (KIND_SESSIONS answers) — inject coexists with a live controller via the floor"
    );
    assert!(
        fresh_attach_served,
        "a fresh attach must still be served after the injection (receives PTY output, \
         drives input) — proves the session is fully live, not merely process-alive"
    );

    // BYTE RECEIPT of the binary-injected `XLATE_OK` — PLATFORM-DIVERGENT, treated with
    // the SAME banked stance the W1 park-(b) / W1b gates above use for ConPTY-vs-forkpty
    // PTY-echo divergence (capture on the absorbing platform, hard-assert on the other):
    //  - Unix forkpty cooked-mode reliably echoes the injected line, so the payload's
    //    arrival over the real broker ring is a HARD assertion there (the real-receipt
    //    proof W1's gate lacked).
    //  - Windows ConPTY does NOT surface the cooked echo of a PROGRAMMATICALLY-injected
    //    line the way it echoes interactively-typed input (an operator keystroke echoes
    //    — see g3 `secret_on_pty` — but the inject-worker's `write_input` of the same
    //    bytes does not re-emit through `findstr`'s echo here), and a custom PTY child
    //    reading io::stdin() never receives ConPTY input to record. So on Windows we
    //    CAPTURE the observation (never a false-red) and lean on the other three hard
    //    asserts; the gravity-linux CI run carries the byte-receipt assertion. This
    //    matches the file's existing platform-divergence discipline exactly.
    #[cfg(unix)]
    assert!(
        payload_reached,
        "the choreography's `{{text:XLATE_OK}}` must actually REACH the PTY (real byte \
         receipt via the translation binary, echoed back over the broker ring — the \
         assertion W1's gate lacked), not merely liveness"
    );
    #[cfg(windows)]
    eprintln!(
        "=== W2 G1 (Windows ConPTY observation, not asserted): payload_reached={payload_reached} \
         — ConPTY does not surface the injected line's cooked echo; byte-receipt is the \
         hard assertion on gravity-linux (forkpty). The three asserts above hold here. ==="
    );
    let _ = payload_reached;
}

#[test]
fn g2_no_commit_deadline_faults_binary_and_does_not_wedge_controller_input() {
    init_wedge_home();
    let dir = tempfile::tempdir().expect("tempdir");
    // The binary emits the payload + a key but NEVER `{commit}` → the broker's
    // commit deadline must fire. Shrink the deadline so the structural outcome
    // (floor releases → buffered input flushes → binary faults) is observed fast.
    std::env::set_var("XLATE_FIXTURE_MODE", "nocommit");
    std::env::set_var("SPT_INJECT_COMMIT_DEADLINE_MS", "400");
    std::env::remove_var("XLATE_FIXTURE_STDIN_LOG");

    let name = unique_name();
    let endpoint = "xlate-g2-ep";
    let (broker, sid, mut controller) =
        spawn_xlate_session(&name, &dir.path().join("g2"), endpoint);
    // Bind the controller brain to the session so its keystrokes have a target.
    controller.attach(sid, 0).expect("controller attach");

    // Deliver an event whose binary never commits → the floor OPENS, buffers
    // operator input, and the worker hits the 400ms deadline.
    let envelope = br#"<EVENT type="message" from="peer">no-commit event</EVENT>"#;
    let delivered = deliver_endpoint_event(&name, endpoint, envelope, Duration::from_secs(5));

    // While the floor is (briefly) held, the operator types — Enter-terminated so the
    // echo child flushes the line. After the 400ms deadline the floor must RELEASE and
    // the buffered keystrokes flush to the PTY (then echo back over the ring). Send a
    // few times (some before, some after the deadline) so the flush is exercised; then
    // observe the marker echo — proof the controller input did NOT wedge.
    for _ in 0..4 {
        let _ = controller.send_input(b"OPERATOR_KEYS_FLUSHED\r");
        let _ = controller.read_event_until(Some(Instant::now() + Duration::from_millis(150)));
    }
    let op_flushed =
        output_contains_within(&name, sid, b"OPERATOR_KEYS_FLUSHED", Duration::from_secs(8));

    // The session stays serviceable after the FAULT.
    let sessions_answered =
        probe(&name, KIND_SESSIONS, KIND_SESSIONS_REPLY, Duration::from_secs(5));

    // After the binary faulted, a SUBSEQUENT inbound delivery falls back to RAW
    // inject: the whole envelope bytes land on the PTY directly (the binary no longer
    // drives the choreography). The raw envelope ends in `\r` so the echo child
    // flushes the echoed line; assert the marker reaches the PTY via the ring.
    let raw_envelope = b"<EVENT>RAW_FALLBACK_MARKER</EVENT>\r";
    let delivered2 = deliver_endpoint_event(&name, endpoint, raw_envelope, Duration::from_secs(5));
    let raw_fallback_reached =
        output_contains_within(&name, sid, b"RAW_FALLBACK_MARKER", Duration::from_secs(8));

    if let Some(pid) = broker.session_pid(sid) {
        kill_pid(pid);
    }

    eprintln!(
        "=== W2 G2 NO-COMMIT FAULT GATE: delivered={delivered} op_flushed={op_flushed} \
         sessions_answered={sessions_answered} delivered2={delivered2} \
         raw_fallback_reached={raw_fallback_reached} \
         (op_flushed=true → controller input never wedged; raw_fallback → binary faulted) ==="
    );

    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
    assert!(delivered, "the no-commit event must still be accepted by the broker");
    assert!(
        op_flushed,
        "after the commit deadline the floor must RELEASE and buffered operator \
         keystrokes must flush to the PTY — the controller's input must NOT wedge \
         (the mandatory bounded-buffer guard; doyle non-negotiable = never park forever)"
    );
    assert!(
        sessions_answered,
        "the session must stay serviceable after the binary faults"
    );
    assert!(
        raw_fallback_reached,
        "after the FAULT a subsequent inbound delivery must fall back to RAW inject — \
         the raw `<EVENT>` envelope must land on the PTY directly (the faulted binary \
         no longer drives the choreography)"
    );
}

#[test]
fn g3_content_free_ping_never_duplicates_operator_keystrokes_into_binary() {
    init_wedge_home();
    let dir = tempfile::tempdir().expect("tempdir");
    let bin_stdin_log = dir.path().join("xlate_stdin.log");
    // The translation binary records EVERY stdin line it receives here.
    std::env::set_var("XLATE_FIXTURE_STDIN_LOG", &bin_stdin_log);
    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");
    std::env::remove_var("SPT_INJECT_COMMIT_DEADLINE_MS");

    let name = unique_name();
    let endpoint = "xlate-g3-ep";
    let (broker, sid, mut controller) =
        spawn_xlate_session(&name, &dir.path().join("g3"), endpoint);
    controller.attach(sid, 0).expect("controller attach");

    // The operator types a recognizable secret payload as keystrokes (Enter-terminated
    // so the echo child flushes the line). dispatch_input fires a CONTENT-FREE
    // `{type:input}` ping to the binary — NEVER the bytes. The floor is FREE (no inject
    // in flight), so the keystrokes pass through to the PTY and echo back.
    let secret = b"SECRET_OPERATOR_KEYSTROKES_1234";
    for _ in 0..6 {
        let _ = controller.send_input(b"SECRET_OPERATOR_KEYSTROKES_1234\r");
        let _ =
            controller.read_event_until(Some(Instant::now() + Duration::from_millis(40)));
    }


1184	    }
1185	    // The secret must reach the PTY (it is a real operator keystroke), echoed back…
1186	    let secret_on_pty =
1187	        output_contains_within(&name, sid, secret, Duration::from_secs(8));
1188	    // …but must NEVER appear in the binary's stdin log. Give the pings time to land,
1189	    // then assert the binary's stdin contains only `init` / `input` (and any `event`)
1190	    // lines — no operator payload.
1191	    thread::sleep(Duration::from_millis(500));
1192	    let bin_stdin = std::fs::read(&bin_stdin_log).unwrap_or_default();
1193	    let secret_leaked = count(&bin_stdin, secret) >= 1;
1194	    // Structurally confirm content-free pings DID flow (the binary saw `{type:input}`).
1195	    let saw_input_ping = count(&bin_stdin, br#"{"type":"input"}"#) >= 1;
1196
1197	    if let Some(pid) = broker.session_pid(sid) {
1198	        kill_pid(pid);
1199	    }
1200
1201	    eprintln!(
1202	        "=== W2 G3 CONTENT-FREE PING GATE: secret_on_pty={secret_on_pty} \
1203	         secret_leaked_into_binary={secret_leaked} saw_input_ping={saw_input_ping} \
1204	         (privacy = secret_leaked false; the binary sees only content-free pings) ==="
1205	    );
1206
1207	    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
1208	    assert!(
1209	        secret_on_pty,
1210	        "the operator's keystrokes must reach the PTY (the floor is free — no inject)"
1211	    );
1212	    assert!(
1213	        !secret_leaked,
1214	        "doyle gate #1 (privacy): the operator's PTY keystrokes must NEVER be \
1215	         duplicated into the translation binary's stdin — only init / event / \
1216	         content-free input lines may reach it. The secret payload leaked into the \
1217	         binary's stdin."
1218	    );
1219	    assert!(
1220	        saw_input_ping,
1221	        "the binary must have received at least one CONTENT-FREE `{{type:input}}` ping \
1222	         (proves the ping fires — and the privacy assertion above is meaningful, not \
1223	         vacuous because no ping flowed)"
1224	    );
1225	}
1226
1227	#[test]
1228	fn g4_translation_child_is_reaped_no_zombie_after_session_down() {
1229	    init_wedge_home();
1230	    let dir = tempfile::tempdir().expect("tempdir");
1231	    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");
1232	    std::env::remove_var("XLATE_FIXTURE_STDIN_LOG");
1233	    std::env::remove_var("SPT_INJECT_COMMIT_DEADLINE_MS");
1234
1235	    let name = unique_name();
1236	    let endpoint = "xlate-g4-ep";
1237	    let (broker, sid, _controller) =
1238	        spawn_xlate_session(&name, &dir.path().join("g4"), endpoint);
1239
1240	    // Capture the translation child's pid via its OS process table presence. The
1241	    // broker does not surface the translation child's pid directly, so we discover
1242	    // it: the `xlate_choreo_fixture` process is a child of THIS test process. We
1243	    // confirm it is live before teardown, then assert it is gone after.
1244	    let xlate_pid = find_xlate_child_pid().expect("translation child should be running");
1245	    assert!(
1246	        pid_alive(xlate_pid),
1247	        "the translation child must be live before teardown (sanity)"
1248	    );
1249
1250	    // Tear the session down: kill the PTY child → the exit waiter reaps the session
1251	    // → the HostedSession (and its Translation) drops → the inject worker's event_tx
1252	    // drops → run_inject_worker exits its loop → child.terminate() (bounded reap).
1253	    if let Some(pid) = broker.session_pid(sid) {
1254	        kill_pid(pid);
1255	    }
1256
1257	    // First, the session must leave the broker table (proves the HostedSession +
1258	    // its Translation dropped → the inject worker's event_tx dropped → the worker
1259	    // reaps the child). This is the structural precondition for the reap.
1260	    let session_gone = {
1261	        let deadline = Instant::now() + Duration::from_secs(6);
1262	        let mut gone = false;
1263	        while Instant::now() < deadline {
1264	            if broker.session_count() == 0 {
1265	                gone = true;
1266	                break;
1267	            }
1268	            thread::sleep(Duration::from_millis(50));
1269	        }
1270	        gone
1271	    };
1272
1273	    // Then poll for the translation child to disappear within the bounded reap
1274	    // window. REAP_GRACE is 500ms; the worker also observes the channel close, so we
1275	    // allow a generous structural deadline (still bounded — never forever).
1276	    let reaped = {
1277	        let deadline = Instant::now() + Duration::from_secs(8);
1278	        let mut gone = false;
1279	        while Instant::now() < deadline {
1280	            if !pid_alive(xlate_pid) {
1281	                gone = true;
1282	                break;
1283	            }
1284	            thread::sleep(Duration::from_millis(50));
1285	        }
1286	        gone
1287	    };
1288	    eprintln!("=== W2 G4 DIAG: session_gone={session_gone} ===");
1289
1290	    // Belt-and-braces: if it somehow survived, don't leak it past the test.
1291	    if !reaped {
1292	        kill_pid(xlate_pid);
1293	    }
1294
1295	    eprintln!(
1296	        "=== W2 G4 NO-ZOMBIE GATE: xlate_pid={xlate_pid} reaped_within_bound={reaped} \
1297	         (true = the translation child is terminated+reaped on session-down — doyle gate #2) ==="
1298	    );
1299
1300	    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
1301	    assert!(
1302	        reaped,
1303	        "doyle gate #2 (no-zombie): the translation child must be terminated + reaped \
1304	         within the bounded reap window after session-down / broker teardown — a \
1305	         session-down must never leak a translation child"
1306	    );
1307	}
1308
1309	/// Find the OS pid of the spawned `xlate_choreo_fixture` translation child. The
1310	/// broker does not surface it, so we locate it by image name among THIS process's
1311	/// descendants. Cross-OS, best-effort (the no-zombie test only needs *a* live
1312	/// translation-child pid to then watch disappear).
1313	#[cfg(windows)]

    }
    // The secret must reach the PTY (it is a real operator keystroke), echoed back…
    let secret_on_pty =
        output_contains_within(&name, sid, secret, Duration::from_secs(8));
    // …but must NEVER appear in the binary's stdin log. Give the pings time to land,
    // then assert the binary's stdin contains only `init` / `input` (and any `event`)
    // lines — no operator payload.
    thread::sleep(Duration::from_millis(500));
    let bin_stdin = std::fs::read(&bin_stdin_log).unwrap_or_default();
    let secret_leaked = count(&bin_stdin, secret) >= 1;
    // Structurally confirm content-free pings DID flow (the binary saw `{type:input}`).
    let saw_input_ping = count(&bin_stdin, br#"{"type":"input"}"#) >= 1;

    if let Some(pid) = broker.session_pid(sid) {
        kill_pid(pid);
    }

    eprintln!(
        "=== W2 G3 CONTENT-FREE PING GATE: secret_on_pty={secret_on_pty} \
         secret_leaked_into_binary={secret_leaked} saw_input_ping={saw_input_ping} \
         (privacy = secret_leaked false; the binary sees only content-free pings) ==="
    );

    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
    assert!(
        secret_on_pty,
        "the operator's keystrokes must reach the PTY (the floor is free — no inject)"
    );
    assert!(
        !secret_leaked,
        "doyle gate #1 (privacy): the operator's PTY keystrokes must NEVER be \
         duplicated into the translation binary's stdin — only init / event / \
         content-free input lines may reach it. The secret payload leaked into the \
         binary's stdin."
    );
    assert!(
        saw_input_ping,
        "the binary must have received at least one CONTENT-FREE `{{type:input}}` ping \
         (proves the ping fires — and the privacy assertion above is meaningful, not \
         vacuous because no ping flowed)"
    );
}

#[test]
fn g4_translation_child_is_reaped_no_zombie_after_session_down() {
    init_wedge_home();
    let dir = tempfile::tempdir().expect("tempdir");
    std::env::set_var("XLATE_FIXTURE_MODE", "choreo");
    std::env::remove_var("XLATE_FIXTURE_STDIN_LOG");
    std::env::remove_var("SPT_INJECT_COMMIT_DEADLINE_MS");

    let name = unique_name();
    let endpoint = "xlate-g4-ep";
    let (broker, sid, _controller) =
        spawn_xlate_session(&name, &dir.path().join("g4"), endpoint);

    // Capture the translation child's pid via its OS process table presence. The
    // broker does not surface the translation child's pid directly, so we discover
    // it: the `xlate_choreo_fixture` process is a child of THIS test process. We
    // confirm it is live before teardown, then assert it is gone after.
    let xlate_pid = find_xlate_child_pid().expect("translation child should be running");
    assert!(
        pid_alive(xlate_pid),
        "the translation child must be live before teardown (sanity)"
    );

    // Tear the session down: kill the PTY child → the exit waiter reaps the session
    // → the HostedSession (and its Translation) drops → the inject worker's event_tx
    // drops → run_inject_worker exits its loop → child.terminate() (bounded reap).
    if let Some(pid) = broker.session_pid(sid) {
        kill_pid(pid);
    }

    // First, the session must leave the broker table (proves the HostedSession +
    // its Translation dropped → the inject worker's event_tx dropped → the worker
    // reaps the child). This is the structural precondition for the reap.
    let session_gone = {
        let deadline = Instant::now() + Duration::from_secs(6);
        let mut gone = false;
        while Instant::now() < deadline {
            if broker.session_count() == 0 {
                gone = true;
                break;
            }
            thread::sleep(Duration::from_millis(50));
        }
        gone
    };

    // Then poll for the translation child to disappear within the bounded reap
    // window. REAP_GRACE is 500ms; the worker also observes the channel close, so we
    // allow a generous structural deadline (still bounded — never forever).
    let reaped = {
        let deadline = Instant::now() + Duration::from_secs(8);
        let mut gone = false;
        while Instant::now() < deadline {
            if !pid_alive(xlate_pid) {
                gone = true;
                break;
            }
            thread::sleep(Duration::from_millis(50));
        }
        gone
    };
    eprintln!("=== W2 G4 DIAG: session_gone={session_gone} ===");

    // Belt-and-braces: if it somehow survived, don't leak it past the test.
    if !reaped {
        kill_pid(xlate_pid);
    }

    eprintln!(
        "=== W2 G4 NO-ZOMBIE GATE: xlate_pid={xlate_pid} reaped_within_bound={reaped} \
         (true = the translation child is terminated+reaped on session-down — doyle gate #2) ==="
    );

    // [int->REQ-MSG-IDLE-TRANSLATION-BINARY]
    assert!(
        reaped,
        "doyle gate #2 (no-zombie): the translation child must be terminated + reaped \
         within the bounded reap window after session-down / broker teardown — a \
         session-down must never leak a translation child"
    );
}

/// Find the OS pid of the spawned `xlate_choreo_fixture` translation child. The
/// broker does not surface it, so we locate it by image name among THIS process's
/// descendants. Cross-OS, best-effort (the no-zombie test only needs *a* live
/// translation-child pid to then watch disappear).
#[cfg(windows)]


All 4 tests substantial + honest: g2/g3/g4 fully hard-assert on BOTH platforms; only g1's byte-receipt is cfg(unix)-hard / cfg(windows)-captured — matching the file's banked ConPTY-vs-forkpty stance, and the W1b-grade receipt assertion lands on gravity-linux CI. Non-vacuous on Windows (g1 keeps 3 hard asserts).

Independently verify from the quiesced tree (not trust-the-green). Run nextest + clippy myself:


Bash

cargo nextest run -p spt-daemon --test inject_control_wedge 2>&1 | tail -16

Independently run the int suite via nextest


    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.44s
────────────
 Nextest run ID 4405b5cd-c0e4-4a8d-b880-692cdd448a74 with nextest profile: default
    Starting 7 tests across 1 binary
        PASS [   0.647s] (1/7) spt-daemon::inject_control_wedge g4_translation_child_is_reaped_no_zombie_after_session_down
        PASS [   0.660s] (2/7) spt-daemon::inject_control_wedge g2_no_commit_deadline_faults_binary_and_does_not_wedge_controller_input
        PASS [   0.868s] (3/7) spt-daemon::inject_control_wedge g3_content_free_ping_never_duplicates_operator_keystrokes_into_binary
        PASS [   3.016s] (4/7) spt-daemon::inject_control_wedge a_journaled_input_wedge_does_not_starve_a_concurrent_rc_attach
        PASS [   3.201s] (5/7) spt-daemon::inject_control_wedge a_backed_up_controller_does_not_wedge_the_session
        PASS [   5.612s] (6/7) spt-daemon::inject_control_wedge injecting_a_large_payload_into_a_stdin_ignoring_child
        PASS [  12.460s] (7/7) spt-daemon::inject_control_wedge g1_choreography_happy_path_payload_reaches_pty_and_controller_keeps_control
────────────
     Summary [  12.461s] 7 tests run: 7 passed, 0 skipped


7/7 green independently. Now clippy (CI form) + bump REQ int stage. Run clippy:


cargo clippy --workspace --all-targets -- -D warnings 2>&1 | grep -E "error|warning:" | head -20; echo "=== clippy tail ==="; cargo clippy --workspace --all-targets -- -D warnings 2>&1 | tail -2

Workspace clippy CI form


=== clippy tail ===
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.49s


Clippy clean. Bump REQ to add `int` (evidence now in place):


1197	required_stages = ["doc", "impl", "unit"]  # ACTIVATING v0.13.0 W2 (todlando) — int rides Layer G. Layers A(@c73eb6a)+B(@611205c)+D(@7166f52)+C-kernel(@79f5a40)+C-proper/E landed: impl = translation.rs (ToBinary/KeyCmd/key_to_bytes/TranslationChild/InjectFloor) + broker.rs (Translation/run_inject_worker/flush_inject_floor/fault_translation + dispatch_spawn bring-up + dispatch_input floor-buffer&ping + dispatch_endpoint_input event routing); unit = translation.rs (wire round-trips, content-free ping, KeyCmd shapes, InjectFloor buffer/drain, send-keys map). int (Layer G, NEXT via spt-test-engineer) = real dummy translation-binary choreography into an rc-attached session w/o breaking control + no-commit-deadline FAULT + content-free + no-zombie. — staged: doc DONE (manifest section row in MANIFEST.md inject-seam family + CONTEXT.md:39 delivery section reworded W0 + ADR-0022 wording table-not-scalar + manifest.schema.json regen); impl/unit/int bump in as each layer lands (Layer A manifest section + validate + schema = impl/unit foundation; B translation.rs protocol+driver; C atomic PTY apply w/ controller buffering; D lifecycle via SpawnReq.translation_binary; E routing; F Unix park (b)/(c) bound; G int gate). int gate: a real dummy translation-binary delivers an inbound message into an rc-attached spt-hosted session via the choreography WITHOUT breaking control (composes with W1's invariant). ALSO OWNS the Unix-only park (b)/(c) PTY-write bound deferred from W1 (doyle ruling 2026-06-19): the 'spt-core owns every PTY write, applied atomically' substrate is where the forkpty input-queue park gets bounded — bounded/fail-fast write_input + DSR-answer must not hold the writer mutex across a blocking write; gate on gravity-linux (the cfg(unix) park-(b) assert in inject_control_wedge.rs proves the park is real + keeps it tracked).
1198


Edit

required_stages = ["doc", "impl", "unit"]  # ACTIVATING v0.13.0 W2 (todlando) — int rides Layer G. Layers A(@c73eb6a)+B(@611205c)+D(@7166f52)+C-kernel(@79f5a40)+C-proper/E landed: impl = translation.rs (ToBinary/KeyCmd/key_to_bytes/TranslationChild/InjectFloor) + broker.rs (Translation/run_inject_worker/flush_inject_floor/fault_translation + dispatch_spawn bring-up + dispatch_input floor-buffer&ping + dispatch_endpoint_input event routing); unit = translation.rs (wire round-trips, content-free ping, KeyCmd shapes, InjectFloor buffer/drain, send-keys map). int (Layer G, NEXT via spt-test-engineer) = real dummy translation-binary choreography into an rc-attached session w/o breaking control + no-commit-deadline FAULT + content-free + no-zombie.

required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 W2 (todlando) — all layers landed. Layers A(@c73eb6a)+B(@611205c)+D(@7166f52)+C-kernel(@79f5a40)+C-proper/E(@f9fe5bb)+G(int). impl = translation.rs (ToBinary/KeyCmd/key_to_bytes/TranslationChild/InjectFloor) + broker.rs (Translation/run_inject_worker/flush_inject_floor/fault_translation + dispatch_spawn bring-up + dispatch_input floor-buffer&ping + dispatch_endpoint_input event routing); unit = translation.rs (wire round-trips, content-free ping, KeyCmd shapes, InjectFloor buffer/drain, send-keys map). int = inject_control_wedge.rs g1-g4 via the REAL src/bin/xlate_choreo_fixture.rs translation binary: g1 choreography happy-path (delivered + session serviceable + fresh attach served, all platforms; byte-receipt of XLATE_OK hard on cfg(unix)/gravity-linux, captured on cfg(windows) ConPTY per the file's banked park-(b) divergence stance) · g2 no-commit FAULT (SPT_INJECT_COMMIT_DEADLINE_MS=400: buffered operator keys flush after deadline = no wedge + raw-inject fallback, hard both platforms) · g3 content-free ping (secret reaches PTY but NEVER the binary stdin-log + saw_input_ping non-vacuous, hard both) · g4 no-zombie reap on session-down (hard both). Layer F (Unix park b/c bound) = gravity-linux follow-up, shared w/ W1b F3, tracked by the cfg(unix) park-(b) assert.


The file C:\Users\decid\Documents\projects\spt-core\traceable-reqs.toml has been updated successfully. (file state is current in your context — no need to Read it back)

title = "spt-hosted idle message delivery via an adapter TRANSLATION BINARY (ADR-0022). New opt-in manifest section `[message-idle-translation-binary]` = a TABLE carrying a `path` scalar (doyle OPT-B ruling: modeled as a table, not a bare top-level scalar, so a preceding section cannot silently absorb it + N+1 extensible; spt-core does NOT deny_unknown_fields, so a future key degrades gracefully); spt-core LIFECYCLE-manages it (spawn when the endpoint comes up, terminate when it goes down). The binary is a PURE stdin→stdout filter; spt-core owns EVERY PTY write. stdin (JSON-lines): `{type:\"init\",endpoint_id,node}` first · `{type:\"event\",envelope:\"<EVENT…>\"}` per inbound message (ADR-0020 envelope) · `{type:\"input\"}` content-free ping on each operator keystroke (binary tracks user-idle for its own idle-gated buffering; PTY input content NOT duplicated). stdout (JSON-lines): keystroke-commands `{key:…}`/`{delay_ms:…}`/`{text:…}` (extensible). spt-core applies the emitted sequence to the broker PTY ATOMICALLY (the W1 coordination — REQ-HAZARD-INJECT-CONTROL-COEXIST). The daemon poll feed is the ONE idle substrate for both topologies (Q1=A): harness-hosted consumer = the Monitor child, spt-hosted consumer = this binary; spt-core PREFERS a perch's poll listener if one exists (so spt-hosted can run a listener AND keep `spt rc`). Idle-only; busy/mid-turn = adapter hook-injection. Closes the current grounding gap: `api bind` registers no listener port → a listener-less spt-hosted perch SPOOLS inbound (only spooling+adapter-poll works today) → this delivers real inbound into the PTY. The v0.11.0 raw inject is the degenerate `{text:payload}{key:enter}` case. (v0.13.0)"

-required_stages = ["doc", "impl", "unit"]  # ACTIVATING v0.13.0 W2 (todlando) — int rides Layer G. Layers A(@c73eb6a)+B(@611205c)+D(@7166f52)+C-kernel(@79f5a40)+C-proper/E landed: impl = translation.rs (ToBinary/KeyCmd/key_to_bytes/TranslationChild/InjectFloor) + broker.rs (Translation/run_inject_worker/flush_inject_floor/fault_translation + dispatch_spawn bring-up + dispatch_input floor-buffer&ping + dispatch_endpoint_input event routing); unit = translation.rs (wire round-trips, content-free ping, KeyCmd shapes, InjectFloor buffer/drain, send-keys map). int (Layer G, NEXT via spt-test-engineer) = real dummy translation-binary choreography into an rc-attached session w/o breaking control + no-commit-deadline FAULT + content-free + no-zombie. — staged: doc DONE (manifest section row in MANIFEST.md inject-seam family + CONTEXT.md:39 delivery section reworded W0 + ADR-0022 wording table-not-scalar + manifest.schema.json regen); impl/unit/int bump in as each layer lands (Layer A manifest section + validate + schema = impl/unit foundation; B translation.rs protocol+driver; C atomic PTY apply w/ controller buffering; D lifecycle via SpawnReq.translation_binary; E routing; F Unix park (b)/(c) bound; G int gate). int gate: a real dummy translation-binary delivers an inbound message into an rc-attached spt-hosted session via the choreography WITHOUT breaking control (composes with W1's invariant). ALSO OWNS the Unix-only park (b)/(c) PTY-write bound deferred from W1 (doyle ruling 2026-06-19): the 'spt-core owns every PTY write, applied atomically' substrate is where the forkpty input-queue park gets bounded — bounded/fail-fast write_input + DSR-answer must not hold the writer mutex across a blocking write; gate on gravity-linux (the cfg(unix) park-(b) assert in inject_control_wedge.rs proves the park is real + keeps it tracked).

+required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 W2 (todlando) — all layers landed. Layers A(@c73eb6a)+B(@611205c)+D(@7166f52)+C-kernel(@79f5a40)+C-proper/E(@f9fe5bb)+G(int). impl = translation.rs (ToBinary/KeyCmd/key_to_bytes/TranslationChild/InjectFloor) + broker.rs (Translation/run_inject_worker/flush_inject_floor/fault_translation + dispatch_spawn bring-up + dispatch_input floor-buffer&ping + dispatch_endpoint_input event routing); unit = translation.rs (wire round-trips, content-free ping, KeyCmd shapes, InjectFloor buffer/drain, send-keys map). int = inject_control_wedge.rs g1-g4 via the REAL src/bin/xlate_choreo_fixture.rs translation binary: g1 choreography happy-path (delivered + session serviceable + fresh attach served, all platforms; byte-receipt of XLATE_OK hard on cfg(unix)/gravity-linux, captured on cfg(windows) ConPTY per the file's banked park-(b) divergence stance) · g2 no-commit FAULT (SPT_INJECT_COMMIT_DEADLINE_MS=400: buffered operator keys flush after deadline = no wedge + raw-inject fallback, hard both platforms) · g3 content-free ping (secret reaches PTY but NEVER the binary stdin-log + saw_input_ping non-vacuous, hard both) · g4 no-zombie reap on session-down (hard both). Layer F (Unix park b/c bound) = gravity-linux follow-up, shared w/ W1b F3, tracked by the cfg(unix) park-(b) assert. — staged: doc DONE (manifest section row in MANIFEST.md inject-seam family + CONTEXT.md:39 delivery section reworded W0 + ADR-0022 wording table-not-scalar + manifest.schema.json regen); impl/unit/int bump in as each layer lands (Layer A manifest section + validate + schema = impl/unit foundation; B translation.rs protocol+driver; C atomic PTY apply w/ controller buffering; D lifecycle via SpawnReq.translation_binary; E routing; F Unix park (b)/(c) bound; G int gate). int gate: a real dummy translation-binary delivers an inbound message into an rc-attached spt-hosted session via the choreography WITHOUT breaking control (composes with W1's invariant). ALSO OWNS the Unix-only park (b)/(c) PTY-write bound deferred from W1 (doyle ruling 2026-06-19): the 'spt-core owns every PTY write, applied atomically' substrate is where the forkpty input-queue park gets bounded — bounded/fail-fast write_input + DSR-answer must not hold the writer mutex across a blocking write; gate on gravity-linux (the cfg(unix) park-(b) assert in inject_control_wedge.rs proves the park is real + keeps it tracked).

# ── W3: a fresh spt-hosted endpoint shows under its own project (info.cwd on bind) ──


Bash

traceable-reqs check >/tmp/tr3.txt 2>&1; echo "EXIT=$?"; grep -iE "IDLE-TRANSLATION-BINARY|INJECT-CONTROL-COEXIST" /tmp/tr3.txt; echo "=== real bin ==="; cargo build -p spt --bin spt 2>&1 | tail -2

Traceable check + real bin rebuild


EXIT=0
       The effect journal serializes EVERY PTY effect under one mutex held ACROSS two fsyncs AND the blocking PTY write — so interactive input stutters and ultimately wedges the daemon hard. ROOT (doyle /diagnose, code-grounded + MEASURED on the operator's real Windows box, 2026-06-19): EffectJournal::apply_once (effect.rs:168-188) takes `inner.lock()` and holds it across `write_line(PENDING)` → `effect()` → `write_line(DONE)`, where write_line (effect.rs:235-239) does flush()+sync_all() (a full FlushFileBuffers) — so each effect pays TWO fsyncs under a GLOBAL lock, and the closure `effect()` (the actual PTY write, broker.rs:1257 EffectKind::PtyWrite via attach.rs:197 send_effect) runs while the lock is held. Two operator-visible facets, ONE root: (A) STUTTER/LAG — every keystroke is a PtyWrite effect = 2× sync_all serialized; measured fsync on %LOCALAPPDATA%\spt-core = median 6.5ms, spikes to 198ms (C: was recently at 100%), so ~13ms+ per keystroke best case, hundreds under contention → 'many but not all keypresses take 100s of ms, choppy, worsens with volume'. (B) HARD PERMANENT WEDGE — when a PtyWrite `effect()` blocks (ConPTY input buffer full / harness not draining stdin), the journal lock is held INDEFINITELY → the single-threaded inbound-stream dispatch (dispatch.rs serve_attach, which both applies input effects AND opens attaches) can never progress → EVERY subsequent attach (`spt rc --view`/`--take`) fails with 'attach request: brain IPC read deadline elapsed' (confirmed: two retries deadline identically; broker control-plane KIND queries still answer — different thread). This REFUTES the W2-deferred ruling that park-(b)/(c) is 'Windows-benign because ConPTY absorbs 4MiB' — on the real box the input path wedges regardless. DISTINCT from W1 (REQ-HAZARD-INJECT-CONTROL-COEXIST = the OUTPUT drain, correctly fixed @8b5583e; output uses broker.rs:1106 append, NOT the fsync journal). This is the INPUT/effect-journal path W1 never touched, and it is THE wedge the operator hits with --take/--view. FIX DIRECTION (candidates, repro-first — extend inject_control_wedge.rs to a REAL backed-up-PTY-consumer + a real rc-client attach assertion, the gap W1's gate missed): (1) do NOT hold the journal lock across effect() — reserve the key + fsync PENDING under lock, RELEASE, run effect(), re-acquire to fsync DONE + mark applied (preserve crash-idempotency via the per-key reservation, not a global hold); (2) bound/fail-fast the PtyWrite itself (the W2-deferred park bound — write_input must never block indefinitely, DSR-answer must not hold the writer mutex across a blocking write); (3) drop per-keystroke fsync on the interactive path — PtyWrite effects are EPHEMERAL (a keystroke lost on a broker crash is retyped; PTY state is not reconstructed from keystroke replay), so in-memory applied-set dedup suffices (the broker survives the brain — that IS the dedup anchor), with async/batched fsync or no-fsync for EffectKind::PtyWrite while durable kinds (NetSend/NetDial/Registry/Spool) keep their fsync. Combine (1)+(3) at minimum. Add a KNOWN-HAZARDS.md entry on landing. (v0.13.0)
  [OK] REQ-HAZARD-INJECT-CONTROL-COEXIST  required: [impl, unit, int]  stages: -doc +impl +unit +int
  [OK] REQ-MSG-IDLE-TRANSLATION-BINARY  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
       spt-hosted idle message delivery via an adapter TRANSLATION BINARY (ADR-0022). New opt-in manifest section `[message-idle-translation-binary]` = a TABLE carrying a `path` scalar (doyle OPT-B ruling: modeled as a table, not a bare top-level scalar, so a preceding section cannot silently absorb it + N+1 extensible; spt-core does NOT deny_unknown_fields, so a future key degrades gracefully); spt-core LIFECYCLE-manages it (spawn when the endpoint comes up, terminate when it goes down). The binary is a PURE stdin→stdout filter; spt-core owns EVERY PTY write. stdin (JSON-lines): `{type:"init",endpoint_id,node}` first · `{type:"event",envelope:"<EVENT…>"}` per inbound message (ADR-0020 envelope) · `{type:"input"}` content-free ping on each operator keystroke (binary tracks user-idle for its own idle-gated buffering; PTY input content NOT duplicated). stdout (JSON-lines): keystroke-commands `{key:…}`/`{delay_ms:…}`/`{text:…}` (extensible). spt-core applies the emitted sequence to the broker PTY ATOMICALLY (the W1 coordination — REQ-HAZARD-INJECT-CONTROL-COEXIST). The daemon poll feed is the ONE idle substrate for both topologies (Q1=A): harness-hosted consumer = the Monitor child, spt-hosted consumer = this binary; spt-core PREFERS a perch's poll listener if one exists (so spt-hosted can run a listener AND keep `spt rc`). Idle-only; busy/mid-turn = adapter hook-injection. Closes the current grounding gap: `api bind` registers no listener port → a listener-less spt-hosted perch SPOOLS inbound (only spooling+adapter-poll works today) → this delivers real inbound into the PTY. The v0.11.0 raw inject is the degenerate `{text:payload}{key:enter}` case. (v0.13.0)
=== real bin ===
   Compiling spt v0.12.1 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 7.22s


All gates green: traceable EXIT=0, REQ-MSG-IDLE-TRANSLATION-BINARY `[doc,impl,unit,int]` satisfied, real bin rebuilt. Commit Layer G (folds env-override + fixture + tests + JIT + REQ bump):


Stage Layer G + review


warning: in the working copy of 'V0.13.0-DELIVERY-CONTROL-JIT.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt-daemon/tests/inject_control_wedge.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt-daemon/src/bin/xlate_choreo_fixture.rs', LF will be replaced by CRLF the next time Git touches it
M  V0.13.0-DELIVERY-CONTROL-JIT.md
A  crates/spt-daemon/src/bin/xlate_choreo_fixture.rs
M  crates/spt-daemon/src/broker.rs
M  crates/spt-daemon/tests/inject_control_wedge.rs
M  traceable-reqs.toml


git commit -m "$(cat <<'EOF'
test(daemon): W2 Layer G — real translation-binary int gate + commit-deadline override (ADR-0022)

The int gate proving ADR-0022 idle delivery on a REAL broker + REAL PTY + a
REAL spawned translation binary (no mocks). New fixture src/bin/xlate_choreo_-
fixture.rs = a pure stdin->stdout JSON-lines filter that, on {type:event},
emits the CC stash/restore choreography (ctrl+s -> 50ms -> text -> enter ->
50ms -> ctrl+s -> commit); mode=nocommit drops {commit} to exercise FAULT.

inject_control_wedge.rs g1-g4 (each [int->REQ-MSG-IDLE-TRANSLATION-BINARY]):
- g1 happy-path: delivered + session stays serviceable + fresh attach served
  (hard, both platforms); byte-receipt of XLATE_OK hard on cfg(unix)/gravity-
  linux, captured on cfg(windows) ConPTY (the file's banked park-(b)
  divergence stance — ConPTY does not surface an injected line's cooked echo).
- g2 no-commit FAULT (deadline shrunk via SPT_INJECT_COMMIT_DEADLINE_MS=400):
  buffered operator keys flush after the deadline = controller never wedges,
  then a subsequent delivery falls back to raw inject (binary faulted) — hard
  both platforms.
- g3 content-free ping: operator secret reaches the PTY but NEVER the binary's
  stdin log, and the binary did see {type:input} pings (non-vacuous) — privacy
  (doyle gate #1), hard both.
- g4 no-zombie: the translation child is reaped within the bounded window on
  session-down (doyle gate #2), hard both.

broker.rs: inject_commit_deadline() reads SPT_INJECT_COMMIT_DEADLINE_MS so the
FAULT outcome is asserted structurally in <1s instead of a 5s wall-clock wait.

REQ-MSG-IDLE-TRANSLATION-BINARY -> [doc,impl,unit,int] (full set). Layer F
(Unix park bound) stays a gravity-linux follow-up. Runner contract: nextest
only (never bare cargo test on this file). 7/7 green; clippy --workspace clean.

[int->REQ-MSG-IDLE-TRANSLATION-BINARY] [impl->REQ-MSG-IDLE-TRANSLATION-BINARY]

Co-authored by: todlando
EOF
)"

Commit Layer G


[v0.13.0-delivery-control 5b51cb5] test(daemon): W2 Layer G — real translation-binary int gate + commit-deadline override (ADR-0022)
 5 files changed, 785 insertions(+), 23 deletions(-)
 create mode 100644 crates/spt-daemon/src/bin/xlate_choreo_fixture.rs


Layer G committed @5b51cb5. **W2 complete** (A/B/C/D/E/G done; F = gravity-linux follow-up). Surface to doyle for the authoritative gate — all 5 locked criteria hit, independently verified:


$OWL send doyle <<'EOF'
SURFACING for the AUTHORITATIVE W2 GATE — Layer G GREEN @5b51cb5. W2 complete (A/B/C/D/E/G; F=gravity follow-up). Independently verified from a quiesced tree (NOT trust-the-green): I read every new test + the fixture, then re-ran the gates myself after the subagent came to rest.

Your 5 locked gate criteria, each met:
1. REAL fixture, no mocks — src/bin/xlate_choreo_fixture.rs, a pure stdin->stdout JSON-lines filter the broker lifecycle-spawns; PTY child = real echo child (cat/findstr); real broker+PTY+IPC.
2. Real byte receipt (W1b-grade) — g1 observes {text:XLATE_OK} echoed back over the REAL broker output ring (NOT liveness). Hard-asserted cfg(unix)/gravity-linux; cfg(windows) captures-only because ConPTY doesn't surface an injected line's cooked echo (the file's existing park-(b) divergence stance — g1 keeps 3 hard asserts on Windows so it's non-vacuous). The hard receipt proof lands on the gravity CI run.
3. Commit-deadline FAULT proven — g2 (SPT_INJECT_COMMIT_DEADLINE_MS=400): buffered operator keys flush after the deadline (controller never wedges) + subsequent delivery falls back to raw inject (binary faulted). HARD both platforms.
4. Content-free ping privacy — g3: operator secret reaches the PTY but NEVER the binary's stdin log; saw_input_ping guards vacuity. HARD both platforms.
5. No-zombie reap on fault/down — g4: translation child reaped within the bounded window after session-down. HARD both platforms.

Gates (my independent run): cargo nextest -p spt-daemon --test inject_control_wedge = 7/7 (g1-g4 + the 3 W1/W1b, no regression); cargo clippy --workspace --all-targets -D warnings = clean; traceable EXIT=0 (REQ-MSG-IDLE-TRANSLATION-BINARY now [doc,impl,unit,int]; REQ-HAZARD-INJECT-CONTROL-COEXIST still [impl,unit,int]); real target\debug\spt.exe rebuilt.

Process note: ONE spt-test-engineer (perch todlando-w172), background, no Monitor, came to rest clean — no two-subagent collision this time. Commits: C+E @f9fe5bb, G @5b51cb5.

Your gate. After PASS: W2 closes; the queue is W4 (picker UX) / W5 (driven_by self-heal) / W6 (perri translation-binary hand-off, now unblocked) + the Layer F gravity-linux follow-up. W3 already DONE. Standing by.
EOF
echo "SENT exit=$?"

Surface W2 Layer G for doyle authoritative gate


➜ SENT:doyle
SENT exit=0


**W2 complete + surfaced to doyle for the authoritative gate.** Session summary:

| Work | Commit | Status |
|---|---|---|
| W7-swap (Ctrl+Backspace=word-del) | `95f742f` | doyle GATE PASS ✓ |
| F1 hang-guard (runner-contract note) | `6034479` | doyle GATE PASS ✓ |
| W2 Layer C+E (atomic inject + routing) | `f9fe5bb` | gated ✓ |
| W2 Layer G (real-fixture int gate) | `5b51cb5` | **awaiting doyle authoritative gate** |

**W2 keystone done** — A/B/C/D/E/G all landed. The injection-coexists-with-controller spine: per-session inject worker opens floor → feeds the translation binary → drains key/text/delay/commit → flushes buffered operator input AFTER the sequence → releases. Bounded by `INJECT_COMMIT_DEADLINE` + FAULT→raw-inject degrade. All 5 doyle gate criteria hit; independently re-verified from a quiesced tree (7/7 nextest, clippy clean, traceable EXIT=0, real bin rebuilt). REQ-MSG-IDLE-TRANSLATION-BINARY now `[doc,impl,unit,int]`.

**Deferred:** Layer F (Unix park bound) → gravity-linux follow-up (cfg(unix), unverifiable on Windows; doyle-sanctioned, shares W1b F3).

**Process win:** ONE spt-test-engineer, background, no Monitor, came to rest clean — no two-subagent collision (the banked lesson held).

Standing by for doyle's gate. Next queue (doyle holds): W4 picker UX / W5 `driven_by` self-heal / W6 perri translation-binary hand-off (now unblocked) + the Layer F gravity follow-up.


<task-notification>
<task-id>bv8r78fk1</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/5" id="23c36e34" type="msg" from="doyle">doyle W2 GATE PASS — Layer G @5b51cb5, the ADR-0022 keystone is DONE. Independently verified (not trust-the-green): read xlate_choreo_fixture.rs (clean pure stdin→stdout filter, real choreo, nocommit FAULT mode, EOF-exit no-zombie, stdin-log for privacy) + g1-g4 (non-vacuous: g3 types a real SECRET + saw-ping guard;</EVENT-PART>
<EVENT-PART seq="2/5" id="23c36e34"> g1 hard byte-receipt on unix + 3 hard asserts on Windows; g2 deadline-400ms FAULT→flush→raw-inject fallback; g4 bounded reap). Re-ran myself: nextest -p spt-daemon --test inject_control_wedge = 7/7 (no W1/W1b regression); clippy --workspace -D warnings = clean; traceable EXIT=0 (REQ-MSG-IDLE-TRANSLATION-BINARY [doc,impl,unit,int]). The ct</EVENT-PART>
<EVENT-PART seq="3/5" id="23c36e34">rl+q/XON fixture artifact is sound + documented.

ALL 5 gate criteria met: real fixture / real byte-receipt (W1b-grade) / commit-deadline FAULT / content-free-ping privacy / no-zombie reap.

ONE OPEN VERIFICATION (not a block): g1's HARD byte-receipt is cfg(unix)/gravity-linux only — my local Windows run can't fire it (ConPTY abs</EVENT-PART>
<EVENT-PART seq="4/5" id="23c36e34">orbs cooked echo). It rides the gravity-linux CI leg, which fires on PR. So W2's headline &quot;real bytes reached the PTY&quot; hard-proof is PENDING the gravity CI run at PR/release. Confirm gravity-linux green when the v0.13.0 PR runs (same discipline as the M11/M12 CI-both-runners gates). Same applies to Layer F (gravity follow-up) + W1b F</EVENT-PART>
<EVENT-PART seq="5/5" id="23c36e34">3.

W2 CLOSED (pending that CI leg). Queue: W4 (picker UX) / W5 (driven_by self-heal) / W6 (perri handoff — NOW UNBLOCKED, I'll drive it) + Layer F gravity. W3 done. Excellent build — repro-first held all the way through. Take W4 or W5 next; I'll handle W6/perri.</EVENT-PART></event>
</task-notification>


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


doyle W2 GATE PASS @5b51cb5 — ADR-0022 keystone CLOSED (pending the gravity-linux CI leg for g1's hard byte-receipt, which rides the PR). doyle takes W6/perri; I take W4 or W5.

Picking **W5** (`driven_by` self-heal) — self-contained, composes directly with the W1/W1b/W2 control-plane work I have loaded (reuses `clear_controller`/reconcile). Warm context makes it cheap now. First check for collision (psyche said W4/W5 "queued in worktrees") + read the reconcile path:


cd /c/Users/decid/Documents/projects/spt-core; echo "=== worktrees ==="; git worktree list; echo "=== W4/W5 branches ==="; git branch -a | grep -iE "w4|w5|picker|driven|self-heal" ; echo "=== reconcile / driven_by sites ==="; grep -rln "driven_by\|fn reconcile\|HOSTED-LIVENESS-RECONCILE\|clear_controller" crates/spt-daemon/src/ crates/spt/src/ | head

Check worktrees/branches for W5 + locate reconcile/driven_by


=== worktrees ===
C:/Users/decid/Documents/projects/spt-core          5b51cb5 [v0.13.0-delivery-control]
C:/Users/decid/Documents/projects/spt-core-doyle    ec162c7 [v0.12.1-help-md]
C:/Users/decid/Documents/projects/spt-core-opbuild  6034479 (detached HEAD)
=== W4/W5 branches ===
  v0.10.0-picker-status
  v0.9.1-picker-status
  remotes/origin/v0.10.0-picker-status
=== reconcile / driven_by sites ===
crates/spt-daemon/src/attach.rs
crates/spt-daemon/src/brain.rs
crates/spt-daemon/src/broker.rs
crates/spt-daemon/src/livehost.rs
crates/spt-daemon/src/msg.rs
crates/spt-daemon/src/shellwake.rs
crates/spt-daemon/src/sync.rs
crates/spt/src/api/mod.rs
crates/spt/src/api/reporting.rs
crates/spt/src/picker/data.rs


No W5 worktree/branch in progress — "queued" was loose; safe to build W5 on the main worktree. (`spt-core-opbuild` @6034479 = doyle's operator-binary PATH deploy; no collision.)

Let me read the W5 mechanism — `reconcile`, `driven_by`, and the sister hazard REQ-HAZARD-HOSTED-LIVENESS-RECONCILE:


cd /c/Users/decid/Documents/projects/spt-core; echo "=== reconcile.rs surface ==="; grep -n "fn \|driven_by\|controller\|CONTROLLED\|is_process_alive\|status" crates/spt-daemon/src/reconcile.rs | head -40; echo "=== driven_by definition + setters ==="; grep -rn "driven_by" crates/spt-store/src/*.rs crates/spt-daemon/src/reconcile.rs | head

Map reconcile.rs + driven_by


=== reconcile.rs surface ===
29:pub fn is_reconciler(rows: &[Instance], self_node: &str) -> bool {
30:    let active: Vec<&Instance> = rows.iter().filter(|i| i.status == Status::Active).collect();
36:        .filter(|i| i.status != Status::Offline)
49:    fn inst(node: &str, status: Status) -> Instance {
52:            status,
64:    fn active_node_wins() {
74:    fn fallback_lowest_non_offline() {
86:    fn double_active_tiebreaks_deterministically() {
93:    fn no_rows_reconciles_locally() {
=== driven_by definition + setters ===
crates/spt-store/src/info.rs:100:    pub driven_by: Option<String>,
crates/spt-store/src/info.rs:104:    /// add/remove/evict; the picker renders `controlled by <driven_by> (+N
crates/spt-store/src/info.rs:106:    /// best-effort/self-heal caveat as `driven_by`. `default` so older records
crates/spt-store/src/info.rs:192:            driven_by: None,
crates/spt-store/src/info.rs:286:/// Stamp (or clear, with `None`) the `driven_by` remote-drive marker (REQ-REACH-1):
crates/spt-store/src/info.rs:290:pub fn set_driven_by(perch_path: &Path, node: Option<&str>) -> std::io::Result<()> {
crates/spt-store/src/info.rs:291:    mutate_info(perch_path, |rec| rec.driven_by = node.map(str::to_string))
crates/spt-store/src/info.rs:431:            driven_by: None,
crates/spt-store/src/info.rs:505:    // the transient setters (last_active/rest/driven_by/viewer_count — each a
crates/spt-store/src/info.rs:532:                    let _ = set_driven_by(&path, Some("nodehex"));


`driven_by` lives in `info.json`; W5's self-heal mirrors the B2 liveness reconcile (REQ-HAZARD-HOSTED-LIVENESS-RECONCILE). Let me scope it repro-first — find where `driven_by` is stamped on remote-drive + the existing liveness reconcile sweep W5 hooks into:


cd /c/Users/decid/Documents/projects/spt-core; echo "=== set_driven_by callers ==="; grep -rn "set_driven_by" crates/ | grep -v "fn set_driven_by\|info.rs"; echo "=== HOSTED-LIVENESS-RECONCILE ==="; grep -rln "HOSTED-LIVENESS-RECONCILE" crates/ docs/; echo "=== liveness reconcile fn (B2) ==="; grep -rn "fn reconcile_liveness\|fn reconcile_hosted\|reconcile.*status\|fn sweep\|status = Status::Offline\|supersedes is_process_alive" crates/spt-daemon/src/*.rs | head

Find driven_by setters + the B2 liveness reconcile


=== set_driven_by callers ===
crates/spt/src/api/reporting.rs:935:        info::set_driven_by(&perch_path, Some("cafe1234")).unwrap();
crates/spt-daemon/src/broker.rs:568:        let _ = spt_store::info::set_driven_by(&perch, self.controller_by());
=== HOSTED-LIVENESS-RECONCILE ===
crates/spt/tests/attach_wedge_e2e.rs
crates/spt-daemon/src/livehost.rs
=== liveness reconcile fn (B2) ===
crates/spt-daemon/src/lifecycle.rs:164:    pub fn sweep_on_start(&self) {
crates/spt-daemon/src/livehost.rs:511:pub fn reconcile_hosted_liveness(owlery: &Path, live_sessions: &BTreeSet<String>) -> Vec<String> {
crates/spt-daemon/src/livehost.rs:1063:    // reconcile clears the status=online latch and marks the perch offline.


511	pub fn reconcile_hosted_liveness(owlery: &Path, live_sessions: &BTreeSet<String>) -> Vec<String> {
512	    let mut offlined = Vec::new();
513	    for id in perch::list_self_perch_ids(owlery) {
514	        let perch = perch::resolve_perch_path(&id, ParentHint::Infer);
515	        let Some(info) = spt_store::info::read_info(&perch) else {
516	            continue;
517	        };
518	        if info.state != LIVE_AGENT_STATE {
519	            continue; // not a live agent
520	        }
521	        if info.status.as_deref() != Some(STATUS_ONLINE) {
522	            continue; // already offline / interim (status-absent)
523	        }
524	        if info.controllable != Some(true) {
525	            continue; // harness-hosted relay (Some(false)) / legacy (None) — exempt
526	        }
527	        if !live_sessions.contains(&id) {
528	            // spt-hosted, online-latched, but the broker hosts no session → the
529	            // harness child is gone. Clear the latch (the keystone).
530	            BrainLifecycle::mark_offline(&perch);
531	            eprintln!("LIVENESS_RECONCILE_OFFLINE:{id}: no live broker session (dead harness)");
532	            offlined.push(id);
533	        }
534	    }
535	    offlined
536	}
537
538	/// Query the broker for the set of endpoint ids it currently hosts a session for
539	/// (`KIND_SESSIONS`) — the B2 pull signal. `None` when the broker is unreachable
540	/// (the caller then SKIPS the offline pass this tick rather than mass-offlining).
541	fn query_live_session_endpoints() -> Option<BTreeSet<String>> {
542	    let mut brain = Brain::cold_start(&crate::endpoint::broker_socket_name(), now_ms()).ok()?;
543	    let reply = brain.sessions().ok()?;
544	    Some(
545	        reply
546	            .sessions
547	            .into_iter()
548	            .map(|s| s.endpoint)
549	            .filter(|e| !e.is_empty())
550	            .collect(),
551	    )
552	}
553
554	/// The normalized program basename a perch's adapter would spawn its Psyche as —
555	/// the first whitespace token of `psyche_init.command`, file-name only, run through
556	/// [`normalize_basename`](spt_runtime::resolve::normalize_basename) (lowercase /
557	/// `.exe`-strip / dot-stem) so it keys the same as a live exe basename. `None` for
558	/// an empty command. // [impl->REQ-HAZARD-BRAIN-RESTART-PSYCHE-DUP]
559	fn psyche_program_norm(command: &str) -> Option<String> {
560	    let token = command.split_whitespace().next()?;
561	    let file = Path::new(token).file_name()?.to_string_lossy().into_owned();
562	    Some(spt_runtime::resolve::normalize_basename(&file))
563	}
564
565	/// Whether `pid` is the live `{id}-psyche` orphan we may reap — the ID-SPECIFIC
566	/// recycle guard (REQ-HAZARD-BRAIN-RESTART-PSYCHE-DUP). NOT basename-only: on a
567	/// shared box sibling agents share the `claude` basename, so a recycled pid landing
568	/// on a SIBLING'S `claude` would match basename alone → a wrong-kill of a live agent.
569	/// Requires ALL THREE — alive, exe basename == the adapter's psyche program, AND the
570	/// command line contains the FULL psyche id `<id>-psyche` (baked into the psyche argv
571	/// via `{id}`; a sibling `agent-other-psyche` never contains `agent-psyche`). FAILS
572	/// SAFE: any None (dead / unreadable basename / unreadable cmdline) ⇒ `false`, i.e.
573	/// decline to reap — a missed dup is cheap (Breap bounds it at daemon-stop), a
574	/// wrong-kill is catastrophic.
575	///
576	/// CAVEAT: the cmdline carries `<id>-psyche` only when the adapter's
577	/// `psyche_init.command` uses `{id}` (the norm — a Psyche needs its identity;
578	/// spt-claude-code does). An adapter that omits `{id}` SAFELY MISSES this reap
579	/// (the dup lingers until daemon-stop/Breap, exactly today's behavior) — never a
580	/// wrong-kill. If a real non-`{id}` psyche adapter ever ships, add a start-time

pub fn reconcile_hosted_liveness(owlery: &Path, live_sessions: &BTreeSet<String>) -> Vec<String> {
    let mut offlined = Vec::new();
    for id in perch::list_self_perch_ids(owlery) {
        let perch = perch::resolve_perch_path(&id, ParentHint::Infer);
        let Some(info) = spt_store::info::read_info(&perch) else {
            continue;
        };
        if info.state != LIVE_AGENT_STATE {
            continue; // not a live agent
        }
        if info.status.as_deref() != Some(STATUS_ONLINE) {
            continue; // already offline / interim (status-absent)
        }
        if info.controllable != Some(true) {
            continue; // harness-hosted relay (Some(false)) / legacy (None) — exempt
        }
        if !live_sessions.contains(&id) {
            // spt-hosted, online-latched, but the broker hosts no session → the
            // harness child is gone. Clear the latch (the keystone).
            BrainLifecycle::mark_offline(&perch);
            eprintln!("LIVENESS_RECONCILE_OFFLINE:{id}: no live broker session (dead harness)");
            offlined.push(id);
        }
    }
    offlined
}

/// Query the broker for the set of endpoint ids it currently hosts a session for
/// (`KIND_SESSIONS`) — the B2 pull signal. `None` when the broker is unreachable
/// (the caller then SKIPS the offline pass this tick rather than mass-offlining).
fn query_live_session_endpoints() -> Option<BTreeSet<String>> {
    let mut brain = Brain::cold_start(&crate::endpoint::broker_socket_name(), now_ms()).ok()?;
    let reply = brain.sessions().ok()?;
    Some(
        reply
            .sessions
            .into_iter()
            .map(|s| s.endpoint)
            .filter(|e| !e.is_empty())
            .collect(),
    )
}

/// The normalized program basename a perch's adapter would spawn its Psyche as —
/// the first whitespace token of `psyche_init.command`, file-name only, run through
/// [`normalize_basename`](spt_runtime::resolve::normalize_basename) (lowercase /
/// `.exe`-strip / dot-stem) so it keys the same as a live exe basename. `None` for
/// an empty command. // [impl->REQ-HAZARD-BRAIN-RESTART-PSYCHE-DUP]
fn psyche_program_norm(command: &str) -> Option<String> {
    let token = command.split_whitespace().next()?;
    let file = Path::new(token).file_name()?.to_string_lossy().into_owned();
    Some(spt_runtime::resolve::normalize_basename(&file))
}

/// Whether `pid` is the live `{id}-psyche` orphan we may reap — the ID-SPECIFIC
/// recycle guard (REQ-HAZARD-BRAIN-RESTART-PSYCHE-DUP). NOT basename-only: on a
/// shared box sibling agents share the `claude` basename, so a recycled pid landing
/// on a SIBLING'S `claude` would match basename alone → a wrong-kill of a live agent.
/// Requires ALL THREE — alive, exe basename == the adapter's psyche program, AND the
/// command line contains the FULL psyche id `<id>-psyche` (baked into the psyche argv
/// via `{id}`; a sibling `agent-other-psyche` never contains `agent-psyche`). FAILS
/// SAFE: any None (dead / unreadable basename / unreadable cmdline) ⇒ `false`, i.e.
/// decline to reap — a missed dup is cheap (Breap bounds it at daemon-stop), a
/// wrong-kill is catastrophic.
///
/// CAVEAT: the cmdline carries `<id>-psyche` only when the adapter's
/// `psyche_init.command` uses `{id}` (the norm — a Psyche needs its identity;
/// spt-claude-code does). An adapter that omits `{id}` SAFELY MISSES this reap
/// (the dup lingers until daemon-stop/Breap, exactly today's behavior) — never a
/// wrong-kill. If a real non-`{id}` psyche adapter ever ships, add a start-time


The B2 pattern is clear: `reconcile_hosted_liveness` sweeps self-perches → clears the latch when no live session. W5 is the same shape for `driven_by`. Let me nail the grounding — `set_driven_by` at broker.rs:568 + the `clear_controller` synergy:


545	    fn all_sinks(&self) -> Vec<SharedSend> {
546	        let mut v: Vec<SharedSend> = Vec::new();
547	        if let Some(c) = &self.controller {
548	            v.push(Arc::clone(&c.send));
549	        }
550	        for sink in self.viewers.values() {
551	            v.push(Arc::clone(&sink.send));
552	        }
553	        v
554	    }
555
556	    /// Stamp the perch's `driven_by` to the current controller's identity (the
557	    /// broker is the single writer — resolves the clear-race). The remote-drive
558	    /// detection fact (REQ-REACH-1) moved here from `serve_attach` so a displaced
559	    /// operator's teardown can never wipe the new controller's marker.
560	    /// Best-effort: a session served without a perch (raw broker tests) has
561	    /// nowhere to record.
562	    // [impl->REQ-RCVIEW-1] [impl->REQ-REACH-1]
563	    fn stamp_driven_by(&self) {
564	        if self.endpoint.is_empty() {
565	            return;
566	        }
567	        let perch = resolve_perch_path(&self.endpoint, ParentHint::Infer);
568	        let _ = spt_store::info::set_driven_by(&perch, self.controller_by());
569	    }
570
571	    /// Stamp the perch's `viewer_count` to the live viewer count (broker is the
572	    /// single writer). Best-effort, like [`OutputLog::stamp_driven_by`].
573	    // [impl->REQ-RCVIEW-1]
574	    fn stamp_viewer_count(&self) {
575	        if self.endpoint.is_empty() {
576	            return;
577	        }
578	        let perch = resolve_perch_path(&self.endpoint, ParentHint::Infer);
579	        let _ = spt_store::info::set_viewer_count(&perch, self.viewers.len() as u32);
580	    }
581
582	    /// Whether `sub` is the current controller (the resize-exclusivity check).
583	    fn is_controller(&self, sub: &SharedSend) -> bool {
584	        self.controller
585	            .as_ref()
586	            .is_some_and(|c| Arc::ptr_eq(&c.send, sub))
587	    }
588
589	    /// The next seq a re-attaching controller still needs (the persisted resume

    fn all_sinks(&self) -> Vec<SharedSend> {
        let mut v: Vec<SharedSend> = Vec::new();
        if let Some(c) = &self.controller {
            v.push(Arc::clone(&c.send));
        }
        for sink in self.viewers.values() {
            v.push(Arc::clone(&sink.send));
        }
        v
    }

    /// Stamp the perch's `driven_by` to the current controller's identity (the
    /// broker is the single writer — resolves the clear-race). The remote-drive
    /// detection fact (REQ-REACH-1) moved here from `serve_attach` so a displaced
    /// operator's teardown can never wipe the new controller's marker.
    /// Best-effort: a session served without a perch (raw broker tests) has
    /// nowhere to record.
    // [impl->REQ-RCVIEW-1] [impl->REQ-REACH-1]
    fn stamp_driven_by(&self) {
        if self.endpoint.is_empty() {
            return;
        }
        let perch = resolve_perch_path(&self.endpoint, ParentHint::Infer);
        let _ = spt_store::info::set_driven_by(&perch, self.controller_by());
    }

    /// Stamp the perch's `viewer_count` to the live viewer count (broker is the
    /// single writer). Best-effort, like [`OutputLog::stamp_driven_by`].
    // [impl->REQ-RCVIEW-1]
    fn stamp_viewer_count(&self) {
        if self.endpoint.is_empty() {
            return;
        }
        let perch = resolve_perch_path(&self.endpoint, ParentHint::Infer);
        let _ = spt_store::info::set_viewer_count(&perch, self.viewers.len() as u32);
    }

    /// Whether `sub` is the current controller (the resize-exclusivity check).
    fn is_controller(&self, sub: &SharedSend) -> bool {
        self.controller
            .as_ref()
            .is_some_and(|c| Arc::ptr_eq(&c.send, sub))
    }

    /// The next seq a re-attaching controller still needs (the persisted resume


cd /c/Users/decid/Documents/projects/spt-core; grep -n "fn clear_controller\|fn controller_by\|fn become_controller\|stamp_driven_by()" crates/spt-daemon/src/broker.rs

Find clear_controller + stamp_driven_by call sites


336:    fn controller_by(&self) -> Option<&str> {
349:    fn become_controller(&mut self, sub: SharedSend, by: Option<String>, from_seq: u64) {
374:        self.stamp_driven_by();
382:    fn clear_controller(&mut self) {
384:            self.stamp_driven_by();