6935	        );
6936	    }
6937
6938	    // [unit->REQ-SUBNET-1] the bounded probe seam: a fast op returns its value;
6939	    // an op that overruns the deadline yields the timeout default (so the
6940	    // --nodes view never hangs on a dead peer's full dial timeout).
6941	    #[test]
6942	    fn run_bounded_yields_value_or_timeout_default() {
6943	        use std::time::Duration;
6944	        assert_eq!(run_bounded(Duration::from_secs(5), 0, || 42), 42);
6945	        assert_eq!(
6946	            run_bounded(Duration::from_millis(50), -1, || {
6947	                std::thread::sleep(Duration::from_millis(800));
6948	                7
6949	            }),
6950	            -1,
6951	            "an op past the deadline reads as the timeout default"
6952	        );
6953	    }
6954
6955	    // [unit->REQ-SUBNET-3] label collision: two nodes sharing a hostname each
6956	    // get the key-prefix disambiguator back (the addressing layer forces it
6957	    // anyway); a unique label stays clean in the same render.
6958	    #[test]
6959	    fn node_rows_disambiguate_only_on_label_collision() {
6960	        let row = |node: &str, label: &str| {
6961	            (
6962	                NodeRow {
6963	                    node: node.to_string(),
6964	                    label: Some(label.to_string()),
6965	                    active: 0,
6966	                    total: 0,
6967	                    liveness: NodeLiveness::Online,
6968	                },
6969	                true,
6970	            )
6971	        };
6972	        // Two BUILDER nodes (shared hostname) + one unique HOST.
6973	        let rows = vec![
6974	            row("aaaa1111deadbeef", "BUILDER"),

        );
    }

    // [unit->REQ-SUBNET-1] the bounded probe seam: a fast op returns its value;
    // an op that overruns the deadline yields the timeout default (so the
    // --nodes view never hangs on a dead peer's full dial timeout).
    #[test]
    fn run_bounded_yields_value_or_timeout_default() {
        use std::time::Duration;
        assert_eq!(run_bounded(Duration::from_secs(5), 0, || 42), 42);
        assert_eq!(
            run_bounded(Duration::from_millis(50), -1, || {
                std::thread::sleep(Duration::from_millis(800));
                7
            }),
            -1,
            "an op past the deadline reads as the timeout default"
        );
    }

    // [unit->REQ-SUBNET-3] label collision: two nodes sharing a hostname each
    // get the key-prefix disambiguator back (the addressing layer forces it
    // anyway); a unique label stays clean in the same render.
    #[test]
    fn node_rows_disambiguate_only_on_label_collision() {
        let row = |node: &str, label: &str| {
            (
                NodeRow {
                    node: node.to_string(),
                    label: Some(label.to_string()),
                    active: 0,
                    total: 0,
                    liveness: NodeLiveness::Online,
                },
                true,
            )
        };
        // Two BUILDER nodes (shared hostname) + one unique HOST.
        let rows = vec![
            row("aaaa1111deadbeef", "BUILDER"),


Enough context. Implement: hoist consts, add `probe_all`, rewrite caller into 3 passes.


Edit

// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
fn probe_node(node_hex: &str, subnet: &str) -> bool {
    const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
    let hex = node_hex.to_string();
    let sub = subnet.to_string();
    run_bounded(PROBE_TIMEOUT, false, move || {
        crate::wansend::probe_node_serving(&hex, &sub)
    })
}

// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

fn probe_node(node_hex: &str, subnet: &str) -> bool {
    let hex = node_hex.to_string();
    let sub = subnet.to_string();
    run_bounded(PROBE_TIMEOUT, false, move || {
        crate::wansend::probe_node_serving(&hex, &sub)
    })
}

/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input
/// order. Wall-time ≈ ONE `ceiling` when `items.len() <= max_inflight`,
/// else `ceil(k / max_inflight)` ceilings. The mesh widen (D6) makes a node
/// see ALL roster members — many silent — so the serial per-node `probe_node`
/// loop cost `offline_count × ceiling`; this fans it out (REQ-MESH-6). `probe`
/// is INJECTED so the unit test passes a deterministic sleeper (no network);
/// the real site passes `probe_node_serving`. Each probe still runs on its own
/// thread under its own `recv_timeout(ceiling)` bound (via `run_bounded`), so
/// one wedged dial costs ONE ceiling, never the batch — KH 5.3 preserved.
// [impl->REQ-MESH-6]
fn probe_all<F>(
    items: &[(String, String)],
    ceiling: std::time::Duration,
    max_inflight: usize,
    probe: F,
) -> Vec<bool>
where
    F: Fn(&str, &str) -> bool + Send + Sync + 'static,
{
    if items.is_empty() {
        return Vec::new();
    }
    let cap = max_inflight.max(1);
    if items.len() > cap {
        eprintln!(
            "Probing {} nodes in batches of {} — wait may be a small multiple of the probe ceiling.",
            items.len(),
            cap
        );
        let _ = std::io::stderr().flush();
    }
    let probe = std::sync::Arc::new(probe);
    let mut out = vec![false; items.len()];
    // Process in windows of `cap`: each window spawns one bounded thread per
    // item and joins before the next, so in-flight never exceeds `cap` and
    // every window is bounded by one `ceiling`. Wall ≈ ceil(k/cap)×ceiling.
    for (wi, window) in items.chunks(cap).enumerate() {
        let base = wi * cap;
        let handles: Vec<(usize, std::thread::JoinHandle<bool>)> = window
            .iter()
            .enumerate()
            .map(|(off, (node, subnet))| {
                let probe = probe.clone();
                let node = node.clone();
                let subnet = subnet.clone();
                (
                    base + off,
                    std::thread::spawn(move || {
                        run_bounded(ceiling, false, move || probe(&node, &subnet))
                    }),
                )
            })
            .collect();
        for (idx, h) in handles {
            out[idx] = h.join().unwrap_or(false);
        }
    }
    out
}


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

// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
fn probe_node(node_hex: &str, subnet: &str) -> bool {
    const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
    let hex = node_hex.to_string();
    let sub = subnet.to_string();
    run_bounded(PROBE_TIMEOUT, false, move || {
        crate::wansend::probe_node_serving(&hex, &sub)
    })
}

// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

fn probe_node(node_hex: &str, subnet: &str) -> bool {
    let hex = node_hex.to_string();
    let sub = subnet.to_string();
    run_bounded(PROBE_TIMEOUT, false, move || {
        crate::wansend::probe_node_serving(&hex, &sub)
    })
}

/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input
/// order. Wall-time ≈ ONE `ceiling` when `items.len() <= max_inflight`,
/// else `ceil(k / max_inflight)` ceilings. The mesh widen (D6) makes a node
/// see ALL roster members — many silent — so the serial per-node `probe_node`
/// loop cost `offline_count × ceiling`; this fans it out (REQ-MESH-6). `probe`
/// is INJECTED so the unit test passes a deterministic sleeper (no network);
/// the real site passes `probe_node_serving`. Each probe still runs on its own
/// thread under its own `recv_timeout(ceiling)` bound (via `run_bounded`), so
/// one wedged dial costs ONE ceiling, never the batch — KH 5.3 preserved.
// [impl->REQ-MESH-6]
fn probe_all<F>(
    items: &[(String, String)],
    ceiling: std::time::Duration,
    max_inflight: usize,
    probe: F,
) -> Vec<bool>
where
    F: Fn(&str, &str) -> bool + Send + Sync + 'static,
{
    if items.is_empty() {
        return Vec::new();
    }
    let cap = max_inflight.max(1);
    if items.len() > cap {
        eprintln!(
            "Probing {} nodes in batches of {} — wait may be a small multiple of the probe ceiling.",
            items.len(),
            cap
        );
        let _ = std::io::stderr().flush();
    }
    let probe = std::sync::Arc::new(probe);
    let mut out = vec![false; items.len()];
    // Process in windows of `cap`: each window spawns one bounded thread per
    // item and joins before the next, so in-flight never exceeds `cap` and
    // every window is bounded by one `ceiling`. Wall ≈ ceil(k/cap)×ceiling.
    for (wi, window) in items.chunks(cap).enumerate() {
        let base = wi * cap;
        let handles: Vec<(usize, std::thread::JoinHandle<bool>)> = window
            .iter()
            .enumerate()
            .map(|(off, (node, subnet))| {
                let probe = probe.clone();
                let node = node.clone();
                let subnet = subnet.clone();
                (
                    base + off,
                    std::thread::spawn(move || {
                        run_bounded(ceiling, false, move || probe(&node, &subnet))
                    }),
                )
            })
            .collect();
        for (idx, h) in handles {
            out[idx] = h.join().unwrap_or(false);
        }
    }
    out
}

+const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);

+/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a

+/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker

+/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒

+/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).

-    const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);

+/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input

+/// order. Wall-time ≈ ONE `ceiling` when `items.len() <= max_inflight`,

+/// else `ceil(k / max_inflight)` ceilings. The mesh widen (D6) makes a node

+/// see ALL roster members — many silent — so the serial per-node `probe_node`

+/// loop cost `offline_count × ceiling`; this fans it out (REQ-MESH-6). `probe`

+/// is INJECTED so the unit test passes a deterministic sleeper (no network);

+/// the real site passes `probe_node_serving`. Each probe still runs on its own

+/// thread under its own `recv_timeout(ceiling)` bound (via `run_bounded`), so

+/// one wedged dial costs ONE ceiling, never the batch — KH 5.3 preserved.

+    F: Fn(&str, &str) -> bool + Send + Sync + 'static,

+            "Probing {} nodes in batches of {} — wait may be a small multiple of the probe ceiling.",

+        let _ = std::io::stderr().flush();

+    let probe = std::sync::Arc::new(probe);

+    let mut out = vec![false; items.len()];

+    // Process in windows of `cap`: each window spawns one bounded thread per

+    // item and joins before the next, so in-flight never exceeds `cap` and

+    // every window is bounded by one `ceiling`. Wall ≈ ceil(k/cap)×ceiling.

+    for (wi, window) in items.chunks(cap).enumerate() {

+        let handles: Vec<(usize, std::thread::JoinHandle<bool>)> = window

+            .map(|(off, (node, subnet))| {

+                let probe = probe.clone();

+                let node = node.clone();

+                let subnet = subnet.clone();

+                    std::thread::spawn(move || {

+                        run_bounded(ceiling, false, move || probe(&node, &subnet))

+            out[idx] = h.join().unwrap_or(false);

/// Render the coming-online banner's "spt subnets joined" section + the

/// concluding divider: header, underline, one `NAME: <state>` row per held

/// subnet (`(none)` when empty), divider. Pure for tests.


Now rewrite the caller into 3 passes:


    let mut out = String::new();
    // Announce the probe phase once, before any dial — a silent node costs a
    // bounded dial (probe_node) and the user should know what the wait is for.
    let mut announced = false;
    for sub in &store.subnets {
        if name.as_deref().is_some_and(|n| n != sub.name) {
            continue;
        }
        let empty = spt_net::net::registry::SubnetRegistry::new();
        let reg = regs.get(&sub.name).unwrap_or(&empty);
        // Membership seed: self + roster members (rowless members still
        // render — fresh boxes and eviction-decayed offline peers alike).
        let mut members: Vec<(String, Option<String>)> = Vec::new();
        if !own_hex.is_empty() {
            members.push((own_hex.clone(), spt_store::hostlabel::os_hostname()));
        }
        for member in roster.members_in(&sub.name) {
            let label = (!member.label.is_empty()).then(|| member.label.clone());
            members.push((member.pubkey_hex.clone(), label));
        }
        let rows = node_status_rows(reg, &members, &heard, &own_hex, now_ms(), stale_after_ms);
        if !announced && rows.iter().any(|r| r.liveness == NodeLiveness::Probe) {
            eprintln!("Checking remote nodes…");
            let _ = std::io::stderr().flush();
            announced = true;
        }
        let settled: Vec<(NodeRow, bool)> = rows
            .into_iter()
            .map(|r| {
                let online = match r.liveness {
                    NodeLiveness::Online => true,
                    NodeLiveness::Offline => false,
                    NodeLiveness::Probe => probe_node(&r.node, &sub.name),
                };
                (r, online)
            })
            .collect();
        out.push_str(&render_node_rows(&sub.name, &settled));
    }

    // Pass 1: classify every matching subnet's rows (pure `node_status_rows`),
    // collecting the silent (Probe) ones into ONE cross-subnet work-list. The
    // fan-out spans the whole view so a multi-subnet status pays one ceiling
    // total, not one per subnet.
    let mut per_subnet: Vec<(String, Vec<NodeRow>)> = Vec::new();
    let mut worklist: Vec<(String, String)> = Vec::new();
    for sub in &store.subnets {
        if name.as_deref().is_some_and(|n| n != sub.name) {
            continue;
        }
        let empty = spt_net::net::registry::SubnetRegistry::new();
        let reg = regs.get(&sub.name).unwrap_or(&empty);
        // Membership seed: self + roster members (rowless members still
        // render — fresh boxes and eviction-decayed offline peers alike).
        let mut members: Vec<(String, Option<String>)> = Vec::new();
        if !own_hex.is_empty() {
            members.push((own_hex.clone(), spt_store::hostlabel::os_hostname()));
        }
        for member in roster.members_in(&sub.name) {
            let label = (!member.label.is_empty()).then(|| member.label.clone());
            members.push((member.pubkey_hex.clone(), label));
        }
        let rows = node_status_rows(reg, &members, &heard, &own_hex, now_ms(), stale_after_ms);
        for r in &rows {
            if r.liveness == NodeLiveness::Probe {
                worklist.push((r.node.clone(), sub.name.clone()));
            }
        }
        per_subnet.push((sub.name.clone(), rows));
    }
    // Announce the probe phase once, before any dial — silent nodes cost a
    // bounded dial each and the user should know what the wait is for.
    if !worklist.is_empty() {
        eprintln!("Checking remote nodes…");
        let _ = std::io::stderr().flush();
    }
    // Pass 2: one CONCURRENT batch across ALL subnets (REQ-MESH-6). Wall ≈ one
    // PROBE_TIMEOUT (bounded by MAX_INFLIGHT), not k×PROBE_TIMEOUT serial.
    let probed = probe_all(&worklist, PROBE_TIMEOUT, MAX_INFLIGHT, |n, s| {
        crate::wansend::probe_node_serving(n, s)
    });
    // Pass 3: stitch results back in row order — the work-list was filled in
    // row order, so a single cursor walks it deterministically. Render is
    // unchanged (`render_node_rows`), so output matches the old serial path.
    let mut cursor = 0usize;
    let mut out = String::new();
    for (sub_name, rows) in per_subnet {
        let settled: Vec<(NodeRow, bool)> = rows
            .into_iter()
            .map(|r| {
                let online = match r.liveness {
                    NodeLiveness::Online => true,
                    NodeLiveness::Offline => false,
                    NodeLiveness::Probe => {
                        let v = probed.get(cursor).copied().unwrap_or(false);
                        cursor += 1;
                        v
                    }
                };
                (r, online)
            })
            .collect();
        out.push_str(&render_node_rows(&sub_name, &settled));
    }


    let mut out = String::new();
    // Announce the probe phase once, before any dial — a silent node costs a
    // bounded dial (probe_node) and the user should know what the wait is for.
    let mut announced = false;
    for sub in &store.subnets {
        if name.as_deref().is_some_and(|n| n != sub.name) {
            continue;
        }
        let empty = spt_net::net::registry::SubnetRegistry::new();
        let reg = regs.get(&sub.name).unwrap_or(&empty);
        // Membership seed: self + roster members (rowless members still
        // render — fresh boxes and eviction-decayed offline peers alike).
        let mut members: Vec<(String, Option<String>)> = Vec::new();
        if !own_hex.is_empty() {
            members.push((own_hex.clone(), spt_store::hostlabel::os_hostname()));
        }
        for member in roster.members_in(&sub.name) {
            let label = (!member.label.is_empty()).then(|| member.label.clone());
            members.push((member.pubkey_hex.clone(), label));
        }
        let rows = node_status_rows(reg, &members, &heard, &own_hex, now_ms(), stale_after_ms);
        if !announced && rows.iter().any(|r| r.liveness == NodeLiveness::Probe) {
            eprintln!("Checking remote nodes…");
            let _ = std::io::stderr().flush();
            announced = true;
        }
        let settled: Vec<(NodeRow, bool)> = rows
            .into_iter()
            .map(|r| {
                let online = match r.liveness {
                    NodeLiveness::Online => true,
                    NodeLiveness::Offline => false,
                    NodeLiveness::Probe => probe_node(&r.node, &sub.name),
                };
                (r, online)
            })
            .collect();
        out.push_str(&render_node_rows(&sub.name, &settled));
    }

    // Pass 1: classify every matching subnet's rows (pure `node_status_rows`),
    // collecting the silent (Probe) ones into ONE cross-subnet work-list. The
    // fan-out spans the whole view so a multi-subnet status pays one ceiling
    // total, not one per subnet.
    let mut per_subnet: Vec<(String, Vec<NodeRow>)> = Vec::new();
    let mut worklist: Vec<(String, String)> = Vec::new();
    for sub in &store.subnets {
        if name.as_deref().is_some_and(|n| n != sub.name) {
            continue;
        }
        let empty = spt_net::net::registry::SubnetRegistry::new();
        let reg = regs.get(&sub.name).unwrap_or(&empty);
        // Membership seed: self + roster members (rowless members still
        // render — fresh boxes and eviction-decayed offline peers alike).
        let mut members: Vec<(String, Option<String>)> = Vec::new();
        if !own_hex.is_empty() {
            members.push((own_hex.clone(), spt_store::hostlabel::os_hostname()));
        }
        for member in roster.members_in(&sub.name) {
            let label = (!member.label.is_empty()).then(|| member.label.clone());
            members.push((member.pubkey_hex.clone(), label));
        }
        let rows = node_status_rows(reg, &members, &heard, &own_hex, now_ms(), stale_after_ms);
        for r in &rows {
            if r.liveness == NodeLiveness::Probe {
                worklist.push((r.node.clone(), sub.name.clone()));
            }
        }
        per_subnet.push((sub.name.clone(), rows));
    }
    // Announce the probe phase once, before any dial — silent nodes cost a
    // bounded dial each and the user should know what the wait is for.
    if !worklist.is_empty() {
        eprintln!("Checking remote nodes…");
        let _ = std::io::stderr().flush();
    }
    // Pass 2: one CONCURRENT batch across ALL subnets (REQ-MESH-6). Wall ≈ one
    // PROBE_TIMEOUT (bounded by MAX_INFLIGHT), not k×PROBE_TIMEOUT serial.
    let probed = probe_all(&worklist, PROBE_TIMEOUT, MAX_INFLIGHT, |n, s| {
        crate::wansend::probe_node_serving(n, s)
    });
    // Pass 3: stitch results back in row order — the work-list was filled in
    // row order, so a single cursor walks it deterministically. Render is
    // unchanged (`render_node_rows`), so output matches the old serial path.
    let mut cursor = 0usize;
    let mut out = String::new();
    for (sub_name, rows) in per_subnet {
        let settled: Vec<(NodeRow, bool)> = rows
            .into_iter()
            .map(|r| {
                let online = match r.liveness {
                    NodeLiveness::Online => true,
                    NodeLiveness::Offline => false,
                    NodeLiveness::Probe => {
                        let v = probed.get(cursor).copied().unwrap_or(false);
                        cursor += 1;
                        v
                    }
                };
                (r, online)
            })
            .collect();
        out.push_str(&render_node_rows(&sub_name, &settled));
    }

let stale_after_ms = 3 * spt_daemon::DaemonConfig::load()

-    // Announce the probe phase once, before any dial — a silent node costs a

-    // bounded dial (probe_node) and the user should know what the wait is for.

+    // Pass 1: classify every matching subnet's rows (pure `node_status_rows`),

+    // collecting the silent (Probe) ones into ONE cross-subnet work-list. The

+    // fan-out spans the whole view so a multi-subnet status pays one ceiling

+    let mut per_subnet: Vec<(String, Vec<NodeRow>)> = Vec::new();

+    let mut worklist: Vec<(String, String)> = Vec::new();

-        if !announced && rows.iter().any(|r| r.liveness == NodeLiveness::Probe) {

-            eprintln!("Checking remote nodes…");

-            let _ = std::io::stderr().flush();

+            if r.liveness == NodeLiveness::Probe {

+                worklist.push((r.node.clone(), sub.name.clone()));

+        per_subnet.push((sub.name.clone(), rows));

+    // Announce the probe phase once, before any dial — silent nodes cost a

+    // bounded dial each and the user should know what the wait is for.

+        eprintln!("Checking remote nodes…");

+        let _ = std::io::stderr().flush();

+    // Pass 2: one CONCURRENT batch across ALL subnets (REQ-MESH-6). Wall ≈ one

+    // PROBE_TIMEOUT (bounded by MAX_INFLIGHT), not k×PROBE_TIMEOUT serial.

+    let probed = probe_all(&worklist, PROBE_TIMEOUT, MAX_INFLIGHT, |n, s| {

+        crate::wansend::probe_node_serving(n, s)

+    // Pass 3: stitch results back in row order — the work-list was filled in

+    // row order, so a single cursor walks it deterministically. Render is

+    // unchanged (`render_node_rows`), so output matches the old serial path.

+    for (sub_name, rows) in per_subnet {

-                    NodeLiveness::Probe => probe_node(&r.node, &sub.name),

+                    NodeLiveness::Probe => {

+                        let v = probed.get(cursor).copied().unwrap_or(false);

-        out.push_str(&render_node_rows(&sub.name, &settled));

+        out.push_str(&render_node_rows(&sub_name, &settled));


Add the 3 units near the `run_bounded` test:


            -1,
            "an op past the deadline reads as the timeout default"
        );
    }

            -1,
            "an op past the deadline reads as the timeout default"
        );
    }

    // [unit->REQ-MESH-6] the fan-out is CONCURRENT, not serial: N probes each
    // sleeping D finish in ≈ one D (plus scheduling slop), not N×D. Injected
    // deterministic sleeper — no network (the mock-clock seam the reg names).
    #[test]
    fn probe_all_runs_concurrently_in_input_order() {
        use std::time::{Duration, Instant};
        let d = Duration::from_millis(200);
        let items: Vec<(String, String)> = (0..8)
            .map(|i| (format!("node{i}"), "sub".to_string()))
            .collect();
        let start = Instant::now();
        // Result encodes the input index so we can prove order is preserved.
        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {
            std::thread::sleep(d);
            n.ends_with(|c: char| c.is_ascii_digit()) // always true here
        });
        let elapsed = start.elapsed();
        assert_eq!(got, vec![true; 8], "every probe settles, in input order");
        assert!(
            elapsed < 4 * d,
            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"
        );
    }

    // [unit->REQ-MESH-6] the in-flight cap BATCHES rather than serializing
    // fully or ignoring the bound: N=20 at cap=4, each sleeping D, runs in
    // ceil(20/4)=5 windows → ≈5×D, not 20×D (serial) and not ≈1×D (uncapped).
    #[test]
    fn probe_all_cap_batches_into_windows() {
        use std::time::{Duration, Instant};
        let d = Duration::from_millis(100);
        let items: Vec<(String, String)> = (0..20)
            .map(|i| (format!("n{i}"), "s".to_string()))
            .collect();
        let start = Instant::now();
        let got = probe_all(&items, Duration::from_secs(5), 4, move |_, _| {
            std::thread::sleep(d);
            true
        });
        let elapsed = start.elapsed();
        assert_eq!(got.len(), 20);
        assert!(got.iter().all(|&v| v));
        assert!(
            elapsed >= 5 * d && elapsed < 9 * d,
            "cap=4 batches 20 into 5 windows ≈5×D=500ms (not 20×D serial, not 1×D uncapped); got {elapsed:?}"
        );
    }

    // [unit->REQ-MESH-6] a probe that overruns the ceiling settles `false`
    // (its own recv_timeout default) WITHOUT dragging the batch past one
    // ceiling — one wedged dial costs one ceiling, never the batch (KH 5.3).
    #[test]
    fn probe_all_timeout_settles_false_without_stalling_batch() {
        use std::time::{Duration, Instant};
        let ceiling = Duration::from_millis(150);
        // Item 1 wedges (sleeps 10×ceiling); items 0 and 2 are instant.
        let items: Vec<(String, String)> = vec![
            ("fast0".into(), "s".into()),
            ("wedged".into(), "s".into()),
            ("fast2".into(), "s".into()),
        ];
        let start = Instant::now();
        let got = probe_all(&items, ceiling, 16, move |n, _| {
            if n == "wedged" {
                std::thread::sleep(Duration::from_millis(1500));
            }
            true
        });
        let elapsed = start.elapsed();
        assert_eq!(got, vec![true, false, true], "wedged probe reads false, fast ones true, order kept");
        assert!(
            elapsed < 4 * ceiling,
            "the wedged probe costs one ceiling, not its full 1500ms sleep; got {elapsed:?}"
        );
    }


            -1,
            "an op past the deadline reads as the timeout default"
        );
    }

    // [unit->REQ-MESH-6] the fan-out is CONCURRENT, not serial: N probes each
    // sleeping D finish in ≈ one D (plus scheduling slop), not N×D. Injected
    // deterministic sleeper — no network (the mock-clock seam the reg names).
    #[test]
    fn probe_all_runs_concurrently_in_input_order() {
        use std::time::{Duration, Instant};
        let d = Duration::from_millis(200);
        let items: Vec<(String, String)> = (0..8)
            .map(|i| (format!("node{i}"), "sub".to_string()))
            .collect();
        let start = Instant::now();
        // Result encodes the input index so we can prove order is preserved.
        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {
            std::thread::sleep(d);
            n.ends_with(|c: char| c.is_ascii_digit()) // always true here
        });
        let elapsed = start.elapsed();
        assert_eq!(got, vec![true; 8], "every probe settles, in input order");
        assert!(
            elapsed < 4 * d,
            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"
        );
    }

    // [unit->REQ-MESH-6] the in-flight cap BATCHES rather than serializing
    // fully or ignoring the bound: N=20 at cap=4, each sleeping D, runs in
    // ceil(20/4)=5 windows → ≈5×D, not 20×D (serial) and not ≈1×D (uncapped).
    #[test]
    fn probe_all_cap_batches_into_windows() {
        use std::time::{Duration, Instant};
        let d = Duration::from_millis(100);
        let items: Vec<(String, String)> = (0..20)
            .map(|i| (format!("n{i}"), "s".to_string()))
            .collect();
        let start = Instant::now();
        let got = probe_all(&items, Duration::from_secs(5), 4, move |_, _| {
            std::thread::sleep(d);
            true
        });
        let elapsed = start.elapsed();
        assert_eq!(got.len(), 20);
        assert!(got.iter().all(|&v| v));
        assert!(
            elapsed >= 5 * d && elapsed < 9 * d,
            "cap=4 batches 20 into 5 windows ≈5×D=500ms (not 20×D serial, not 1×D uncapped); got {elapsed:?}"
        );
    }

    // [unit->REQ-MESH-6] a probe that overruns the ceiling settles `false`
    // (its own recv_timeout default) WITHOUT dragging the batch past one
    // ceiling — one wedged dial costs one ceiling, never the batch (KH 5.3).
    #[test]
    fn probe_all_timeout_settles_false_without_stalling_batch() {
        use std::time::{Duration, Instant};
        let ceiling = Duration::from_millis(150);
        // Item 1 wedges (sleeps 10×ceiling); items 0 and 2 are instant.
        let items: Vec<(String, String)> = vec![
            ("fast0".into(), "s".into()),
            ("wedged".into(), "s".into()),
            ("fast2".into(), "s".into()),
        ];
        let start = Instant::now();
        let got = probe_all(&items, ceiling, 16, move |n, _| {
            if n == "wedged" {
                std::thread::sleep(Duration::from_millis(1500));
            }
            true
        });
        let elapsed = start.elapsed();
        assert_eq!(got, vec![true, false, true], "wedged probe reads false, fast ones true, order kept");
        assert!(
            elapsed < 4 * ceiling,
            "the wedged probe costs one ceiling, not its full 1500ms sleep; got {elapsed:?}"
        );
    }

+    // [unit->REQ-MESH-6] the fan-out is CONCURRENT, not serial: N probes each

+    // sleeping D finish in ≈ one D (plus scheduling slop), not N×D. Injected

+    // deterministic sleeper — no network (the mock-clock seam the reg names).

+    fn probe_all_runs_concurrently_in_input_order() {

+        use std::time::{Duration, Instant};

+        let d = Duration::from_millis(200);

+        let items: Vec<(String, String)> = (0..8)

+            .map(|i| (format!("node{i}"), "sub".to_string()))

+        // Result encodes the input index so we can prove order is preserved.

+        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {

+            n.ends_with(|c: char| c.is_ascii_digit()) // always true here

+        assert_eq!(got, vec![true; 8], "every probe settles, in input order");

+            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"

+    // [unit->REQ-MESH-6] the in-flight cap BATCHES rather than serializing

+    // fully or ignoring the bound: N=20 at cap=4, each sleeping D, runs in

+    // ceil(20/4)=5 windows → ≈5×D, not 20×D (serial) and not ≈1×D (uncapped).

+    fn probe_all_cap_batches_into_windows() {

+        let d = Duration::from_millis(100);

+        let items: Vec<(String, String)> = (0..20)

+        let got = probe_all(&items, Duration::from_secs(5), 4, move |_, _| {

+        assert!(got.iter().all(|&v| v));

+            elapsed >= 5 * d && elapsed < 9 * d,

+            "cap=4 batches 20 into 5 windows ≈5×D=500ms (not 20×D serial, not 1×D uncapped); got {elapsed:?}"

+    // [unit->REQ-MESH-6] a probe that overruns the ceiling settles `false`

+    // (its own recv_timeout default) WITHOUT dragging the batch past one

+    // ceiling — one wedged dial costs one ceiling, never the batch (KH 5.3).

+    fn probe_all_timeout_settles_false_without_stalling_batch() {

+        use std::time::{Duration, Instant};

+        let ceiling = Duration::from_millis(150);

+        // Item 1 wedges (sleeps 10×ceiling); items 0 and 2 are instant.

+        let items: Vec<(String, String)> = vec![

+            ("wedged".into(), "s".into()),

+        let got = probe_all(&items, ceiling, 16, move |n, _| {

+                std::thread::sleep(Duration::from_millis(1500));

+        assert_eq!(got, vec![true, false, true], "wedged probe reads false, fast ones true, order kept");

+            "the wedged probe costs one ceiling, not its full 1500ms sleep; got {elapsed:?}"

// [unit->REQ-SUBNET-3] label collision: two nodes sharing a hostname each

// get the key-prefix disambiguator back (the addressing layer forces it

// anyway); a unique label stays clean in the same render.


Strengthen first test to actually prove order mapping:


        let start = Instant::now();
        // Result encodes the input index so we can prove order is preserved.
        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {
            std::thread::sleep(d);
            n.ends_with(|c: char| c.is_ascii_digit()) // always true here
        });
        let elapsed = start.elapsed();
        assert_eq!(got, vec![true; 8], "every probe settles, in input order");
        assert!(
            elapsed < 4 * d,
            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"
        );

        let start = Instant::now();
        // Probe returns false only for node3, so the result vector proves the
        // index→result mapping survived the concurrent fan-out (not just timing).
        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {
            std::thread::sleep(d);
            n != "node3"
        });
        let elapsed = start.elapsed();
        let mut want = vec![true; 8];
        want[3] = false;
        assert_eq!(got, want, "results map back to input order; node3 false");
        assert!(
            elapsed < 4 * d,
            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"
        );


        let start = Instant::now();
        // Result encodes the input index so we can prove order is preserved.
        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {
            std::thread::sleep(d);
            n.ends_with(|c: char| c.is_ascii_digit()) // always true here
        });
        let elapsed = start.elapsed();
        assert_eq!(got, vec![true; 8], "every probe settles, in input order");
        assert!(
            elapsed < 4 * d,
            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"
        );

        let start = Instant::now();
        // Probe returns false only for node3, so the result vector proves the
        // index→result mapping survived the concurrent fan-out (not just timing).
        let got = probe_all(&items, Duration::from_secs(5), 16, move |n, _| {
            std::thread::sleep(d);
            n != "node3"
        });
        let elapsed = start.elapsed();
        let mut want = vec![true; 8];
        want[3] = false;
        assert_eq!(got, want, "results map back to input order; node3 false");
        assert!(
            elapsed < 4 * d,
            "8 concurrent probes finish well under serial 8×D=1600ms; got {elapsed:?}"
        );

-        // Result encodes the input index so we can prove order is preserved.

+        // Probe returns false only for node3, so the result vector proves the

+        // index→result mapping survived the concurrent fan-out (not just timing).

-            n.ends_with(|c: char| c.is_ascii_digit()) // always true here

-        assert_eq!(got, vec![true; 8], "every probe settles, in input order");

+        assert_eq!(got, want, "results map back to input order; node3 false");


Now activate REQ-MESH-6 in the registry:


771	required_stages = ["impl", "unit"]  # Mesh-D6 activated: impl = TrustStore + peers.json + every call site DELETED (spt-store mod, perch::trust_file, pairing wire trust write, peerloop push, CLI status/list/prune/leave, xtask); the serve/inbound gates authorize on roster membership (propagate serve_update → RosterStore::is_member_any; dispatch caller); warn-on-change re-homed onto machine_id as a non-blocking RekeyNotice at the repair_evict_superseded event. unit = roster::is_member_any spans subnets + honors tombstones; repair_evict emits the machine_id-anchored rekey notice without blocking, and absent machine_id raises no false notice; the deletion is compile-enforced (no TrustStore symbol remains).
772	[[requirements]]
773	id = "REQ-MESH-6"
774	title = "Concurrent liveness probes: `spt subnet status --nodes` fans out its offline/serve-probes (REQ-SUBNET-5) CONCURRENTLY — total wall-time bounded by the single-probe ceiling (~3s), never k×ceiling. The mesh makes a node see ALL members (many possibly offline), so a serial probe loop would be offline_count×3s. (Planning verifies the current REQ-SUBNET-5 probe loop's behavior and fixes it if serial.)"
775	required_stages = []  # activate at mesh execution. impl = join_all/futures fan-out of the serve-probes under one bound, not a sequential await loop. unit = N offline nodes complete within ~one ceiling, not N×ceiling (deterministic mock-clock seam).
776

required_stages = ["impl", "unit"]  # Mesh-D6 activated: impl = TrustStore + peers.json + every call site DELETED (spt-store mod, perch::trust_file, pairing wire trust write, peerloop push, CLI status/list/prune/leave, xtask); the serve/inbound gates authorize on roster membership (propagate serve_update → RosterStore::is_member_any; dispatch caller); warn-on-change re-homed onto machine_id as a non-blocking RekeyNotice at the repair_evict_superseded event. unit = roster::is_member_any spans subnets + honors tombstones; repair_evict emits the machine_id-anchored rekey notice without blocking, and absent machine_id raises no false notice; the deletion is compile-enforced (no TrustStore symbol remains).
[[requirements]]
id = "REQ-MESH-6"
title = "Concurrent liveness probes: `spt subnet status --nodes` fans out its offline/serve-probes (REQ-SUBNET-5) CONCURRENTLY — total wall-time bounded by the single-probe ceiling (~3s), never k×ceiling. The mesh makes a node see ALL members (many possibly offline), so a serial probe loop would be offline_count×3s. (Planning verifies the current REQ-SUBNET-5 probe loop's behavior and fixes it if serial.)"
required_stages = []  # activate at mesh execution. impl = join_all/futures fan-out of the serve-probes under one bound, not a sequential await loop. unit = N offline nodes complete within ~one ceiling, not N×ceiling (deterministic mock-clock seam).


required_stages = []  # activate at mesh execution. impl = join_all/futures fan-out of the serve-probes under one bound, not a sequential await loop. unit = N offline nodes complete within ~one ceiling, not N×ceiling (deterministic mock-clock seam).

required_stages = ["impl", "unit"]  # Mesh-D8 activated: impl = `probe_all(items, ceiling, max_inflight, probe)` fans the --nodes serve-probes out across ALL subnets in one bounded batch (thread-per-probe under run_bounded, in-flight cap MAX_INFLIGHT=16, results stitched back in row order), replacing the serial `.map(probe_node)` loop; each probe stays individually ceiling-bounded (KH 5.3) and the over-cap path logs (no silent truncation). Threads + run_bounded, NOT tokio. unit = injected deterministic sleeper proves N probes finish in ≈one ceiling not N×ceiling AND map back in input order; a cap unit proves window-batching (20 at cap 4 ≈ 5 windows); a timeout unit proves one wedged probe settles false in one ceiling without dragging the batch.


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 = "Concurrent liveness probes: `spt subnet status --nodes` fans out its offline/serve-probes (REQ-SUBNET-5) CONCURRENTLY — total wall-time bounded by the single-probe ceiling (~3s), never k×ceiling. The mesh makes a node see ALL members (many possibly offline), so a serial probe loop would be offline_count×3s. (Planning verifies the current REQ-SUBNET-5 probe loop's behavior and fixes it if serial.)"

-required_stages = []  # activate at mesh execution. impl = join_all/futures fan-out of the serve-probes under one bound, not a sequential await loop. unit = N offline nodes complete within ~one ceiling, not N×ceiling (deterministic mock-clock seam).

+required_stages = ["impl", "unit"]  # Mesh-D8 activated: impl = `probe_all(items, ceiling, max_inflight, probe)` fans the --nodes serve-probes out across ALL subnets in one bounded batch (thread-per-probe under run_bounded, in-flight cap MAX_INFLIGHT=16, results stitched back in row order), replacing the serial `.map(probe_node)` loop; each probe stays individually ceiling-bounded (KH 5.3) and the over-cap path logs (no silent truncation). Threads + run_bounded, NOT tokio. unit = injected deterministic sleeper proves N probes finish in ≈one ceiling not N×ceiling AND map back in input order; a cap unit proves window-batching (20 at cap 4 ≈ 5 windows); a timeout unit proves one wedged probe settles false in one ceiling without dragging the batch.


Now build + test + checks. Run in background (owl reachability):


Bash

cargo test -p spt --lib probe_all 2>&1 | tail -30

Run probe_all unit tests


Command running in background with ID: bpq8lhp1e. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bpq8lhp1e.output. You will be notified when it completes. To check interim output, use Read on that file path.


<task-notification>
<task-id>bpq8lhp1e</task-id>
<tool-use-id>toolu_01FC6BxPPGe4TEyzRx87u6k9</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bpq8lhp1e.output</output-file>
<status>completed</status>
<summary>Background command "Run probe_all unit tests" completed (exit code 0)</summary>
</task-notification>


noop


waiting


Prompt:
<task-notification>
<task-id>bpq8lhp1e</task-id>
<tool-use-id>toolu_01FC6BxPPGe4TEyzRx87u6k9</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bpq8lhp1e.output</output-file>
<status>completed</status>
<summary>Background command "Run probe_all unit tests" completed (exit code 0)</summary>
</task-notification>


1	error: no library targets found in package `spt`
2


Binary crate. Run via bin target:


cargo test -p spt --bin spt probe_all 2>&1 | tail -30

Run probe_all tests via bin


Command running in background with ID: bbqb3mnqs. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bbqb3mnqs.output. You will be notified when it completes. To check interim output, use Read on that file path.


grep -rn "fn main" crates/spt/src/main.rs 2>/dev/null | head -1; ls crates/spt/src/*.rs | head

Check bin target name


19:fn main() {
crates/spt/src/cli.rs
crates/spt/src/elevation.rs
crates/spt/src/main.rs
crates/spt/src/roster.rs
crates/spt/src/testutil.rs
crates/spt/src/wansend.rs


<system-reminder>Warning: the file exists but is shorter than the provided offset (1). The file has 1 lines.</system-reminder>


<task-notification>
<task-id>bbqb3mnqs</task-id>
<tool-use-id>toolu_01DyvsNLxqwMmnaqYiJcVHMS</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bbqb3mnqs.output</output-file>
<status>completed</status>
<summary>Background command "Run probe_all tests via bin" completed (exit code 0)</summary>
</task-notification>


Still compiling. Wait.


wait for build


<tool_use_error>Blocked: sleep 30 followed by: echo done. To wait for a condition, use Monitor with an until-loop (e.g. `until <check>; do sleep 2; done`). To wait for a command you started, use run_in_background: true. Do not chain shorter sleeps to work around this block.</tool_use_error>

Error: Blocked: sleep 30 followed by: echo done. To wait for a condition, use Monitor with an until-loop (e.g. `until <check>; do sleep 2; done`). To wait for a command you started, use run_in_background: true. Do not chain shorter sleeps to work around this block.


Prompt:
<task-notification>
<task-id>bbqb3mnqs</task-id>
<tool-use-id>toolu_01DyvsNLxqwMmnaqYiJcVHMS</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bbqb3mnqs.output</output-file>
<status>completed</status>
<summary>Background command "Run probe_all tests via bin" completed (exit code 0)</summary>
</task-notification>


1	   Compiling spt v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
2	warning: function `probe_node` is never used
3	    --> crates\spt\src\cli.rs:2682:4
4	     |
5	2682 | fn probe_node(node_hex: &str, subnet: &str) -> bool {
6	     |    ^^^^^^^^^^
7	     |
8	     = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
9
10	warning: `spt` (bin "spt" test) generated 1 warning
11	    Finished `test` profile [unoptimized + debuginfo] target(s) in 5.18s
12	     Running unittests src\main.rs (target\debug\deps\spt-27119dc630f145a2.exe)
13
14	running 3 tests
15	test cli::tests::probe_all_timeout_settles_false_without_stalling_batch ... ok
16	test cli::tests::probe_all_runs_concurrently_in_input_order ... ok
17	test cli::tests::probe_all_cap_batches_into_windows ... ok
18
19	test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 102 filtered out; finished in 0.50s
20
21

   Compiling spt v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
warning: function `probe_node` is never used
    --> crates\spt\src\cli.rs:2682:4
     |
2682 | fn probe_node(node_hex: &str, subnet: &str) -> bool {
     |    ^^^^^^^^^^
     |
     = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default

warning: `spt` (bin "spt" test) generated 1 warning
    Finished `test` profile [unoptimized + debuginfo] target(s) in 5.18s
     Running unittests src\main.rs (target\debug\deps\spt-27119dc630f145a2.exe)

running 3 tests
test cli::tests::probe_all_timeout_settles_false_without_stalling_batch ... ok
test cli::tests::probe_all_runs_concurrently_in_input_order ... ok
test cli::tests::probe_all_cap_batches_into_windows ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 102 filtered out; finished in 0.50s


3 green. But `probe_node` now dead code — carried REQ-SUBNET-1/5 tags. Check whether those reqs have other evidence before deciding delete vs keep.


git grep -n "impl->REQ-SUBNET-1\]\|impl->REQ-SUBNET-5\]\|unit->REQ-SUBNET-5\]\|unit->REQ-SUBNET-1\]" -- '*.rs' '*.md'

All SUBNET-1/5 impl+unit evidence tags


crates/spt-daemon/src/config.rs:341:    // [unit->REQ-SUBNET-5] the startup serve-state default is config-driven:
crates/spt-daemon/src/daemon.rs:126:        // [impl->REQ-SUBNET-5]
crates/spt-daemon/src/dispatch.rs:413:            // [impl->REQ-SUBNET-5]
crates/spt-daemon/src/pairhost.rs:74:    // [impl->REQ-SUBNET-5]
crates/spt-daemon/src/peerloop.rs:357:        // [impl->REQ-SUBNET-5]
crates/spt-daemon/src/registryhost.rs:265:        // [impl->REQ-SUBNET-1]
crates/spt-daemon/src/registryhost.rs:571:    // [impl->REQ-SUBNET-1]
crates/spt-daemon/src/registryhost.rs:1446:    // [unit->REQ-SUBNET-1] the gossip-recency half of hybrid liveness: an
crates/spt-daemon/src/serveprobe.rs:31:// [impl->REQ-SUBNET-5]
crates/spt-daemon/src/serveprobe.rs:50:// [impl->REQ-SUBNET-5]
crates/spt-daemon/src/serveprobe.rs:69:// [impl->REQ-SUBNET-5]
crates/spt-daemon/src/serveprobe.rs:113:// [impl->REQ-SUBNET-5]
crates/spt-daemon/src/serveprobe.rs:151:    // [unit->REQ-SUBNET-5] the serve-state predicate: a held + attached subnet
crates/spt-net/src/net/serveprobe.rs:25:// [impl->REQ-SUBNET-5]
crates/spt-net/src/net/serveprobe.rs:34:// [impl->REQ-SUBNET-5]
crates/spt-net/src/net/serveprobe.rs:61:    // [unit->REQ-SUBNET-5] both record kinds round-trip through the NDJSON
crates/spt-store/src/attachment.rs:17:// [impl->REQ-SUBNET-5]
crates/spt-store/src/attachment.rs:111:    // [unit->REQ-SUBNET-5] attached is the default: an absent file detaches
crates/spt-store/src/attachment.rs:138:    // [unit->REQ-SUBNET-5] a corrupt state file degrades to all-attached —
crates/spt-store/src/attachment.rs:148:    // [unit->REQ-SUBNET-5] the boot reset seeds live state from the config
crates/spt/src/cli.rs:2068:// [impl->REQ-SUBNET-1] [impl->REQ-SUBNET-4]
crates/spt/src/cli.rs:2233:// [impl->REQ-PAIR-3] [impl->REQ-PAIR-6] [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:2252:// [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:2313:// [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:2355:// [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:2528:// [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:2598:// [impl->REQ-SUBNET-1] [impl->REQ-SUBNET-3]
crates/spt/src/cli.rs:2673:// [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:2674:// [impl->REQ-SUBNET-5]
crates/spt/src/cli.rs:2835:// [impl->REQ-SUBNET-1]
crates/spt/src/cli.rs:3322:// [impl->REQ-SUBNET-5]
crates/spt/src/cli.rs:6520:    // [unit->REQ-SUBNET-1] [unit->REQ-PAIR-3] the subnet arg shapes parse:
crates/spt/src/cli.rs:6577:        // [unit->REQ-SUBNET-5] attach/detach: positional name + --save
crates/spt/src/cli.rs:6690:    // [unit->REQ-SUBNET-1] the `pair` namespace is deleted outright (no shim).
crates/spt/src/cli.rs:6697:    // [unit->REQ-SUBNET-1] elevated create prints the full joining material —
crates/spt/src/cli.rs:6750:    // [unit->REQ-SUBNET-1] [unit->REQ-SUBNET-4] an unelevated create refuses
crates/spt/src/cli.rs:6767:    // [unit->REQ-SUBNET-1] creating an existing name is a usage error (the
crates/spt/src/cli.rs:6781:    // [unit->REQ-SUBNET-1] [unit->REQ-SUBNET-8] the status view: zero
crates/spt/src/cli.rs:6879:    // [unit->REQ-SUBNET-1] [unit->REQ-SUBNET-3] the --nodes hybrid liveness
crates/spt/src/cli.rs:7029:    // [unit->REQ-SUBNET-1] the bounded probe seam: a fast op returns its value;
crates/spt/src/wansend.rs:418:// [impl->REQ-SUBNET-1]
crates/spt/src/wansend.rs:419:// [impl->REQ-SUBNET-5]


REQ-SUBNET-1/5 amply covered elsewhere (`wansend.rs:418-419` on the real `probe_node_serving`, still called). `probe_node` is now a dead wrapper — delete it. Read current region:


2663	/// Subnet-scoped liveness probe for one node, BOUNDED. The `--nodes` view
2664	/// dials this synchronously per silent node; an id-only dial to a dead peer
2665	/// otherwise runs the full iroh discovery+connect timeout (~30s, observed live
2666	/// on the M8 acceptance rig). A probe that does not complete within
2667	/// `PROBE_TIMEOUT` reads as offline — a node that cannot finish a handshake in
2668	/// a couple seconds is offline for liveness purposes. The probe is now
2669	/// subnet-scoped (REQ-SUBNET-5): it dials (proves reachable) THEN asks the
2670	/// peer "serving `subnet`?", so a detached-but-alive peer reads offline for
2671	/// that subnet (was the criterion-5 detach-liveness bug — a raw dial proved
2672	/// only the box was up).
2673	// [impl->REQ-SUBNET-1]
2674	// [impl->REQ-SUBNET-5]
2675	const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
2676	/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
2677	/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
2678	/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
2679	/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
2680	const MAX_INFLIGHT: usize = 16;
2681
2682	fn probe_node(node_hex: &str, subnet: &str) -> bool {
2683	    let hex = node_hex.to_string();
2684	    let sub = subnet.to_string();

/// Subnet-scoped liveness probe for one node, BOUNDED. The `--nodes` view
/// dials this synchronously per silent node; an id-only dial to a dead peer
/// otherwise runs the full iroh discovery+connect timeout (~30s, observed live
/// on the M8 acceptance rig). A probe that does not complete within
/// `PROBE_TIMEOUT` reads as offline — a node that cannot finish a handshake in
/// a couple seconds is offline for liveness purposes. The probe is now
/// subnet-scoped (REQ-SUBNET-5): it dials (proves reachable) THEN asks the
/// peer "serving `subnet`?", so a detached-but-alive peer reads offline for
/// that subnet (was the criterion-5 detach-liveness bug — a raw dial proved
/// only the box was up).
// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

fn probe_node(node_hex: &str, subnet: &str) -> bool {
    let hex = node_hex.to_string();
    let sub = subnet.to_string();


Edit

/// Subnet-scoped liveness probe for one node, BOUNDED. The `--nodes` view
/// dials this synchronously per silent node; an id-only dial to a dead peer
/// otherwise runs the full iroh discovery+connect timeout (~30s, observed live
/// on the M8 acceptance rig). A probe that does not complete within
/// `PROBE_TIMEOUT` reads as offline — a node that cannot finish a handshake in
/// a couple seconds is offline for liveness purposes. The probe is now
/// subnet-scoped (REQ-SUBNET-5): it dials (proves reachable) THEN asks the
/// peer "serving `subnet`?", so a detached-but-alive peer reads offline for
/// that subnet (was the criterion-5 detach-liveness bug — a raw dial proved
/// only the box was up).
// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

fn probe_node(node_hex: &str, subnet: &str) -> bool {
    let hex = node_hex.to_string();
    let sub = subnet.to_string();
    run_bounded(PROBE_TIMEOUT, false, move || {
        crate::wansend::probe_node_serving(&hex, &sub)
    })
}

/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input

/// Per-node probe ceiling. An id-only dial to a dead peer otherwise runs the
/// full iroh discovery+connect timeout (~30s, observed live on the M8
/// acceptance rig); a node that can't finish a subnet-scoped handshake in a
/// couple seconds reads offline for liveness purposes. The probe itself
/// (`probe_node_serving`, wansend.rs) is subnet-scoped per REQ-SUBNET-5: dial
/// (proves reachable) THEN ask "serving `subnet`?", so a detached-but-alive
/// peer reads offline for that subnet.
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input


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

/// Subnet-scoped liveness probe for one node, BOUNDED. The `--nodes` view
/// dials this synchronously per silent node; an id-only dial to a dead peer
/// otherwise runs the full iroh discovery+connect timeout (~30s, observed live
/// on the M8 acceptance rig). A probe that does not complete within
/// `PROBE_TIMEOUT` reads as offline — a node that cannot finish a handshake in
/// a couple seconds is offline for liveness purposes. The probe is now
/// subnet-scoped (REQ-SUBNET-5): it dials (proves reachable) THEN asks the
/// peer "serving `subnet`?", so a detached-but-alive peer reads offline for
/// that subnet (was the criterion-5 detach-liveness bug — a raw dial proved
/// only the box was up).
// [impl->REQ-SUBNET-1]
// [impl->REQ-SUBNET-5]
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

fn probe_node(node_hex: &str, subnet: &str) -> bool {
    let hex = node_hex.to_string();
    let sub = subnet.to_string();
    run_bounded(PROBE_TIMEOUT, false, move || {
        crate::wansend::probe_node_serving(&hex, &sub)
    })
}

/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input

/// Per-node probe ceiling. An id-only dial to a dead peer otherwise runs the
/// full iroh discovery+connect timeout (~30s, observed live on the M8
/// acceptance rig); a node that can't finish a subnet-scoped handshake in a
/// couple seconds reads offline for liveness purposes. The probe itself
/// (`probe_node_serving`, wansend.rs) is subnet-scoped per REQ-SUBNET-5: dial
/// (proves reachable) THEN ask "serving `subnet`?", so a detached-but-alive
/// peer reads offline for that subnet.
const PROBE_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(2500);
/// In-flight cap for the concurrent `--nodes` probe fan-out (REQ-MESH-6): a
/// small fixed pool so a 200-member subnet can't open 200 simultaneous broker
/// IPC conns + dials at once. `k ≤ cap` ⇒ one ceiling; `k > cap` ⇒
/// `ceil(k/cap)` ceilings (logged — no silent truncation of the wait).
const MAX_INFLIGHT: usize = 16;

/// Run every `(node, subnet)` probe CONCURRENTLY; collect results in input

-/// Subnet-scoped liveness probe for one node, BOUNDED. The `--nodes` view

-/// dials this synchronously per silent node; an id-only dial to a dead peer

-/// otherwise runs the full iroh discovery+connect timeout (~30s, observed live

-/// on the M8 acceptance rig). A probe that does not complete within

-/// `PROBE_TIMEOUT` reads as offline — a node that cannot finish a handshake in

-/// a couple seconds is offline for liveness purposes. The probe is now

-/// subnet-scoped (REQ-SUBNET-5): it dials (proves reachable) THEN asks the

-/// peer "serving `subnet`?", so a detached-but-alive peer reads offline for

-/// that subnet (was the criterion-5 detach-liveness bug — a raw dial proved

+/// Per-node probe ceiling. An id-only dial to a dead peer otherwise runs the

+/// full iroh discovery+connect timeout (~30s, observed live on the M8

+/// acceptance rig); a node that can't finish a subnet-scoped handshake in a

+/// couple seconds reads offline for liveness purposes. The probe itself

+/// (`probe_node_serving`, wansend.rs) is subnet-scoped per REQ-SUBNET-5: dial

+/// (proves reachable) THEN ask "serving `subnet`?", so a detached-but-alive

+/// peer reads offline for that subnet.

-fn probe_node(node_hex: &str, subnet: &str) -> bool {

-    run_bounded(PROBE_TIMEOUT, false, move || {

-        crate::wansend::probe_node_serving(&hex, &sub)

/// order. Wall-time ≈ ONE `ceiling` when `items.len() <= max_inflight`,

/// else `ceil(k / max_inflight)` ceilings. The mesh widen (D6) makes a node


Now full gate run: build, full test, clippy, no-default-features, traceable-reqs, docs-drift.


Bash

cargo test -p spt --bin spt 2>&1 | tail -20

Full spt bin test suite


Command running in background with ID: bjgzwdnv5. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bjgzwdnv5.output. You will be notified when it completes. To check interim output, use Read on that file path.


cargo clippy -p spt --bin spt --all-targets 2>&1 | tail -15

Clippy spt


Command running in background with ID: bnmyqecyc. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bnmyqecyc.output. You will be notified when it completes. To check interim output, use Read on that file path.


<task-notification>
<task-id>bnmyqecyc</task-id>
<tool-use-id>toolu_01SWbrC2amBJjYwpch3iAZF8</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bnmyqecyc.output</output-file>
<status>completed</status>
<summary>Background command "Clippy spt" completed (exit code 0)</summary>
</task-notification>


traceable-reqs check 2>&1 | tail -25; echo "EXIT=$?"

traceable-reqs check


Command running in background with ID: bj1cmtte8. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bj1cmtte8.output. You will be notified when it completes. To check interim output, use Read on that file path.


Prompt:
<task-notification>
<task-id>bnmyqecyc</task-id>
<tool-use-id>toolu_01SWbrC2amBJjYwpch3iAZF8</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bnmyqecyc.output</output-file>
<status>completed</status>
<summary>Background command "Clippy spt" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bj1cmtte8</task-id>
<tool-use-id>toolu_017p1ZGqo6BZGrvpxE1HHnHm</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bj1cmtte8.output</output-file>
<status>completed</status>
<summary>Background command "traceable-reqs check" completed (exit code 0)</summary>
</task-notification>


1	    Blocking waiting for file lock on build directory
2	    Checking spt v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
3	    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.75s
4

    Blocking waiting for file lock on build directory
    Checking spt v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.75s


1	       Trust lifecycle verbs, elevation-gated: spt subnet leave <NAME> (membership exit) and spt subnet prune <node> (removes a dead identity's trust + registry rows, killing its dead dials; trust mutation = security surface, REQ-PAIR-6 gate machinery) (M8 decisions 6-7)
2	  [OK] REQ-SUBNET-7  required: [impl, unit]  stages: -doc +impl +unit -int
3	       Per-machine re-pair trust overwrite: registry rows carry a hashed stable machine identifier (OS machine id /etc/machine-id|MachineGuid, domain-separated SHA-256 before gossip, spt-minted persisted UUID fallback; additive serde-default field — old rows parse clean); a COMPLETED pairing ceremony presenting the same node label AND machine id as an existing trusted row evicts the superseded identity's trust + registry rows on the seed-holder and replicates the eviction; a gossiped claim alone never evicts trust (M8 decisions 13, 22)
4	  [OK] REQ-SUBNET-8  required: [impl, unit]  stages: -doc +impl +unit -int
5	       Status render honesty: zero-subnet text is daemon-aware ('No subnets registered — this node is standalone.' + daemon-running-dependent blurb, never implying messaging works while the daemon is down); hint footer prints on bare spt subnet only (status drops it); a stalled pump is surfaced in subnet status, never rendered implied-healthy (M8 decisions 11-12, 23)
6	  [OK] REQ-TERM-1  required: [impl, unit]  stages: -doc +impl +unit -int
7	       Process-supervisor terminal wrapper hosting broker PTYs
8	  [OK] REQ-TERM-2  required: [impl, unit]  stages: -doc +impl +unit -int
9	       session-surface abstraction; send-keys + send-line injection
10	  [OK] REQ-TERM-3  required: [impl, unit]  stages: -doc +impl +unit -int
11	       Byte-stream remote terminal streaming for v1
12	  [OK] REQ-TERM-4  required: [impl, unit, int]  stages: +doc +impl +unit +int
13	       Live activity buffer (PTY digest): adapter-supplied patterns over broker PTY, spt digest pull + delta-stream, opt-in Path-B log
14	  [OK] REQ-UPD-1  required: [impl, unit, int]  stages: -doc +impl +unit +int
15	       Peer-propagated update over P2P
16	  [OK] REQ-UPD-2  required: [impl, unit]  stages: -doc +impl +unit -int
17	       All binaries signature-verified before handoff
18	  [OK] REQ-UPD-3  required: [impl, unit, int]  stages: -doc +impl +unit +int
19	       No endpoint process terminates/suspends during self-update
20	  [OK] REQ-UPD-4  required: [impl, unit]  stages: -doc +impl +unit -int
21	       Update gated on user confirmation by default; opt-in full-auto
22	  [OK] REQ-UPD-5  required: [impl, unit]  stages: -doc +impl +unit -int
23	       spt-core ripple-updates registered adapters
24	  [OK] REQ-UPD-6  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
25	       Platform-targeted update sets and debug rollout: signed multi-platform update metadata, recipient platform selection, channel-scoped monotonic counters, debug-channel opt-in via release-key overlay, local staging plus pull-based peer propagation, and maintainer-only convergence tooling (ADR-0016)
26	EXIT=0
27

       Trust lifecycle verbs, elevation-gated: spt subnet leave <NAME> (membership exit) and spt subnet prune <node> (removes a dead identity's trust + registry rows, killing its dead dials; trust mutation = security surface, REQ-PAIR-6 gate machinery) (M8 decisions 6-7)
  [OK] REQ-SUBNET-7  required: [impl, unit]  stages: -doc +impl +unit -int
       Per-machine re-pair trust overwrite: registry rows carry a hashed stable machine identifier (OS machine id /etc/machine-id|MachineGuid, domain-separated SHA-256 before gossip, spt-minted persisted UUID fallback; additive serde-default field — old rows parse clean); a COMPLETED pairing ceremony presenting the same node label AND machine id as an existing trusted row evicts the superseded identity's trust + registry rows on the seed-holder and replicates the eviction; a gossiped claim alone never evicts trust (M8 decisions 13, 22)
  [OK] REQ-SUBNET-8  required: [impl, unit]  stages: -doc +impl +unit -int
       Status render honesty: zero-subnet text is daemon-aware ('No subnets registered — this node is standalone.' + daemon-running-dependent blurb, never implying messaging works while the daemon is down); hint footer prints on bare spt subnet only (status drops it); a stalled pump is surfaced in subnet status, never rendered implied-healthy (M8 decisions 11-12, 23)
  [OK] REQ-TERM-1  required: [impl, unit]  stages: -doc +impl +unit -int
       Process-supervisor terminal wrapper hosting broker PTYs
  [OK] REQ-TERM-2  required: [impl, unit]  stages: -doc +impl +unit -int
       session-surface abstraction; send-keys + send-line injection
  [OK] REQ-TERM-3  required: [impl, unit]  stages: -doc +impl +unit -int
       Byte-stream remote terminal streaming for v1
  [OK] REQ-TERM-4  required: [impl, unit, int]  stages: +doc +impl +unit +int
       Live activity buffer (PTY digest): adapter-supplied patterns over broker PTY, spt digest pull + delta-stream, opt-in Path-B log
  [OK] REQ-UPD-1  required: [impl, unit, int]  stages: -doc +impl +unit +int
       Peer-propagated update over P2P
  [OK] REQ-UPD-2  required: [impl, unit]  stages: -doc +impl +unit -int
       All binaries signature-verified before handoff
  [OK] REQ-UPD-3  required: [impl, unit, int]  stages: -doc +impl +unit +int
       No endpoint process terminates/suspends during self-update
  [OK] REQ-UPD-4  required: [impl, unit]  stages: -doc +impl +unit -int
       Update gated on user confirmation by default; opt-in full-auto
  [OK] REQ-UPD-5  required: [impl, unit]  stages: -doc +impl +unit -int
       spt-core ripple-updates registered adapters
  [OK] REQ-UPD-6  required: [doc, impl, unit, int]  stages: +doc +impl +unit +int
       Platform-targeted update sets and debug rollout: signed multi-platform update metadata, recipient platform selection, channel-scoped monotonic counters, debug-channel opt-in via release-key overlay, local staging plus pull-based peer propagation, and maintainer-only convergence tooling (ADR-0016)
EXIT=0


Prompt:
<task-notification>
<task-id>bj1cmtte8</task-id>
<tool-use-id>toolu_017p1ZGqo6BZGrvpxE1HHnHm</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bj1cmtte8.output</output-file>
<status>completed</status>
<summary>Background command "traceable-reqs check" completed (exit code 0)</summary>
</task-notification>


Clippy clean, traceable-reqs EXIT=0. Check full test result:


<system-reminder>Warning: the file exists but is shorter than the provided offset (1). The file has 1 lines.</system-reminder>


Full test still running (build lock). Kick off no-default-features + docs-drift while waiting:


cargo build --no-default-features 2>&1 | tail -8; echo "NDF_EXIT=$?"

no-default-features build


Command running in background with ID: bvq2xd7np. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bvq2xd7np.output. You will be notified when it completes. To check interim output, use Read on that file path.


<task-notification>
<task-id>bvq2xd7np</task-id>
<tool-use-id>toolu_01WqbqDVxKWi2nZb1H58ym3C</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bvq2xd7np.output</output-file>
<status>completed</status>
<summary>Background command "no-default-features build" completed (exit code 0)</summary>
</task-notification>


grep -rn "xtask gen\|docs-drift\|reference.md\|gen-docs\|verify" xtask/src/main.rs 2>/dev/null | head; ls xtask/src 2>/dev/null

Find docs-gen xtask entry


Exit code 2


Prompt:
<task-notification>
<task-id>bvq2xd7np</task-id>
<tool-use-id>toolu_01WqbqDVxKWi2nZb1H58ym3C</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bvq2xd7np.output</output-file>
<status>completed</status>
<summary>Background command "no-default-features build" completed (exit code 0)</summary>
</task-notification>


<task-notification>
<task-id>bjgzwdnv5</task-id>
<tool-use-id>toolu_01TLvEjvarwbn3SbjPHLhZXg</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bjgzwdnv5.output</output-file>
<status>completed</status>
<summary>Background command "Full spt bin test suite" completed (exit code 0)</summary>
</task-notification>


grep -rn "gen\|reference" xtask/Cargo.toml 2>/dev/null; find . -maxdepth 2 -name "*.rs" -path "*xtask*" 2>/dev/null; grep -rn "subcommand\|\"gen\"\|reference.md" xtask/ 2>/dev/null | head

Locate xtask layout


(Bash completed with no output)


Prompt:
<task-notification>
<task-id>bjgzwdnv5</task-id>
<tool-use-id>toolu_01TLvEjvarwbn3SbjPHLhZXg</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bjgzwdnv5.output</output-file>
<status>completed</status>
<summary>Background command "Full spt bin test suite" completed (exit code 0)</summary>
</task-notification>


1	test cli::tests::subnet_arg_shapes_parse ... ok
2	test wansend::tests::load_snapshots_degrades_on_junk ... ok
3	test api::worker::tests::worker_poll_drains_spool ... ok
4	test api::worker::tests::worker_poll_holds_deferred_while_resting ... ok
5	test api::worker::tests::worker_start_nests_under_parent ... ok
6	test cli::tests::probe_all_cap_batches_into_windows ... ok
7	test cli::tests::fork_forks_homes_and_deletes_exactly_the_source ... ok
8	test cli::tests::owner_shutdown_gated_by_can_shutdown_grant ... ok
9	test cli::tests::shell_channels_relay_sensory_and_text_file ... ok
10	test cli::tests::shell_owner_exclusivity_negatives ... ok
11	test cli::tests::shell_relink_relaunches_offline_instances_only ... ok
12	test cli::tests::shell_spawn_approval_floor_gates ... ok
13	test cli::tests::shell_spawn_cap_and_over_cap_gates ... ok
14	test cli::tests::shell_spawn_gates_on_the_registered_set ... ok
15	test cli::tests::shutdown_soft_stops_and_suspends ... ok
16	test wansend::tests::remote_rest_suspends_and_wakes_with_the_deferred_gate ... ok
17	test wansend::tests::wan_send_ships_to_the_resolved_node ... ok
18
19	test result: ok. 105 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 28.78s
20
21

test cli::tests::subnet_arg_shapes_parse ... ok
test wansend::tests::load_snapshots_degrades_on_junk ... ok
test api::worker::tests::worker_poll_drains_spool ... ok
test api::worker::tests::worker_poll_holds_deferred_while_resting ... ok
test api::worker::tests::worker_start_nests_under_parent ... ok
test cli::tests::probe_all_cap_batches_into_windows ... ok
test cli::tests::fork_forks_homes_and_deletes_exactly_the_source ... ok
test cli::tests::owner_shutdown_gated_by_can_shutdown_grant ... ok
test cli::tests::shell_channels_relay_sensory_and_text_file ... ok
test cli::tests::shell_owner_exclusivity_negatives ... ok
test cli::tests::shell_relink_relaunches_offline_instances_only ... ok
test cli::tests::shell_spawn_approval_floor_gates ... ok
test cli::tests::shell_spawn_cap_and_over_cap_gates ... ok
test cli::tests::shell_spawn_gates_on_the_registered_set ... ok
test cli::tests::shutdown_soft_stops_and_suspends ... ok
test wansend::tests::remote_rest_suspends_and_wakes_with_the_deferred_gate ... ok
test wansend::tests::wan_send_ships_to_the_resolved_node ... ok

test result: ok. 105 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 28.78s


git grep -n "reference.md\|gen" xtask.toml Justfile justfile Makefile .github/workflows/*.yml 2>/dev/null | grep -i "gen\|reference" | head; echo "---"; ls xtask 2>/dev/null; git grep -rln "fn main" -- 'xtask*' 2>/dev/null

Find doc-gen invocation


105/105 pass. Find docs-gen mechanism (commit `4c583f7` regenerates reference.md):


git show --stat 4c583f7 2>&1 | head -20; echo "===WF==="; git grep -rln "reference.md\|gen-reference\|cli reference" -- '*.yml' '*.yaml' '*.rs' '*.toml' 2>/dev/null | head

Inspect reference.md regen commit + generator


commit 4c583f78fc9810fa1a5bd4d1a9189d7acead4480
Author: Reavo End <decidel@gmail.com>
Date:   Mon Jun 8 16:31:26 2026 -0700

    docs(cli): regenerate reference.md — prune→roster wording + daemon start alias

    The Mesh-D6 CLI repoint changed `spt subnet prune`'s --help (roster tombstone,
    not trust rows); also picks up the earlier `daemon run` `start` alias that was
    never regenerated. Closes the CI docs-drift gate (`xtask check`).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

 docs-site/src/cli/reference.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
===WF===
crates/xtask/src/main.rs


grep -n "fn main\|\"check\"\|\"gen\"\|reference\|=> " crates/xtask/src/main.rs | head -30

xtask subcommands


4://! - `gen` — regenerate the checked-in generated docs (CLI reference).
5://! - `check` — drift gate: regenerate + diff the CLI reference, and
29:fn main() {
33:        "gen" => gen(false),
34:        "check" => {
39:        "site" => {
43:        "release-keygen" => release_keygen(&args[1..]),
44:        "release-sign" => release_sign(&args[1..]),
45:        "release-publish" => release_publish(&args[1..]),
46:        "release-verify" => release_verify(&args[1..]),
47:        "debug-keygen" => debug_keygen(&args[1..]),
48:        "debug-pin" => debug_pin(&args[1..]),
49:        "debug-rollout" => debug_rollout(&args[1..]),
50:        "debug-converge" => debug_converge(&args[1..]),
51:        _ => {
64:/// reference platform-dependent).
110:/// The generated CLI reference: every command + nested subcommand's help,
112:/// reference IS the binary's own words — it cannot drift (REQ-DOCS-5).
114:fn cli_reference(bin: &Path) -> String {
116:        "# CLI reference\n\n\
163:    let generated = cli_reference(&bin);
164:    let path = root.join("docs-site/src/cli/reference.md");
167:            .expect("checked-in cli/reference.md (run `cargo run -p xtask -- gen`)")
171:                "xtask check: docs-site/src/cli/reference.md drifted from the \
177:        std::fs::write(&path, &generated).expect("write cli reference");
202:            "llms-full.txt" | "manifest.schema.json" => true,
203:            "install.sh" | "install.ps1" => true,
204:            t => root.join("docs-site/src").join(t).exists(),
362:            "--key-id" => key_id = it.next().cloned(),
363:            "--version" => version = it.next().and_then(|v| v.parse::<u64>().ok()),


Run the docs-drift gate (`xtask check`):


cargo run -p xtask -- check 2>&1 | tail -15; echo "XTASK_EXIT=$?"

docs-drift gate


Command running in background with ID: bw3k0e5qe. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bw3k0e5qe.output. You will be notified when it completes. To check interim output, use Read on that file path.


until [ -s "C:/Users/decid/AppData/Local/Temp/claude/C--Users-decid-Documents-projects-spt-core/afad552a-7216-48d3-ba81-3c8294f2a399/tasks/bw3k0e5qe.output" ]; do sleep 2; done; tail -8 "C:/Users/decid/AppData/Local/Temp/claude/C--Users-decid-Documents-projects-spt-core/afad552a-7216-48d3-ba81-3c8294f2a399/tasks/bw3k0e5qe.output"

wait + read xtask check output


<task-notification>
<task-id>bw3k0e5qe</task-id>
<tool-use-id>toolu_01KQGWDNEUmD1sahaUQbUPhE</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bw3k0e5qe.output</output-file>
<status>completed</status>
<summary>Background command "docs-drift gate" completed (exit code 0)</summary>
</task-notification>


   Compiling iroh v0.98.2
   Compiling spt-net v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\spt-net)
   Compiling spt-daemon v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\spt-daemon)
   Compiling xtask v0.2.0 (C:\Users\decid\Documents\projects\spt-core\crates\xtask)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 19.26s
     Running `target\debug\xtask.exe check`
xtask check: OK
XTASK_EXIT=0


Prompt:
<task-notification>
<task-id>bw3k0e5qe</task-id>
<tool-use-id>toolu_01KQGWDNEUmD1sahaUQbUPhE</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\afad552a-7216-48d3-ba81-3c8294f2a399\tasks\bw3k0e5qe.output</output-file>
<status>completed</status>
<summary>Background command "docs-drift gate" completed (exit code 0)</summary>
</task-notification>


All gates green: 105 tests (3 new), clippy clean, `--no-default-features` ok, traceable-reqs EXIT=0, xtask check OK. Commit:


cd "C:/Users/decid/Documents/projects/spt-core" && git add -A && git commit -q -F - <<'EOF'
perf(mesh): concurrent subnet status --nodes liveness probes (REQ-MESH-6) — Mesh-D8

The D6 mesh widen makes a node see ALL roster members of a subnet, many
silent → the serial `--nodes` probe loop (`.map(probe_node)`) cost
offline_count × PROBE_TIMEOUT (~2.5s each). Fan the probes out.

- `probe_all(items, ceiling, max_inflight, probe)`: one bounded thread per
  probe (each wrapped in `run_bounded`, so individually ceiling-bounded —
  KH 5.3 preserved), in-flight capped at MAX_INFLIGHT=16, results stitched
  back in row order. Wall ≈ one ceiling for k ≤ cap, ceil(k/cap) ceilings
  beyond (logged — no silent truncation of the wait). Threads + run_bounded,
  not tokio.
- `cmd_subnet_status` --nodes arm: three passes — classify all subnets'
  rows (pure), one concurrent batch across ALL subnets at once (one ceiling
  total, not one per subnet), stitch results back. Render unchanged, so
  output matches the old serial path (order-stable Online/Offline/Probe→bool).
- Dead `probe_node` wrapper removed; the real subnet-scoped probe
  (`probe_node_serving`, wansend.rs) is now injected into `probe_all`.

Units (REQ-MESH-6): injected deterministic sleeper proves N probes finish in
≈one ceiling not N×ceiling and map back in input order; a cap unit proves
window-batching; a timeout unit proves one wedged probe settles false in one
ceiling without dragging the batch.

traceable-reqs / clippy / --no-default-features / xtask docs-drift green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EOF
git log --oneline -1

Commit Mesh-D8


warning: in the working copy of 'crates/spt/src/cli.rs', LF will be replaced by CRLF the next time Git touches it
0c5c4f5 perf(mesh): concurrent subnet status --nodes liveness probes (REQ-MESH-6) — Mesh-D8


Mesh-D8 shipped: `0c5c4f5` (local, not pushed). Mesh arc essentially complete. Commune to Psyche:


Skill

Mesh-D8 DONE (commit 0c5c4f5, local/unpushed). REQ-MESH-6 activated [impl,unit]. probe_all() fans status --nodes liveness probes concurrently across ALL subnets in one bounded batch (thread-per-probe under run_bounded, cap MAX_INFLIGHT=16, results stitched order-stable) — replaces serial .map(probe_node) loop that cost offline_count×2.5s after D6 widen. Dead probe_node wrapper deleted; probe_node_serving now injected. 3 new units (concurrency+order, cap-batching, timeout-settles-false). ALL gates green: 105 tests, clippy, --no-default-features, traceable-reqs EXIT=0, xtask check (docs-drift) OK. Mesh arc D0–D8 now essentially COMPLETE. Next separate track = DAEMON-LIFECYCLE-PLAN.md (queued, untouched). User controls merge to main — push not requested this session.


Launching skill: spt:commune


Base directory for this skill: C:\Users\decid\.ccs\instances\bigscreen\plugins\cache\cplugs\spt\1.11.25\skills\commune

# /spt:commune

All commands use `$LIVE` env var, auto-injected by the plugin's SessionStart hook. If commands fail with "command not found", restart the Claude Code session so the SessionStart hook re-runs.

> **Identity auto-detection:** Your identity is auto-detected from your session. Pass your ID explicitly only if auto-detection fails.

## Flow

1. **Download Psyche's *current* context** — it shifts during the session as background echo communes fire. Re-download right before composing; the gen-N snapshot you read at session start is already stale:
   ```bash
   $LIVE psyche-download <your-id>
   ```

   > **Output truncation.** If the Bash tool reports `Output too large (N KB)` and saves the full result to a `tool-results/<id>.txt` file, use the `Read` tool on that saved path to access the full content. Do NOT re-run `psyche-download` to grep/awk out sections — repeated invocations re-download the same context, waste tokens, and may duplicate `## Pending Commune` sections in `live_context.md`.

2. **Diff your knowledge against this fresh download** — only what's missing from *it* is the real delta (new work, decisions, intentions). Anything already absorbed is not. If the download includes a `<memformat>` section, use it as a guide for what topics to cover. A `## Pending Commune (uncommitted)` section means a previous commune is still queued — do NOT re-send it.

3. **Commune only the delta** -- use the **Write tool** to create
   `.claude/{your-id}-commune.md` with the two-slice body as its contents
   (see `## Two-slice body shape (Phase 25 D-10/D-11)` below for the required
   envelope wrapping). Do not use Bash/heredoc -- Write is the canonical path:
   no shell escaping, no `EOF` collision risk, and Write auto-creates the
   `.claude/` parent directory.

   Your Self listener detects the file on its next poll iteration, notifies
   your Psyche wrapper, and the wrapper ingests the content via the existing
   Psyche session. On success (subprocess exit code 0) the wrapper deletes the
   file. On error (token rate limit, etc) the file is retained and retried on
   the next consume cycle. If you write again before the wrapper consumes, the
   latest write wins (last-write-wins overwrite semantics).

If Psyche's context is already current, no commune is needed. Say so and move on.

Read `commune.md` (in this skill directory) for the full commune protocol -- when to send, what to include, and diligence triggers.

**Agent-type guard:** Only works on live agents. If target is not live, refuses with: "Communes require a live agent with Psyche."

## Two-slice body shape (Phase 25 D-10/D-11)

The body you write in `.claude/{your-id}-commune.md` MUST itself be wrapped in two-slice envelopes per Phase 25 D-10/D-11. The taxonomy — what belongs in `<live-context>` vs `<project-context>` — is defined canonically in `psyche.md` §`<output_envelope>` (lines 282–323). Read that section as the source of truth; this skill doc teaches only when and how to apply it.

**In-project detection rule (D-25.1-04).** Before composing your commune body, run `$LIVE psyche-download <your-id>` (Step 1 of `## Flow` above) and inspect the `<current ... />` tag at the top of the output. The `<current/>` tag carries a `project="..."` attribute whenever any payload is produced — its presence means you are inside a tracked project (inside a git repo, `project` is the repo name; outside a git repo per D-11, `project` is the cwd-basename fallback, which still counts as a project context for routing purposes). A `psyche-download` invocation that returns no payload at all (NO-CONTEXT exit) means no project resolved. So: `project="..."` populated on `<current/>` → emit BOTH envelopes (apply rule 1 or 2 below); no payload at all → emit ONLY `<live-context>` (rule 3). Secondary signal: the `<project-context-resolved name="..."/>` sentinel further down the output indicates the project file already has prior content — useful for spotting first-time-in-project pairings, but NOT the routing rule.

**Three rules (D-25.1-01..03):**

- **In-project, both slices populated** (marker present, you have project-specific content this cycle): emit `<live-context>...</live-context>` AND `<project-context>...</project-context>`, both with non-empty bodies.
- **In-project, no project-specific update this cycle** (marker present, but nothing project-bound to report): emit `<live-context>...</live-context>` AND `<project-context></project-context>` (empty body — the deliberate "in-project but quiet" signal per D-25.1-02). Distinguishable from "no project resolved".
- **Outside any tracked project** (marker absent): emit ONLY `<live-context>...</live-context>`. Do NOT emit an empty `<project-context>` envelope (missing tag means "no project resolved" per D-25.1-03).

**Nested envelopes.** The Phase 23 `<EVENT type="commune">` envelope (see `## Envelope shape (Phase 23 v1.8)` below) is composed by `$LIVE commune` automatically — you NEVER write `<EVENT>` tags. You write ONLY the inner two-slice body. The two envelope layers nest: outer EVENT wraps inner two-slice body.

(See `psyche.md` §`<output_envelope>` for the canonical taxonomy and per-slice content rules.)

## Envelope shape (Phase 23 v1.8)

As of v1.8 Phase 23, commune deliveries are wrapped in a typed EVENT envelope carrying a 5-field stamp (`machine`, `project`, `branch`, `head_sha`, `head_subject`); the prose `COMMUNE (timestamp): body` form is gone.

```xml
<EVENT type="commune" timestamp="2026-05-20T06:00:00-07:00" machine="hostname" project="claude_skill_owl" branch="main" head_sha="abc123..." head_subject="subject line capped at 72 chars">body</EVENT>
```

Outside a git repo (D-11), `branch`, `head_sha`, and `head_subject` are omitted entirely (not empty-string-set):

```xml
<EVENT type="commune" timestamp="2026-05-20T06:00:00-07:00" machine="hostname" project="cwd-basename">body</EVENT>
```

`$LIVE commune` composes this envelope automatically — Self does NOT manually construct EVENT XML. The `body` placeholder in the example above is the two-slice body (see `## Two-slice body shape (Phase 25 D-10/D-11)` above); the two envelope layers nest. The wrapper-side parser ignores unknown attrs, so the stamp fields are forward-compatible with older receivers. For drift detection on resume, see the `live` skill.

ARGUMENTS: Mesh-D8 DONE (commit 0c5c4f5, local/unpushed). REQ-MESH-6 activated [impl,unit]. probe_all() fans status --nodes liveness probes concurrently across ALL subnets in one bounded batch (thread-per-probe under run_bounded, cap MAX_INFLIGHT=16, results stitched order-stable) — replaces serial .map(probe_node) loop that cost offline_count×2.5s after D6 widen. Dead probe_node wrapper deleted; probe_node_serving now injected. 3 new units (concurrency+order, cap-batching, timeout-settles-false). ALL gates green: 105 tests, clippy, --no-default-features, traceable-reqs EXIT=0, xtask check (docs-drift) OK. Mesh arc D0–D8 now essentially COMPLETE. Next separate track = DAEMON-LIFECYCLE-PLAN.md (queued, untouched). User controls merge to main — push not requested this session.


Download fresh Psyche context first (shifts during session):


Bash

$LIVE psyche-download doyle 2>&1 | head -60

Download current Psyche context


<memformat>
<?xml version="1.0"?>
<memformat version="1">
<!-- Changelog: v1 - initial seed -->
<topics>
  <topic name="events">Notable or unusual events and requests</topic>
  <topic name="interactions">Agent interactions -- who, roles, contributions</topic>
  <topic name="reflections">Thoughts on recent work -- what went well, what was tricky</topic>
  <topic name="ideas">Ideas to raise with the user</topic>
  <topic name="improvements">Further improvement ideas for recent problem spaces</topic>
  <topic name="timeline">What happened when, timing, sequencing</topic>
  <topic name="blockers">Current blockers or concerns</topic>
  <topic name="focus">Current focus and immediate next steps</topic>
</topics>
</memformat>
</memformat>

<current machine="HFENDULEAM" project="spt-core" branch="dev-freeform" head_sha="0c5c4f5df5f4a3ce5b4d9ce205087720d2c17d60" head_subject="perf(mesh): concurrent subnet status --nodes liveness probes (REQ-MESH-6…" commits_since="0" commits_unpulled="0"/>
Delta only (you already hold D7's five layers, deviations, and green verification — not repeating).

**D7 crypto lessons worth carrying (two failure modes I hit, not just the final design):**
1. STREAM DESYNC from asymmetric grading. A tombstone is one-sided: the rotator grades the revokee `Denied`, but the revokee grades the rotator `Full`. So the full/reseed grade is ASYMMETRIC between peers. The roster + SeedTransfer legs MUST run over the SYMMETRIC Hello-agreed shared set (both sides computed the same intersection), NOT gated on the grade — else one side sends a leg frame the other doesn't read and the bidi stream desyncs/hangs. The legs send grade-filtered CONTENT (empty frame when nothing to share) but always exchange the frame. Gated only on the roster-seam being present (symmetric by config).
2. DELIVERY RACE. First cut had the acceptor return `None` (drop the conn) right after pushing the seed — the QUIC CONNECTION_CLOSE raced the stale dialer's read of the SeedTransfer frame, so the offliner often never got the seed (test flaked/failed). Fix: a reseed-only conn must be REGISTERED (empty proven set) so it stays alive for delivery; only a PURE denial (nothing full AND nothing reseed) drops. `finalize(graded)` encodes this. The lingering reseed-only conn is benign and replaced when the healed peer reconnects full.

**D8 design (from MESH-D8-PLAN.md, now committed 0a3e036) — pre-flight is DONE so next session skips straight to impl:**
- CONFIRMED serial: cli.rs:2856-2866 (`cmd_subnet_status` --nodes arm) is a sequential `.map` over `probe_node` (each `run_bounded`-bounded 2.5s). D6's widen → every silent roster member is a Probe row → wall = k×2.5s. That IS REQ-MESH-6.
- FIX: add `probe_all(items, ceiling, max_inflight, probe)` — one std::thread per probe (mirrors `run_bounded`'s spawn+recv_timeout), concurrency cap ~16, the probe-fn INJECTED so the unit test passes a deterministic sleeper (no network). Batch spans ALL subnets at once (not per-subnet) → one ceiling total. Carry input index → stitch results back order-stable; render unchanged.
- Each thread stays individually hard-bounded by `ceiling` (KH 5.3 preserved). Log when k > cap (no silent truncation of the wait).
- Units: inject sleeper, assert N probes finish in <<N×D (proves not serial); a cap-batching unit; a timeout unit. Activate REQ-MESH-6 [impl,unit]. NO crypto/wire change. Do NOT pull tokio into the CLI — threads + run_bounded suffice. `probe_node_serving` cold-starts a brain IPC + net_dial per probe; concurrent dials against the one broker runtime are fine (block_on bridges from N caller threads).
- REMEMBER both CI gates on D8: traceable-reqs AND docs-drift (D8 changes no --help flags, so xtask gen likely a no-op, but check).<project-context-resolved name="spt-core"/>
HEAD now `0a3e036` (dev-freeform): D7 impl `618845d` + D8 plan `0a3e036`. Both committed LOCAL, NOT pushed (user controls merge to main; push not requested this session).

IMMEDIATE NEXT = Mesh-D8 (REQ-MESH-6), full JIT plan in MESH-D8-PLAN.md — start at impl (pre-flight done: probe loop confirmed serial). Concurrent `status --nodes` liveness probes; pure CLI polish, no crypto/wire change.

Mesh arc: D0–D5b ✅ · D6 ✅ (mesh ON, TrustStore/peers.json deleted) · D7 ✅ (revoke + timeboxed rotation + re-seed grace, REQ-MESH-4) · **D8 ← NEXT** (probe concurrency, REQ-MESH-6) · then the mesh arc is essentially complete. Queued untouched separate track: DAEMON-LIFECYCLE-PLAN.md.

traceable-reqs binding still in force (tag in-commit, run check before done, read RAW exit codes — false-green trap). Any CLI `--help` change ⇒ `xtask gen` or the docs-drift gate fails.


Marker present (`project="spt-core"`); Psyche still holds D8-as-NEXT (pre-impl). Write delta commune, both slices:


Write

<live-context>
Delta: Mesh-D8 is DONE (you held it as NEXT/pre-impl — update).

**D8 shipped exactly to plan, no deviations.** commit `0c5c4f5` (dev-freeform, LOCAL/unpushed). REQ-MESH-6 activated `[impl,unit]`.

- `probe_all(items, ceiling, max_inflight, probe)` added: one std::thread per probe wrapped in `run_bounded` (each individually ceiling-bounded — KH 5.3 preserved), processed in windows of `cap`=MAX_INFLIGHT(16), results stitched back order-stable. Wall ≈ one ceiling for k≤cap, ceil(k/cap) beyond (logged via eprintln when k>cap — no silent truncation). Threads + run_bounded, NO tokio.
- `cmd_subnet_status` --nodes arm rewritten to 3 passes: classify all subnets' rows (pure node_status_rows) → ONE concurrent batch across ALL subnets at once → stitch by cursor. Render unchanged (render_node_rows), so output identical to old serial path.
- Dead `probe_node` wrapper DELETED (clippy flagged it unused once the batch path took over). The real subnet-scoped probe `probe_node_serving` (wansend.rs, still carries impl->REQ-SUBNET-1/5) is now injected directly into `probe_all`'s closure. PROBE_TIMEOUT/MAX_INFLIGHT hoisted to module consts.
- 3 new units (all green): `probe_all_runs_concurrently_in_input_order` (N=8/D=200ms, <4×D + node3→false proves index mapping), `probe_all_cap_batches_into_windows` (N=20/cap=4/D=100ms, [5×D,9×D)), `probe_all_timeout_settles_false_without_stalling_batch` (one 1500ms wedged probe settles false in <4×150ms ceiling, batch not dragged).

**Verification — ALL gates green:** 105 spt-bin tests pass; clippy clean; `--no-default-features` builds; `traceable-reqs check` EXIT=0 (read raw — REQ-MESH-6 [impl,unit] satisfied); `cargo run -p xtask -- check` = "xtask check: OK" (docs-drift — D8 changed no --help flags as predicted, no-op regen).

Lesson confirmed: the injected-probe seam made the timing units fully deterministic (no network, no flake) — same mock-clock discipline that worked for run_bounded.
</live-context>
<project-context>
HEAD now `0c5c4f5` (dev-freeform): D7 `618845d` + D8 plan `0a3e036` + D8 impl `0c5c4f5`. All LOCAL, NOT pushed (user controls merge to main; push not requested this session).

Mesh arc: D0–D5b ✅ · D6 ✅ · D7 ✅ · **D8 ✅ (REQ-MESH-6 concurrent --nodes probes)** → mesh arc D0–D8 essentially COMPLETE.

IMMEDIATE NEXT = no active mesh work. Queued untouched separate track: DAEMON-LIFECYCLE-PLAN.md. Awaiting user direction on whether to start it or push/merge the mesh arc.

traceable-reqs binding still in force (tag in-commit, run check before done, raw exit codes). Any CLI --help change ⇒ xtask gen or docs-drift gate fails.
</project-context>