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)

use clap::{Parser, Subcommand};
use spt_msg::deliver::{self, SendOutcome};
use spt_msg::ready::ReadyAgent;
use spt_msg::ring::{self, RingOutcome};
use spt_store::perch::{self, ParentHint};
use spt_store::registry;

use crate::roster;

use clap::{Parser, Subcommand};
use spt_msg::deliver::{self, SendOutcome};
use spt_msg::ready::ReadyAgent;
use spt_msg::ring::{self, RingOutcome};
use spt_net::net::pairing::totp::TotpSeed;
use spt_store::perch::{self, ParentHint};
use spt_store::registry;
use spt_store::subnet::{SubnetError, SubnetStore};

use crate::elevation::{self, Elevation, Gate};
use crate::roster;

/// Product tag embedded in the `otpauth://` provisioning URI (the authenticator-app
/// issuer label). Stable user-facing string.
const ISSUER: &str = "spt";

/// `spt pair show-totp` refused the fetch for lack of OS elevation. Distinct from the
/// crate-wide codes (`0` ok · `1` runtime refusal · `2` usage): `3` says the fetch was
/// *refused, not failed* — re-run elevated, or read the code from your authenticator app.
const EXIT_NOT_ELEVATED: i32 = 3;

+use crate::elevation::{self, Elevation, Gate};

+/// Product tag embedded in the `otpauth://` provisioning URI (the authenticator-app

+/// issuer label). Stable user-facing string.

+/// `spt pair show-totp` refused the fetch for lack of OS elevation. Distinct from the

+/// crate-wide codes (`0` ok · `1` runtime refusal · `2` usage): `3` says the fetch was

+/// *refused, not failed* — re-run elevated, or read the code from your authenticator app.

#[command(name = "spt", version, about = "spt-core local messaging", long_about = None)]


Edit

    /// Print this session's own perch id (from $OWL_SESSION_ID / $SPT_AGENT_ID).
    Whoami,

    /// Print this session's own perch id (from $OWL_SESSION_ID / $SPT_AGENT_ID).
    Whoami,
    /// Subnet pairing operations (REQ-PAIR-*). Local-only here — the cross-node
    /// ceremony rides spt-net (M4 D4+).
    Pair {
        #[command(subcommand)]
        action: PairCmd,
    },


    /// Print this session's own perch id (from $OWL_SESSION_ID / $SPT_AGENT_ID).
    Whoami,
    /// Subnet pairing operations (REQ-PAIR-*). Local-only here — the cross-node
    /// ceremony rides spt-net (M4 D4+).
    Pair {
        #[command(subcommand)]
        action: PairCmd,
    },

+    /// Subnet pairing operations (REQ-PAIR-*). Local-only here — the cross-node

+    /// ceremony rides spt-net (M4 D4+).

/// Show a daemon-hosted session's live activity buffer (PTY digest) — the

/// at-a-glance "what is this agent doing now" view (ADR-0008). Pulls a

/// snapshot, or `--follow`s the delta-stream. Local addressing only (the


Now add the `PairCmd` enum after the `Cmd` enum closes, and the dispatch arm.


    /// Run the per-machine broker/brain daemon (REQ-DAEMON-3). Internal: an
    /// `api` invocation auto-starts this; operators rarely run it directly.
    #[command(hide = true)]
    Daemon,
}

    /// Run the per-machine broker/brain daemon (REQ-DAEMON-3). Internal: an
    /// `api` invocation auto-starts this; operators rarely run it directly.
    #[command(hide = true)]
    Daemon,
}

/// `spt pair <action>` subcommands.
#[derive(Subcommand)]
enum PairCmd {
    /// Show a subnet's current 6-digit pairing code + `otpauth://` URI — the
    /// node-bound fetch, gated behind OS elevation (REQ-PAIR-3/6). With no flag the
    /// node's sole subnet is used; if it holds several, `--subnet <name>` is required
    /// (no guessing). `--create-new <name>` mints a fresh subnet first.
    ShowTotp {
        /// Which subnet's code to show. Required only when the node holds several.
        #[arg(long)]
        subnet: Option<String>,
        /// Mint a fresh subnet with this name (this node becomes the sole seed-holder),
        /// then show its code. Mutually exclusive with `--subnet`.
        #[arg(long, value_name = "NAME", conflicts_with = "subnet")]
        create_new: Option<String>,
    },
}


NOTE fROM THE USER:proceed withnext steps.


    /// Run the per-machine broker/brain daemon (REQ-DAEMON-3). Internal: an
    /// `api` invocation auto-starts this; operators rarely run it directly.
    #[command(hide = true)]
    Daemon,
}

/// `spt pair <action>` subcommands.
#[derive(Subcommand)]
enum PairCmd {
    /// Show a subnet's current 6-digit pairing code + `otpauth://` URI — the
    /// node-bound fetch, gated behind OS elevation (REQ-PAIR-3/6). With no flag the
    /// node's sole subnet is used; if it holds several, `--subnet <name>` is required
    /// (no guessing). `--create-new <name>` mints a fresh subnet first.
    ShowTotp {
        /// Which subnet's code to show. Required only when the node holds several.
        #[arg(long)]
        subnet: Option<String>,
        /// Mint a fresh subnet with this name (this node becomes the sole seed-holder),
        /// then show its code. Mutually exclusive with `--subnet`.
        #[arg(long, value_name = "NAME", conflicts_with = "subnet")]
        create_new: Option<String>,
    },
}

+    /// Show a subnet's current 6-digit pairing code + `otpauth://` URI — the

+    /// node-bound fetch, gated behind OS elevation (REQ-PAIR-3/6). With no flag the

+    /// node's sole subnet is used; if it holds several, `--subnet <name>` is required

+    /// (no guessing). `--create-new <name>` mints a fresh subnet first.

+        /// Which subnet's code to show. Required only when the node holds several.

+        /// Mint a fresh subnet with this name (this node becomes the sole seed-holder),

+        /// then show its code. Mutually exclusive with `--subnet`.

+        #[arg(long, value_name = "NAME", conflicts_with = "subnet")]

/// Parse args and dispatch. Returns the process exit code.


        Cmd::Whoami => cmd_whoami(),
        Cmd::Digest { id, follow, json } => cmd_digest(&id, follow, json),

        Cmd::Whoami => cmd_whoami(),
        Cmd::Pair { action } => match action {
            PairCmd::ShowTotp { subnet, create_new } => cmd_pair_show_totp(subnet, create_new),
        },
        Cmd::Digest { id, follow, json } => cmd_digest(&id, follow, json),


        Cmd::Whoami => cmd_whoami(),
        Cmd::Digest { id, follow, json } => cmd_digest(&id, follow, json),

        Cmd::Whoami => cmd_whoami(),
        Cmd::Pair { action } => match action {
            PairCmd::ShowTotp { subnet, create_new } => cmd_pair_show_totp(subnet, create_new),
        },
        Cmd::Digest { id, follow, json } => cmd_digest(&id, follow, json),

+        Cmd::Pair { action } => match action {

+            PairCmd::ShowTotp { subnet, create_new } => cmd_pair_show_totp(subnet, create_new),


Now the handler + resolution seam. Insert before the test module.


#[cfg(test)]
mod tests {
    use super::*;

    fn parse(args: &[&str]) -> Result<Cli, clap::Error> {
        Cli::try_parse_from(args)
    }

/// What `show-totp` resolved its arguments to against the node's subnet store — the
/// platform-independent half of the command, decided before any OS elevation call so
/// it can be unit-tested hermetically.
enum Resolved {
    /// A subnet to surface: its name + raw seed bytes. `minted` = freshly created by
    /// `--create-new` (persist it only once the code is actually shown).
    Subnet { name: String, seed: [u8; spt_store::subnet::TOTP_SEED_LEN], minted: bool },
    /// Several subnets and no `--subnet` — refuse rather than guess.
    Ambiguous(Vec<String>),
    /// The node belongs to no subnet at all.
    Empty,
    /// A named subnet (`--subnet`) is not in the store.
    NotFound(String),
    /// `--create-new <name>` for a subnet that already exists.
    Exists(String),
    /// The stored seed is unreadable (corrupt hex/length) — re-pair to re-provision.
    Corrupt(String),
}

/// The rendered outcome of `show-totp`: an exit code, the optional stdout block (the
/// code + URI — present ONLY on the elevated show path, never leaked otherwise), a
/// stderr status line, and whether to persist a freshly-minted subnet. Pure over its
/// inputs (no IO, no OS calls) so every branch is unit-tested.
struct ShowResult {
    code: i32,
    out: Option<String>,
    msg: String,
    save: bool,
}

/// Resolve `show-totp` arguments against the store (mutating it iff `--create-new`
/// mints). The mint is in-memory only; the caller persists it just on the show path.
// [impl->REQ-PAIR-3]
fn resolve(store: &mut SubnetStore, subnet: Option<String>, create_new: Option<String>) -> Resolved {
    if let Some(name) = create_new {
        return match store.create_subnet(&name) {
            Ok(rec) => match rec.seed_bytes() {
                Some(seed) => Resolved::Subnet { name: rec.name.clone(), seed, minted: true },
                None => Resolved::Corrupt(rec.name.clone()),
            },
            Err(SubnetError::Exists(n)) => Resolved::Exists(n),
            Err(e) => Resolved::Corrupt(e.to_string()),
        };
    }
    if let Some(name) = subnet {
        return match store.find(&name) {
            Some(rec) => match rec.seed_bytes() {
                Some(seed) => Resolved::Subnet { name: rec.name.clone(), seed, minted: false },
                None => Resolved::Corrupt(rec.name.clone()),
            },
            None => Resolved::NotFound(name),
        };
    }
    // No flag: auto-select iff the node holds exactly one subnet (same no-guessing
    // ethos as D3c addressing — several is an error, not a default pick).
    match store.subnets.len() {
        0 => Resolved::Empty,
        1 => match store.subnets[0].seed_bytes() {
            Some(seed) => Resolved::Subnet { name: store.subnets[0].name.clone(), seed, minted: false },
            None => Resolved::Corrupt(store.subnets[0].name.clone()),
        },
        _ => Resolved::Ambiguous(store.subnets.iter().map(|s| s.name.clone()).collect()),
    }
}

/// Decide the rendered outcome from a resolution + the clock + the elevation level.
/// The elevation gate is applied LAST: a resolved subnet still falls back (and leaks
/// no code) unless the process is confirmed elevated.
// [impl->REQ-PAIR-3] [impl->REQ-PAIR-6]
fn decide_show_totp(resolved: Resolved, now: u64, elevation: Elevation) -> ShowResult {
    match resolved {
        Resolved::Subnet { name, seed, minted } => match elevation::gate_for(elevation) {
            Gate::Show => {
                let totp = TotpSeed::from_bytes(seed);
                // The URI carries the base32 secret — importable into an authenticator
                // app; QR *rendering* is GUI/later, so we print the URI text only.
                let out = format!("{}\n{}\n", totp.code_at(now), totp.otpauth_uri(ISSUER, &name));
                ShowResult { code: 0, out: Some(out), msg: format!("TOTP:{name} (elevated)"), save: minted }
            }
            // Refused fetch: no code, and we do NOT persist a `--create-new` mint —
            // a refused command leaves no durable side effect (re-run elevated).
            Gate::Fallback => ShowResult {
                code: EXIT_NOT_ELEVATED,
                out: None,
                msg: elevation::fallback_message(&name),
                save: false,
            },
        },
        Resolved::Ambiguous(names) => ShowResult {
            code: 2,
            out: None,
            msg: format!(
                "AMBIGUOUS_SUBNET: this node holds {} subnets ({}) — pass --subnet <name>",
                names.len(),
                names.join(", ")
            ),
            save: false,
        },
        Resolved::Empty => ShowResult {
            code: 2,
            out: None,
            msg: "NO_SUBNETS: this node belongs to no subnet — pair first, or mint one with --create-new <name>".to_string(),
            save: false,
        },
        Resolved::NotFound(n) => ShowResult {
            code: 2,
            out: None,
            msg: format!("NO_SUCH_SUBNET:{n}"),
            save: false,
        },
        Resolved::Exists(n) => ShowResult {
            code: 2,
            out: None,
            msg: format!("SUBNET_EXISTS:{n} — already a member; drop --create-new to show its code"),
            save: false,
        },
        Resolved::Corrupt(n) => ShowResult {
            code: 1,
            out: None,
            msg: format!("CORRUPT_SEED:{n} — stored seed is unreadable; re-pair to re-provision"),
            save: false,
        },
    }
}

/// `spt pair show-totp` — surface a subnet's current code off this node, behind the
/// OS-elevation gate (REQ-PAIR-3/6). Wires the real store, clock, and elevation probe
/// into the unit-tested [`resolve`]/[`decide_show_totp`] core.
// [impl->REQ-PAIR-3] [impl->REQ-PAIR-6]
fn cmd_pair_show_totp(subnet: Option<String>, create_new: Option<String>) -> i32 {
    let mut store = SubnetStore::load();
    let resolved = resolve(&mut store, subnet, create_new);
    let result = decide_show_totp(resolved, now_unix(), elevation::current());

    if result.save {
        if let Err(e) = store.save() {
            eprintln!("SAVE_FAIL: freshly minted subnet not persisted: {e}");
            return 1;
        }
    }
    if let Some(out) = result.out {
        print!("{out}");
        let _ = std::io::stdout().flush();
    }
    eprintln!("{}", result.msg);
    result.code
}

/// Current unix time in whole seconds (the TOTP clock input). A pre-epoch clock
/// degrades to step 0 rather than panicking.
fn now_unix() -> u64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0)
}

#[cfg(test)]
mod tests {
    use super::*;

    fn parse(args: &[&str]) -> Result<Cli, clap::Error> {
        Cli::try_parse_from(args)
    }


/// What `show-totp` resolved its arguments to against the node's subnet store — the
/// platform-independent half of the command, decided before any OS elevation call so
/// it can be unit-tested hermetically.
enum Resolved {
    /// A subnet to surface: its name + raw seed bytes. `minted` = freshly created by
    /// `--create-new` (persist it only once the code is actually shown).
    Subnet { name: String, seed: [u8; spt_store::subnet::TOTP_SEED_LEN], minted: bool },
    /// Several subnets and no `--subnet` — refuse rather than guess.
    Ambiguous(Vec<String>),
    /// The node belongs to no subnet at all.
    Empty,
    /// A named subnet (`--subnet`) is not in the store.
    NotFound(String),
    /// `--create-new <name>` for a subnet that already exists.
    Exists(String),
    /// The stored seed is unreadable (corrupt hex/length) — re-pair to re-provision.
    Corrupt(String),
}

/// The rendered outcome of `show-totp`: an exit code, the optional stdout block (the
/// code + URI — present ONLY on the elevated show path, never leaked otherwise), a
/// stderr status line, and whether to persist a freshly-minted subnet. Pure over its
/// inputs (no IO, no OS calls) so every branch is unit-tested.
struct ShowResult {
    code: i32,
    out: Option<String>,
    msg: String,
    save: bool,
}

/// Resolve `show-totp` arguments against the store (mutating it iff `--create-new`
/// mints). The mint is in-memory only; the caller persists it just on the show path.
// [impl->REQ-PAIR-3]
fn resolve(store: &mut SubnetStore, subnet: Option<String>, create_new: Option<String>) -> Resolved {
    if let Some(name) = create_new {
        return match store.create_subnet(&name) {
            Ok(rec) => match rec.seed_bytes() {
                Some(seed) => Resolved::Subnet { name: rec.name.clone(), seed, minted: true },
                None => Resolved::Corrupt(rec.name.clone()),
            },
            Err(SubnetError::Exists(n)) => Resolved::Exists(n),
            Err(e) => Resolved::Corrupt(e.to_string()),
        };
    }
    if let Some(name) = subnet {
        return match store.find(&name) {
            Some(rec) => match rec.seed_bytes() {
                Some(seed) => Resolved::Subnet { name: rec.name.clone(), seed, minted: false },
                None => Resolved::Corrupt(rec.name.clone()),
            },
            None => Resolved::NotFound(name),
        };
    }
    // No flag: auto-select iff the node holds exactly one subnet (same no-guessing
    // ethos as D3c addressing — several is an error, not a default pick).
    match store.subnets.len() {
        0 => Resolved::Empty,
        1 => match store.subnets[0].seed_bytes() {
            Some(seed) => Resolved::Subnet { name: store.subnets[0].name.clone(), seed, minted: false },
            None => Resolved::Corrupt(store.subnets[0].name.clone()),
        },
        _ => Resolved::Ambiguous(store.subnets.iter().map(|s| s.name.clone()).collect()),
    }
}

/// Decide the rendered outcome from a resolution + the clock + the elevation level.
/// The elevation gate is applied LAST: a resolved subnet still falls back (and leaks
/// no code) unless the process is confirmed elevated.
// [impl->REQ-PAIR-3] [impl->REQ-PAIR-6]
fn decide_show_totp(resolved: Resolved, now: u64, elevation: Elevation) -> ShowResult {
    match resolved {
        Resolved::Subnet { name, seed, minted } => match elevation::gate_for(elevation) {
            Gate::Show => {
                let totp = TotpSeed::from_bytes(seed);
                // The URI carries the base32 secret — importable into an authenticator
                // app; QR *rendering* is GUI/later, so we print the URI text only.
                let out = format!("{}\n{}\n", totp.code_at(now), totp.otpauth_uri(ISSUER, &name));
                ShowResult { code: 0, out: Some(out), msg: format!("TOTP:{name} (elevated)"), save: minted }
            }
            // Refused fetch: no code, and we do NOT persist a `--create-new` mint —
            // a refused command leaves no durable side effect (re-run elevated).
            Gate::Fallback => ShowResult {
                code: EXIT_NOT_ELEVATED,
                out: None,
                msg: elevation::fallback_message(&name),
                save: false,
            },
        },
        Resolved::Ambiguous(names) => ShowResult {
            code: 2,
            out: None,
            msg: format!(
                "AMBIGUOUS_SUBNET: this node holds {} subnets ({}) — pass --subnet <name>",
                names.len(),
                names.join(", ")
            ),
            save: false,
        },
        Resolved::Empty => ShowResult {
            code: 2,
            out: None,
            msg: "NO_SUBNETS: this node belongs to no subnet — pair first, or mint one with --create-new <name>".to_string(),
            save: false,
        },
        Resolved::NotFound(n) => ShowResult {
            code: 2,
            out: None,
            msg: format!("NO_SUCH_SUBNET:{n}"),
            save: false,
        },
        Resolved::Exists(n) => ShowResult {
            code: 2,
            out: None,
            msg: format!("SUBNET_EXISTS:{n} — already a member; drop --create-new to show its code"),
            save: false,
        },
        Resolved::Corrupt(n) => ShowResult {
            code: 1,
            out: None,
            msg: format!("CORRUPT_SEED:{n} — stored seed is unreadable; re-pair to re-provision"),
            save: false,
        },
    }
}

/// `spt pair show-totp` — surface a subnet's current code off this node, behind the
/// OS-elevation gate (REQ-PAIR-3/6). Wires the real store, clock, and elevation probe
/// into the unit-tested [`resolve`]/[`decide_show_totp`] core.
// [impl->REQ-PAIR-3] [impl->REQ-PAIR-6]
fn cmd_pair_show_totp(subnet: Option<String>, create_new: Option<String>) -> i32 {
    let mut store = SubnetStore::load();
    let resolved = resolve(&mut store, subnet, create_new);
    let result = decide_show_totp(resolved, now_unix(), elevation::current());

    if result.save {
        if let Err(e) = store.save() {
            eprintln!("SAVE_FAIL: freshly minted subnet not persisted: {e}");
            return 1;
        }
    }
    if let Some(out) = result.out {
        print!("{out}");
        let _ = std::io::stdout().flush();
    }
    eprintln!("{}", result.msg);
    result.code
}

/// Current unix time in whole seconds (the TOTP clock input). A pre-epoch clock
/// degrades to step 0 rather than panicking.
fn now_unix() -> u64 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_secs())
        .unwrap_or(0)
}

#[cfg(test)]
mod tests {
    use super::*;

    fn parse(args: &[&str]) -> Result<Cli, clap::Error> {
        Cli::try_parse_from(args)
    }

+/// What `show-totp` resolved its arguments to against the node's subnet store — the

+/// platform-independent half of the command, decided before any OS elevation call so

+/// it can be unit-tested hermetically.

+    /// A subnet to surface: its name + raw seed bytes. `minted` = freshly created by

+    /// `--create-new` (persist it only once the code is actually shown).

+    Subnet { name: String, seed: [u8; spt_store::subnet::TOTP_SEED_LEN], minted: bool },

+    /// Several subnets and no `--subnet` — refuse rather than guess.

+    /// The node belongs to no subnet at all.

+    /// A named subnet (`--subnet`) is not in the store.

+    /// `--create-new <name>` for a subnet that already exists.

+    /// The stored seed is unreadable (corrupt hex/length) — re-pair to re-provision.

+/// The rendered outcome of `show-totp`: an exit code, the optional stdout block (the

+/// code + URI — present ONLY on the elevated show path, never leaked otherwise), a

+/// stderr status line, and whether to persist a freshly-minted subnet. Pure over its

+/// inputs (no IO, no OS calls) so every branch is unit-tested.

+/// Resolve `show-totp` arguments against the store (mutating it iff `--create-new`

+/// mints). The mint is in-memory only; the caller persists it just on the show path.

+fn resolve(store: &mut SubnetStore, subnet: Option<String>, create_new: Option<String>) -> Resolved {

+        return match store.create_subnet(&name) {

+            Ok(rec) => match rec.seed_bytes() {

+                Some(seed) => Resolved::Subnet { name: rec.name.clone(), seed, minted: true },

+                None => Resolved::Corrupt(rec.name.clone()),

+            Err(SubnetError::Exists(n)) => Resolved::Exists(n),

+            Err(e) => Resolved::Corrupt(e.to_string()),

+        return match store.find(&name) {

+            Some(rec) => match rec.seed_bytes() {

+                Some(seed) => Resolved::Subnet { name: rec.name.clone(), seed, minted: false },

+            None => Resolved::NotFound(name),

+    // No flag: auto-select iff the node holds exactly one subnet (same no-guessing

+    // ethos as D3c addressing — several is an error, not a default pick).

+        1 => match store.subnets[0].seed_bytes() {

+            Some(seed) => Resolved::Subnet { name: store.subnets[0].name.clone(), seed, minted: false },

+            None => Resolved::Corrupt(store.subnets[0].name.clone()),

+        _ => Resolved::Ambiguous(store.subnets.iter().map(|s| s.name.clone()).collect()),

+/// Decide the rendered outcome from a resolution + the clock + the elevation level.

+/// The elevation gate is applied LAST: a resolved subnet still falls back (and leaks

+/// no code) unless the process is confirmed elevated.

+fn decide_show_totp(resolved: Resolved, now: u64, elevation: Elevation) -> ShowResult {

+        Resolved::Subnet { name, seed, minted } => match elevation::gate_for(elevation) {

+                let totp = TotpSeed::from_bytes(seed);

+                // The URI carries the base32 secret — importable into an authenticator

+                // app; QR *rendering* is GUI/later, so we print the URI text only.

+                let out = format!("{}\n{}\n", totp.code_at(now), totp.otpauth_uri(ISSUER, &name));

+                ShowResult { code: 0, out: Some(out), msg: format!("TOTP:{name} (elevated)"), save: minted }

+            // Refused fetch: no code, and we do NOT persist a `--create-new` mint —

+            // a refused command leaves no durable side effect (re-run elevated).

+            Gate::Fallback => ShowResult {

+                code: EXIT_NOT_ELEVATED,

+                msg: elevation::fallback_message(&name),

+        Resolved::Ambiguous(names) => ShowResult {

+                "AMBIGUOUS_SUBNET: this node holds {} subnets ({}) — pass --subnet <name>",

+        Resolved::Empty => ShowResult {

+            msg: "NO_SUBNETS: this node belongs to no subnet — pair first, or mint one with --create-new <name>".to_string(),

+        Resolved::NotFound(n) => ShowResult {

+            msg: format!("NO_SUCH_SUBNET:{n}"),

+        Resolved::Exists(n) => ShowResult {

+            msg: format!("SUBNET_EXISTS:{n} — already a member; drop --create-new to show its code"),

+        Resolved::Corrupt(n) => ShowResult {

+            msg: format!("CORRUPT_SEED:{n} — stored seed is unreadable; re-pair to re-provision"),

+/// `spt pair show-totp` — surface a subnet's current code off this node, behind the

+/// OS-elevation gate (REQ-PAIR-3/6). Wires the real store, clock, and elevation probe

+/// into the unit-tested [`resolve`]/[`decide_show_totp`] core.

+fn cmd_pair_show_totp(subnet: Option<String>, create_new: Option<String>) -> i32 {

+    let mut store = SubnetStore::load();

+    let resolved = resolve(&mut store, subnet, create_new);

+    let result = decide_show_totp(resolved, now_unix(), elevation::current());

+            eprintln!("SAVE_FAIL: freshly minted subnet not persisted: {e}");

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

+/// Current unix time in whole seconds (the TOTP clock input). A pre-epoch clock

+/// degrades to step 0 rather than panicking.

+        .duration_since(std::time::UNIX_EPOCH)


Now the cli tests. Append to the test module.


    // [unit->REQ-MSG-2] unknown subcommand / missing required arg are usage errors.
    #[test]
    fn invalid_usage_errors() {
        assert!(parse(&["spt", "bogus"]).is_err());
        assert!(parse(&["spt", "ring"]).is_err()); // missing required target
    }
}

    // [unit->REQ-MSG-2] unknown subcommand / missing required arg are usage errors.
    #[test]
    fn invalid_usage_errors() {
        assert!(parse(&["spt", "bogus"]).is_err());
        assert!(parse(&["spt", "ring"]).is_err()); // missing required target
    }

    // ── pair show-totp ─────────────────────────────────────────────────────────

    fn show_totp(args: &[&str]) -> PairCmd {
        match parse(args).unwrap().cmd {
            Cmd::Pair { action } => action,
            _ => panic!("expected Pair"),
        }
    }

    // [unit->REQ-PAIR-3] the show-totp arg shapes parse: bare, --subnet, --create-new.
    #[test]
    fn pair_show_totp_arg_shapes_parse() {
        assert!(matches!(
            show_totp(&["spt", "pair", "show-totp"]),
            PairCmd::ShowTotp { subnet: None, create_new: None }
        ));
        assert!(matches!(
            show_totp(&["spt", "pair", "show-totp", "--subnet", "home"]),
            PairCmd::ShowTotp { subnet: Some(s), .. } if s == "home"
        ));
        assert!(matches!(
            show_totp(&["spt", "pair", "show-totp", "--create-new", "home"]),
            PairCmd::ShowTotp { create_new: Some(s), .. } if s == "home"
        ));
    }

    // [unit->REQ-PAIR-3] --subnet and --create-new are mutually exclusive.
    #[test]
    fn pair_show_totp_subnet_and_create_new_conflict() {
        assert!(parse(&["spt", "pair", "show-totp", "--subnet", "a", "--create-new", "b"]).is_err());
    }

    fn store_with(names: &[&str]) -> SubnetStore {
        let mut s = SubnetStore::default();
        for n in names {
            s.create_subnet(n).expect("create");
        }
        s
    }

    // [unit->REQ-PAIR-3] a lone subnet is auto-selected with no flag; elevated, the
    // printed code matches TotpSeed computed from that subnet's stored seed.
    #[test]
    fn single_subnet_auto_selects_and_code_matches_seed() {
        let mut store = store_with(&["home"]);
        let seed = store.find("home").unwrap().seed_bytes().unwrap();
        let now = 1_111_111_109;
        let r = decide_show_totp(resolve(&mut store, None, None), now, Elevation::Elevated);
        assert_eq!(r.code, 0);
        let expected = TotpSeed::from_bytes(seed).code_at(now);
        let out = r.out.expect("elevated show prints the code");
        assert!(out.starts_with(&expected), "stdout starts with the code");
        assert!(out.contains("otpauth://"), "stdout carries the provisioning URI");
        assert!(!r.save, "an existing subnet is not re-persisted");
    }

    // [unit->REQ-PAIR-3] several subnets + no --subnet refuses (no guessing); naming
    // one resolves it.
    #[test]
    fn multi_subnet_refuses_without_flag_then_resolves_with_it() {
        let mut store = store_with(&["home", "work"]);
        let amb = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Elevated);
        assert_eq!(amb.code, 2);
        assert!(amb.out.is_none());
        assert!(amb.msg.contains("AMBIGUOUS_SUBNET"));

        let work_seed = store.find("work").unwrap().seed_bytes().unwrap();
        let now = 1_234_567_890;
        let r = decide_show_totp(
            resolve(&mut store, Some("work".into()), None),
            now,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 0);
        assert!(r.out.unwrap().starts_with(&TotpSeed::from_bytes(work_seed).code_at(now)));
    }

    // [unit->REQ-PAIR-3] --create-new on a fresh name mints + shows, and flags the
    // store for persistence (save = true) on the elevated path.
    #[test]
    fn create_new_mints_shows_and_requests_save() {
        let mut store = SubnetStore::default();
        let r = decide_show_totp(
            resolve(&mut store, None, Some("fresh".into())),
            42,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 0);
        assert!(r.save, "a freshly minted subnet must be persisted on show");
        assert!(r.out.unwrap().contains("otpauth://"));
        assert!(store.find("fresh").is_some(), "mint landed in the in-memory store");
    }

    // [unit->REQ-PAIR-3] --create-new for an existing name is a usage error.
    #[test]
    fn create_new_existing_name_is_usage_error() {
        let mut store = store_with(&["home"]);
        let r = decide_show_totp(
            resolve(&mut store, None, Some("home".into())),
            0,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 2);
        assert!(r.msg.contains("SUBNET_EXISTS"));
    }

    // [unit->REQ-PAIR-3] zero subnets + no flag points the user at pairing / --create-new.
    #[test]
    fn empty_store_no_flag_guides_to_pair_or_create() {
        let mut store = SubnetStore::default();
        let r = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Elevated);
        assert_eq!(r.code, 2);
        assert!(r.msg.contains("NO_SUBNETS"));
    }

    // [unit->REQ-PAIR-3] a named-but-absent subnet is a usage error.
    #[test]
    fn unknown_named_subnet_is_usage_error() {
        let mut store = store_with(&["home"]);
        let r = decide_show_totp(
            resolve(&mut store, Some("ghost".into()), None),
            0,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 2);
        assert!(r.msg.contains("NO_SUCH_SUBNET:ghost"));
    }

    // [unit->REQ-PAIR-6] not elevated: the fetch is refused — distinct exit code, NO
    // code in stdout (no leak), fallback message names the authenticator app, and a
    // would-be --create-new mint is NOT persisted (refused = no durable side effect).
    #[test]
    fn not_elevated_refuses_without_leaking_code_or_saving() {
        let mut store = SubnetStore::default();
        let r = decide_show_totp(
            resolve(&mut store, None, Some("fresh".into())),
            0,
            Elevation::NotElevated,
        );
        assert_eq!(r.code, EXIT_NOT_ELEVATED);
        assert!(r.out.is_none(), "no code leaks on the refused path");
        assert!(r.msg.contains("authenticator app"));
        assert!(!r.save, "a refused fetch persists no mint");
    }

    // [unit->REQ-PAIR-6] an undeterminable elevation (Unknown) also falls back — the
    // same fail-safe path as NotElevated, never leaking the code.
    #[test]
    fn unknown_elevation_falls_back() {
        let mut store = store_with(&["home"]);
        let r = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Unknown);
        assert_eq!(r.code, EXIT_NOT_ELEVATED);
        assert!(r.out.is_none());
    }
}


    // [unit->REQ-MSG-2] unknown subcommand / missing required arg are usage errors.
    #[test]
    fn invalid_usage_errors() {
        assert!(parse(&["spt", "bogus"]).is_err());
        assert!(parse(&["spt", "ring"]).is_err()); // missing required target
    }
}

    // [unit->REQ-MSG-2] unknown subcommand / missing required arg are usage errors.
    #[test]
    fn invalid_usage_errors() {
        assert!(parse(&["spt", "bogus"]).is_err());
        assert!(parse(&["spt", "ring"]).is_err()); // missing required target
    }

    // ── pair show-totp ─────────────────────────────────────────────────────────

    fn show_totp(args: &[&str]) -> PairCmd {
        match parse(args).unwrap().cmd {
            Cmd::Pair { action } => action,
            _ => panic!("expected Pair"),
        }
    }

    // [unit->REQ-PAIR-3] the show-totp arg shapes parse: bare, --subnet, --create-new.
    #[test]
    fn pair_show_totp_arg_shapes_parse() {
        assert!(matches!(
            show_totp(&["spt", "pair", "show-totp"]),
            PairCmd::ShowTotp { subnet: None, create_new: None }
        ));
        assert!(matches!(
            show_totp(&["spt", "pair", "show-totp", "--subnet", "home"]),
            PairCmd::ShowTotp { subnet: Some(s), .. } if s == "home"
        ));
        assert!(matches!(
            show_totp(&["spt", "pair", "show-totp", "--create-new", "home"]),
            PairCmd::ShowTotp { create_new: Some(s), .. } if s == "home"
        ));
    }

    // [unit->REQ-PAIR-3] --subnet and --create-new are mutually exclusive.
    #[test]
    fn pair_show_totp_subnet_and_create_new_conflict() {
        assert!(parse(&["spt", "pair", "show-totp", "--subnet", "a", "--create-new", "b"]).is_err());
    }

    fn store_with(names: &[&str]) -> SubnetStore {
        let mut s = SubnetStore::default();
        for n in names {
            s.create_subnet(n).expect("create");
        }
        s
    }

    // [unit->REQ-PAIR-3] a lone subnet is auto-selected with no flag; elevated, the
    // printed code matches TotpSeed computed from that subnet's stored seed.
    #[test]
    fn single_subnet_auto_selects_and_code_matches_seed() {
        let mut store = store_with(&["home"]);
        let seed = store.find("home").unwrap().seed_bytes().unwrap();
        let now = 1_111_111_109;
        let r = decide_show_totp(resolve(&mut store, None, None), now, Elevation::Elevated);
        assert_eq!(r.code, 0);
        let expected = TotpSeed::from_bytes(seed).code_at(now);
        let out = r.out.expect("elevated show prints the code");
        assert!(out.starts_with(&expected), "stdout starts with the code");
        assert!(out.contains("otpauth://"), "stdout carries the provisioning URI");
        assert!(!r.save, "an existing subnet is not re-persisted");
    }

    // [unit->REQ-PAIR-3] several subnets + no --subnet refuses (no guessing); naming
    // one resolves it.
    #[test]
    fn multi_subnet_refuses_without_flag_then_resolves_with_it() {
        let mut store = store_with(&["home", "work"]);
        let amb = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Elevated);
        assert_eq!(amb.code, 2);
        assert!(amb.out.is_none());
        assert!(amb.msg.contains("AMBIGUOUS_SUBNET"));

        let work_seed = store.find("work").unwrap().seed_bytes().unwrap();
        let now = 1_234_567_890;
        let r = decide_show_totp(
            resolve(&mut store, Some("work".into()), None),
            now,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 0);
        assert!(r.out.unwrap().starts_with(&TotpSeed::from_bytes(work_seed).code_at(now)));
    }

    // [unit->REQ-PAIR-3] --create-new on a fresh name mints + shows, and flags the
    // store for persistence (save = true) on the elevated path.
    #[test]
    fn create_new_mints_shows_and_requests_save() {
        let mut store = SubnetStore::default();
        let r = decide_show_totp(
            resolve(&mut store, None, Some("fresh".into())),
            42,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 0);
        assert!(r.save, "a freshly minted subnet must be persisted on show");
        assert!(r.out.unwrap().contains("otpauth://"));
        assert!(store.find("fresh").is_some(), "mint landed in the in-memory store");
    }

    // [unit->REQ-PAIR-3] --create-new for an existing name is a usage error.
    #[test]
    fn create_new_existing_name_is_usage_error() {
        let mut store = store_with(&["home"]);
        let r = decide_show_totp(
            resolve(&mut store, None, Some("home".into())),
            0,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 2);
        assert!(r.msg.contains("SUBNET_EXISTS"));
    }

    // [unit->REQ-PAIR-3] zero subnets + no flag points the user at pairing / --create-new.
    #[test]
    fn empty_store_no_flag_guides_to_pair_or_create() {
        let mut store = SubnetStore::default();
        let r = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Elevated);
        assert_eq!(r.code, 2);
        assert!(r.msg.contains("NO_SUBNETS"));
    }

    // [unit->REQ-PAIR-3] a named-but-absent subnet is a usage error.
    #[test]
    fn unknown_named_subnet_is_usage_error() {
        let mut store = store_with(&["home"]);
        let r = decide_show_totp(
            resolve(&mut store, Some("ghost".into()), None),
            0,
            Elevation::Elevated,
        );
        assert_eq!(r.code, 2);
        assert!(r.msg.contains("NO_SUCH_SUBNET:ghost"));
    }

    // [unit->REQ-PAIR-6] not elevated: the fetch is refused — distinct exit code, NO
    // code in stdout (no leak), fallback message names the authenticator app, and a
    // would-be --create-new mint is NOT persisted (refused = no durable side effect).
    #[test]
    fn not_elevated_refuses_without_leaking_code_or_saving() {
        let mut store = SubnetStore::default();
        let r = decide_show_totp(
            resolve(&mut store, None, Some("fresh".into())),
            0,
            Elevation::NotElevated,
        );
        assert_eq!(r.code, EXIT_NOT_ELEVATED);
        assert!(r.out.is_none(), "no code leaks on the refused path");
        assert!(r.msg.contains("authenticator app"));
        assert!(!r.save, "a refused fetch persists no mint");
    }

    // [unit->REQ-PAIR-6] an undeterminable elevation (Unknown) also falls back — the
    // same fail-safe path as NotElevated, never leaking the code.
    #[test]
    fn unknown_elevation_falls_back() {
        let mut store = store_with(&["home"]);
        let r = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Unknown);
        assert_eq!(r.code, EXIT_NOT_ELEVATED);
        assert!(r.out.is_none());
    }
}

+    // ── pair show-totp ─────────────────────────────────────────────────────────

+    fn show_totp(args: &[&str]) -> PairCmd {

+        match parse(args).unwrap().cmd {

+            Cmd::Pair { action } => action,

+            _ => panic!("expected Pair"),

+    // [unit->REQ-PAIR-3] the show-totp arg shapes parse: bare, --subnet, --create-new.

+    fn pair_show_totp_arg_shapes_parse() {

+            show_totp(&["spt", "pair", "show-totp"]),

+            PairCmd::ShowTotp { subnet: None, create_new: None }

+            show_totp(&["spt", "pair", "show-totp", "--subnet", "home"]),

+            PairCmd::ShowTotp { subnet: Some(s), .. } if s == "home"

+            show_totp(&["spt", "pair", "show-totp", "--create-new", "home"]),

+            PairCmd::ShowTotp { create_new: Some(s), .. } if s == "home"

+    // [unit->REQ-PAIR-3] --subnet and --create-new are mutually exclusive.

+    fn pair_show_totp_subnet_and_create_new_conflict() {

+        assert!(parse(&["spt", "pair", "show-totp", "--subnet", "a", "--create-new", "b"]).is_err());

+    fn store_with(names: &[&str]) -> SubnetStore {

+        let mut s = SubnetStore::default();

+            s.create_subnet(n).expect("create");

+    // [unit->REQ-PAIR-3] a lone subnet is auto-selected with no flag; elevated, the

+    // printed code matches TotpSeed computed from that subnet's stored seed.

+    fn single_subnet_auto_selects_and_code_matches_seed() {

+        let mut store = store_with(&["home"]);

+        let seed = store.find("home").unwrap().seed_bytes().unwrap();

+        let r = decide_show_totp(resolve(&mut store, None, None), now, Elevation::Elevated);

+        let expected = TotpSeed::from_bytes(seed).code_at(now);

+        let out = r.out.expect("elevated show prints the code");

+        assert!(out.starts_with(&expected), "stdout starts with the code");

+        assert!(out.contains("otpauth://"), "stdout carries the provisioning URI");

+        assert!(!r.save, "an existing subnet is not re-persisted");

+    // [unit->REQ-PAIR-3] several subnets + no --subnet refuses (no guessing); naming

+    fn multi_subnet_refuses_without_flag_then_resolves_with_it() {

+        let mut store = store_with(&["home", "work"]);

+        let amb = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Elevated);

+        assert!(amb.msg.contains("AMBIGUOUS_SUBNET"));

+        let work_seed = store.find("work").unwrap().seed_bytes().unwrap();

+            resolve(&mut store, Some("work".into()), None),

+        assert!(r.out.unwrap().starts_with(&TotpSeed::from_bytes(work_seed).code_at(now)));

+    // [unit->REQ-PAIR-3] --create-new on a fresh name mints + shows, and flags the

+    // store for persistence (save = true) on the elevated path.

+    fn create_new_mints_shows_and_requests_save() {

+        let mut store = SubnetStore::default();

+            resolve(&mut store, None, Some("fresh".into())),

+        assert!(r.save, "a freshly minted subnet must be persisted on show");

+        assert!(r.out.unwrap().contains("otpauth://"));

+        assert!(store.find("fresh").is_some(), "mint landed in the in-memory store");

+    // [unit->REQ-PAIR-3] --create-new for an existing name is a usage error.

+    fn create_new_existing_name_is_usage_error() {

+        let mut store = store_with(&["home"]);

+            resolve(&mut store, None, Some("home".into())),

+        assert!(r.msg.contains("SUBNET_EXISTS"));

+    // [unit->REQ-PAIR-3] zero subnets + no flag points the user at pairing / --create-new.

+    fn empty_store_no_flag_guides_to_pair_or_create() {

+        let r = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Elevated);

+        assert!(r.msg.contains("NO_SUBNETS"));

+    // [unit->REQ-PAIR-3] a named-but-absent subnet is a usage error.

+    fn unknown_named_subnet_is_usage_error() {

+            resolve(&mut store, Some("ghost".into()), None),

+        assert!(r.msg.contains("NO_SUCH_SUBNET:ghost"));

+    // [unit->REQ-PAIR-6] not elevated: the fetch is refused — distinct exit code, NO

+    // code in stdout (no leak), fallback message names the authenticator app, and a

+    // would-be --create-new mint is NOT persisted (refused = no durable side effect).

+    fn not_elevated_refuses_without_leaking_code_or_saving() {

+        let mut store = SubnetStore::default();

+        assert_eq!(r.code, EXIT_NOT_ELEVATED);

+        assert!(r.out.is_none(), "no code leaks on the refused path");

+        assert!(r.msg.contains("authenticator app"));

+        assert!(!r.save, "a refused fetch persists no mint");

+    // [unit->REQ-PAIR-6] an undeterminable elevation (Unknown) also falls back — the

+    // same fail-safe path as NotElevated, never leaking the code.

+    fn unknown_elevation_falls_back() {

+        let mut store = store_with(&["home"]);

+        let r = decide_show_totp(resolve(&mut store, None, None), 0, Elevation::Unknown);


Activate REQ-PAIR-3/6 in traceable-reqs.toml.


id = "REQ-PAIR-3"
title = "Fetch current pairing code from any paired node"
required_stages = []

id = "REQ-PAIR-3"
title = "Fetch current pairing code from any paired node"
required_stages = ["impl", "unit"]  # activated M4-D2g: `spt pair show-totp [--subnet <name>|--create-new <name>]` surfaces a subnet's current code + otpauth:// URI off this node (cli.rs decide_show_totp). Per-subnet resolution: single auto-selects, multi refuses without --subnet (no guessing), --create-new mints a sole-holder subnet (SubnetStore::create_subnet). Code reuses spt_net TotpSeed (matches the ceremony exactly), never reimplemented. unit = single/multi/create-new/empty/unknown resolution + code-matches-seed. The cross-node fetch (off a *remote* paired node over IPC) is D4/D5; int = two-host at D9.


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)

id = "REQ-PAIR-3"
title = "Fetch current pairing code from any paired node"
required_stages = []

id = "REQ-PAIR-3"
title = "Fetch current pairing code from any paired node"
required_stages = ["impl", "unit"]  # activated M4-D2g: `spt pair show-totp [--subnet <name>|--create-new <name>]` surfaces a subnet's current code + otpauth:// URI off this node (cli.rs decide_show_totp). Per-subnet resolution: single auto-selects, multi refuses without --subnet (no guessing), --create-new mints a sole-holder subnet (SubnetStore::create_subnet). Code reuses spt_net TotpSeed (matches the ceremony exactly), never reimplemented. unit = single/multi/create-new/empty/unknown resolution + code-matches-seed. The cross-node fetch (off a *remote* paired node over IPC) is D4/D5; int = two-host at D9.

+required_stages = ["impl", "unit"]  # activated M4-D2g: `spt pair show-totp [--subnet <name>|--create-new <name>]` surfaces a subnet's current code + otpauth:// URI off this node (cli.rs decide_show_totp). Per-subnet resolution: single auto-selects, multi refuses without --subnet (no guessing), --create-new mints a sole-holder subnet (SubnetStore::create_subnet). Code reuses spt_net TotpSeed (matches the ceremony exactly), never reimplemented. unit = single/multi/create-new/empty/unknown resolution + code-matches-seed. The cross-node fetch (off a *remote* paired node over IPC) is D4/D5; int = two-host at D9.

title = "Subnet naming on first pairing"


id = "REQ-PAIR-6"
title = "Elevation-gated per-subnet code fetch (UAC/root or elevated agent; else authenticator app)"
required_stages = []

id = "REQ-PAIR-6"
title = "Elevation-gated per-subnet code fetch (UAC/root or elevated agent; else authenticator app)"
required_stages = ["impl", "unit"]  # activated M4-D2g: elevation.rs probes OS privilege (Linux libc::geteuid()==0; Windows GetTokenInformation(TokenElevation) via windows-sys; cfg-split) — only the binary pulls OS deps. gate_for: Elevated => Show, NotElevated|Unknown => Fallback (fail safe, never leak the code unconfirmed). Refused fetch leaks no code, persists no mint, distinct exit 3, and the fallback names the authenticator app (seed provisioned there at pairing). unit = gate decision both ways + Unknown fallback + no-leak/no-save on refusal; the live OS probe is environment-dependent (manual verification via todlando / D9). The elevated-*agent*-endpoint path (IPC) is D4/D5, not D2g.


id = "REQ-PAIR-6"
title = "Elevation-gated per-subnet code fetch (UAC/root or elevated agent; else authenticator app)"
required_stages = []

id = "REQ-PAIR-6"
title = "Elevation-gated per-subnet code fetch (UAC/root or elevated agent; else authenticator app)"
required_stages = ["impl", "unit"]  # activated M4-D2g: elevation.rs probes OS privilege (Linux libc::geteuid()==0; Windows GetTokenInformation(TokenElevation) via windows-sys; cfg-split) — only the binary pulls OS deps. gate_for: Elevated => Show, NotElevated|Unknown => Fallback (fail safe, never leak the code unconfirmed). Refused fetch leaks no code, persists no mint, distinct exit 3, and the fallback names the authenticator app (seed provisioned there at pairing). unit = gate decision both ways + Unknown fallback + no-leak/no-save on refusal; the live OS probe is environment-dependent (manual verification via todlando / D9). The elevated-*agent*-endpoint path (IPC) is D4/D5, not D2g.

+required_stages = ["impl", "unit"]  # activated M4-D2g: elevation.rs probes OS privilege (Linux libc::geteuid()==0; Windows GetTokenInformation(TokenElevation) via windows-sys; cfg-split) — only the binary pulls OS deps. gate_for: Elevated => Show, NotElevated|Unknown => Fallback (fail safe, never leak the code unconfirmed). Refused fetch leaks no code, persists no mint, distinct exit 3, and the fallback names the authenticator app (seed provisioned there at pairing). unit = gate decision both ways + Unknown fallback + no-leak/no-save on refusal; the live OS probe is environment-dependent (manual verification via todlando / D9). The elevated-*agent*-endpoint path (IPC) is D4/D5, not D2g.

title = "Subnet icon (inline image metadata, GUI-only consumer)"


Now build + test the spt crate.


Bash

Build + test spt crate


test cli::tests::pair_show_totp_subnet_and_create_new_conflict ... ok
test api::reporting::tests::presence_records_endpoint ... ok
test cli::tests::ring_timeout_defaults ... ok
test cli::tests::send_target_optional_with_reply_to ... ok
test cli::tests::single_subnet_auto_selects_and_code_matches_seed ... ok
test cli::tests::unknown_elevation_falls_back ... ok
test cli::tests::unknown_named_subnet_is_usage_error ... ok
test elevation::tests::current_returns_a_determinate_level_on_supported_platforms ... ok
test elevation::tests::fallback_message_names_authenticator_app_and_subnet ... ok
test elevation::tests::gate_shows_only_when_confirmed_elevated ... ok
test cli::tests::subcommands_parse ... ok
test api::reporting::tests::session_end_erase_refused_with_live_children ... ok
test api::reporting::tests::session_end_erase_wipes_childless_perch ... ok
test api::reporting::tests::session_end_soft_preserves_state ... ok
test api::startup::tests::empty_session_seed_refused ... ok
test api::startup::tests::live_perch_under_other_session_conflicts ... ok
test api::startup::tests::missing_seed_refused ... ok
test api::startup::tests::post_spawn_bind_establishes_perch ... ok
test api::startup::tests::rebind_same_session_ok ... ok
test api::startup::tests::stale_seed_with_dead_anchor_refused ... ok
test api::startup::tests::valid_seed_binds_live_perch ... ok
test api::worker::tests::cascade_guard_tracks_live_children ... ok
test api::worker::tests::guard_clears_only_when_all_children_stopped ... ok
test api::worker::tests::worker_poll_drains_spool ... ok
test api::worker::tests::worker_start_nests_under_parent ... ok

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

     Running tests\contract_e2e.rs (target\debug\deps\contract_e2e-dc56d7e971b01164.exe)

running 4 tests
test cold_api_call_autostarts_daemon_and_handoff_is_in_memory ... ok
SEEDED:7116
test live_agent_lifecycle_e2e ... ok
test mock_adapter_drives_the_full_contract ... ok
SEEDED:7116
test seed_then_listen_binds_and_relays ... ok

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


All 54 pass (new pair + elevation tests included). spt-net/iroh dep compiled clean. Run traceable-reqs check + clippy.


echo "=== traceable-reqs check ===" && traceable-reqs check 2>&1 | tail -25

traceable-reqs evidence check


=== traceable-reqs check ===
       Harness-hosted startup: api seed then listen
  [OK] REQ-START-3  required: [impl, unit, int]  stages: -doc +impl +unit +int
       spt-hosted startup: spawn-session then api bind (no file)
  [OK] REQ-START-4  required: [impl, unit]  stages: -doc +impl +unit -int
       Adapter-injected env aliases (SPT/OWL/LIVE)
  [OK] REQ-STORE-1  required: []  stages: -doc -impl -unit -int
       spt-store::BranchStore (git branch as versioned KV; commit=checkpoint/tip=resume, atomic multi-key, merge-native sync) is the substrate for coarse/durable/audited state (context, registry snapshot+distribution, daemon checkpoint); hot paths (B5 fsync journal) + indexed queries (SQLite spool) excluded (ADR-0011)
  [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: []  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


echo "=== PAIR rows + summary ===" && traceable-reqs check 2>&1 | grep -E "REQ-PAIR-[36]|FAIL|MISSING|ERROR|Coverage|passed|✓|✗|exit" | head -20; echo "=== exit code ==="; traceable-reqs check >/dev/null 2>&1; echo $?

Check PAIR-3/6 coverage + exit code


=== PAIR rows + summary ===
       Ephemeral perch cleanup on every ring exit path (3.1)
       spt binary CLI surface: send/ring/ready/poll/list/stop/whoami, stable arg shapes + exit codes
  [OK] REQ-PAIR-3  required: [impl, unit]  stages: -doc +impl +unit -int
  [OK] REQ-PAIR-6  required: [impl, unit]  stages: -doc +impl +unit -int
=== exit code ===
0


traceable-reqs green (exit 0), PAIR-3/6 both [OK]. Windows `detect()` compiled on this host. Run clippy.


cargo clippy -p spt --all-targets 2>&1 | grep -E "warning|error" | head -30; echo "=== done ==="

Clippy on spt crate


=== done ===


Clippy clean. Update the stale subcommand lists in the cli.rs/main.rs headers (now include `pair`), and check CI on 72570d5 + any doc-gen drift gate.


echo "=== CI 72570d5 ===" && gh run list --limit 2 --json status,conclusion,headSha 2>/dev/null
echo "=== doc-gen / CLI-reference drift gate? ==="
grep -rln "send · ring\|send/ring/ready\|spt pair\|show-totp" docs/ 2>/dev/null | head
ls docs/ 2>/dev/null | head -30

CI status + doc drift surface


=== CI 72570d5 ===
[{"conclusion":"success","headSha":"72570d5c6e191afa75ade22787422ae8ebe7708a","status":"completed"},{"conclusion":"success","headSha":"452358d79c2238142e99956e32dc3ce340fcee1a","status":"completed"}]
=== doc-gen / CLI-reference drift gate? ===
docs/adr/0005-totp-seeded-spake2-node-pairing.md
docs/DOCS-STRATEGY.md
CONTEXT-MEMORY.md
DEFERRED.md
DOCS-STRATEGY.md
KNOWN-HAZARDS.md
MANIFEST.md
STORAGE.md
TRACEABILITY.md
adr
reviews
spikes


CI green on 72570d5 — precondition satisfied. No CI-gated CLI-reference doc to drift (the REQ-MSG-2 header lists are correctly scoped to messaging; `pair` is a separate req family). Commit.


git add -A && git status --short && echo "=== diffstat ===" && git diff --cached --stat

Stage + review changes


warning: in the working copy of 'Cargo.lock', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/Cargo.toml', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/cli.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/main.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'traceable-reqs.toml', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/elevation.rs', LF will be replaced by CRLF the next time Git touches it
M  Cargo.lock
M  crates/spt/Cargo.toml
M  crates/spt/src/cli.rs
A  crates/spt/src/elevation.rs
M  crates/spt/src/main.rs
M  traceable-reqs.toml
=== diffstat ===
 Cargo.lock                  |   3 +
 crates/spt/Cargo.toml       |  17 +++
 crates/spt/src/cli.rs       | 351 ++++++++++++++++++++++++++++++++++++++++++++
 crates/spt/src/elevation.rs | 155 +++++++++++++++++++
 crates/spt/src/main.rs      |   1 +
 traceable-reqs.toml         |   4 +-
 6 files changed, 529 insertions(+), 2 deletions(-)


Cargo.lock only +3 — iroh already locked (spt-net is an existing workspace member); just dependency edges. Commit.


git commit -m @'
feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)

The last D2 task: the local node-bound pairing-code fetch. `spt pair
show-totp [--subnet <name> | --create-new <name>]` surfaces a subnet''s
current 6-digit code + otpauth:// URI, gated behind OS privilege elevation.

- elevation.rs (REQ-PAIR-6): cfg-split OS probe — Linux libc::geteuid()==0,
  Windows GetTokenInformation(TokenElevation) via windows-sys. Unknown/
  unsupported => NotElevated (fail safe). Pure gate_for seam unit-tested both
  ways; the live probe is environment-dependent (manual verify via todlando).
  Only the binary pulls the OS deps; core stays dep-minimal.
- cli.rs (REQ-PAIR-3): resolve/decide_show_totp seam — single subnet auto-
  selects, multi refuses without --subnet (no guessing), --create-new mints a
  sole-holder subnet. Code reuses spt_net TotpSeed so it matches the ceremony
  exactly (never reimplemented); a refused fetch leaks no code and persists no
  mint, with a distinct exit 3.
- spt depends on spt-net (ADR-0002: net is default-on in the reference binary;
  iroh already locked, no new crates).

11 new unit tests; traceable-reqs check green. D2 complete (REQ-PAIR-1..6
all [impl,unit]). Next: D3 subnet registry.

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

Commit D2g


[dev-freeform fb201d6] @ feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)
 6 files changed, 529 insertions(+), 2 deletions(-)
 create mode 100644 crates/spt/src/elevation.rs


Commit message mangled — I used PowerShell here-string syntax in the Bash tool, so literal `@` leaked into subject/end. Check + fix with a file-based message.


git log -1 --format='%B' | head -30; echo "=== END ==="

Inspect commit message


@
feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)

The last D2 task: the local node-bound pairing-code fetch. `spt pair
show-totp [--subnet <name> | --create-new <name>]` surfaces a subnets
current 6-digit code + otpauth:// URI, gated behind OS privilege elevation.

- elevation.rs (REQ-PAIR-6): cfg-split OS probe — Linux libc::geteuid()==0,
  Windows GetTokenInformation(TokenElevation) via windows-sys. Unknown/
  unsupported => NotElevated (fail safe). Pure gate_for seam unit-tested both
  ways; the live probe is environment-dependent (manual verify via todlando).
  Only the binary pulls the OS deps; core stays dep-minimal.
- cli.rs (REQ-PAIR-3): resolve/decide_show_totp seam — single subnet auto-
  selects, multi refuses without --subnet (no guessing), --create-new mints a
  sole-holder subnet. Code reuses spt_net TotpSeed so it matches the ceremony
  exactly (never reimplemented); a refused fetch leaks no code and persists no
  mint, with a distinct exit 3.
- spt depends on spt-net (ADR-0002: net is default-on in the reference binary;
  iroh already locked, no new crates).

11 new unit tests; traceable-reqs check green. D2 complete (REQ-PAIR-1..6
all [impl,unit]). Next: D3 subnet registry.

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

=== END ===


Body intact; just stray `@` lines top/bottom. Amend via message file.


Write

feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)

The last D2 task: the local node-bound pairing-code fetch. `spt pair
show-totp [--subnet <name> | --create-new <name>]` surfaces a subnet's
current 6-digit code + otpauth:// URI, gated behind OS privilege elevation.

- elevation.rs (REQ-PAIR-6): cfg-split OS probe — Linux libc::geteuid()==0,
  Windows GetTokenInformation(TokenElevation) via windows-sys. Unknown/
  unsupported => NotElevated (fail safe). Pure gate_for seam unit-tested both
  ways; the live probe is environment-dependent (manual verify via todlando).
  Only the binary pulls the OS deps; core stays dep-minimal.
- cli.rs (REQ-PAIR-3): resolve/decide_show_totp seam — single subnet auto-
  selects, multi refuses without --subnet (no guessing), --create-new mints a
  sole-holder subnet. Code reuses spt_net TotpSeed so it matches the ceremony
  exactly (never reimplemented); a refused fetch leaks no code and persists no
  mint, with a distinct exit 3.
- spt depends on spt-net (ADR-0002: net is default-on in the reference binary;
  iroh already locked, no new crates).

11 new unit tests; traceable-reqs check green. D2 complete (REQ-PAIR-1..6
all [impl,unit]). Next: D3 subnet registry.

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


File created successfully at: C:\Users\decid\Documents\projects\spt-core\.git\COMMIT_D2G.txt (file state is current in your context — no need to Read it back)

feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)

The last D2 task: the local node-bound pairing-code fetch. `spt pair
show-totp [--subnet <name> | --create-new <name>]` surfaces a subnet's
current 6-digit code + otpauth:// URI, gated behind OS privilege elevation.

- elevation.rs (REQ-PAIR-6): cfg-split OS probe — Linux libc::geteuid()==0,
  Windows GetTokenInformation(TokenElevation) via windows-sys. Unknown/
  unsupported => NotElevated (fail safe). Pure gate_for seam unit-tested both
  ways; the live probe is environment-dependent (manual verify via todlando).
  Only the binary pulls the OS deps; core stays dep-minimal.
- cli.rs (REQ-PAIR-3): resolve/decide_show_totp seam — single subnet auto-
  selects, multi refuses without --subnet (no guessing), --create-new mints a
  sole-holder subnet. Code reuses spt_net TotpSeed so it matches the ceremony
  exactly (never reimplemented); a refused fetch leaks no code and persists no
  mint, with a distinct exit 3.
- spt depends on spt-net (ADR-0002: net is default-on in the reference binary;
  iroh already locked, no new crates).

11 new unit tests; traceable-reqs check green. D2 complete (REQ-PAIR-1..6
all [impl,unit]). Next: D3 subnet registry.

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


Bash

git commit --amend -F .git/COMMIT_D2G.txt && rm .git/COMMIT_D2G.txt && echo "=== subject ===" && git log -1 --format='%s'

Amend with clean message


[dev-freeform f2cb019] feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)
 Date: Wed Jun 3 15:00:04 2026 -0700
 6 files changed, 529 insertions(+), 2 deletions(-)
 create mode 100644 crates/spt/src/elevation.rs
=== subject ===
feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)


Clean: f2cb019. Push to trigger CI (the per-task green-gate workflow D2a–f followed).


git remote -v 2>/dev/null | head -2; echo "---push---"; git push 2>&1 | tail -15

Push to trigger CI


origin	https://github.com/SaberMage/spt-core.git (fetch)
origin	https://github.com/SaberMage/spt-core.git (push)
---push---
To https://github.com/SaberMage/spt-core.git
   72570d5..f2cb019  dev-freeform -> dev-freeform


Pushed f2cb019. Watch CI to green-gate D2g.


sleep 8; rid=$(gh run list --limit 1 --json databaseId --jq '.[0].databaseId' 2>/dev/null); echo "run=$rid"; gh run watch "$rid" --exit-status 2>&1 | tail -30

Watch CI run to completion


run=26915711984
  ✓ Install Rust (stable + clippy)
  ✓ Cache cargo
  ✓ Build
  ✓ Test
  ✓ Clippy (deny warnings)
  ✓ Post Cache cargo
  ✓ Post Run actions/checkout@v4
  ✓ Complete job
X test (ubuntu-latest) in 1m14s (ID 79404743053)
  ✓ Set up job
  ✓ Run actions/checkout@v4
  ✓ Install Rust (stable + clippy)
  ✓ Cache cargo
  ✓ Build
  ✓ Test
  X Clippy (deny warnings)
  - Post Cache cargo
  ✓ Post Run actions/checkout@v4
  ✓ Complete job

ANNOTATIONS
! Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected: actions/checkout@v4. Actions will be forced to run with Node.js 24 by default starting June 16th, 2026. Node.js 20 will be removed from the runner on September 16th, 2026. Please check if updated versions of these actions are available that support Node.js 24. To opt into Node.js 24 now, set the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true environment variable on the runner or in your workflow file. Once Node.js 24 becomes the default, you can temporarily opt out by setting ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
traceability: .github#2

! Node.js 20 actions are deprecated. The following actions are running on Node.js 20 and may not work as expected: actions/checkout@v4. Actions will be forced to run with Node.js 24 by default starting June 16th, 2026. Node.js 20 will be removed from the runner on September 16th, 2026. Please check if updated versions of these actions are available that support Node.js 24. To opt into Node.js 24 now, set the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true environment variable on the runner or in your workflow file. Once Node.js 24 becomes the default, you can temporarily opt out by setting ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
test (ubuntu-latest): .github#4

X Process completed with exit code 101.
test (ubuntu-latest): .github#35


CI red — Clippy on Linux (my local clippy only checked the Windows `cfg` branch; the `#[cfg(unix)]` path went unchecked). Get the error.


gh run view 26915711984 --log-failed 2>&1 | grep -iE "clippy|warning|error|geteuid|elevation|unix" | head -30

Extract Linux clippy failure


test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7908024Z ##[group]Run cargo clippy --workspace --all-targets -- -D warnings
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7908534Z cargo clippy --workspace --all-targets -- -D warnings
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7937365Z shell: /usr/bin/bash -e {0}
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7937815Z env:
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7938157Z   CARGO_HOME: /home/runner/.cargo
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7938609Z   CARGO_INCREMENTAL: 0
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7939007Z   CARGO_TERM_COLOR: always
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7939419Z   CACHE_ON_FAILURE: false
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:58.7939820Z ##[endgroup]
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:59.0952943Z     Checking spt-proto v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-proto)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:59.3835274Z     Checking spt-store v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-store)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:01:59.8626596Z     Checking spt-msg v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-msg)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:00.0026614Z     Checking spt-term v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-term)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:00.2441652Z     Checking spt-runtime v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-runtime)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:00.2805962Z     Checking spt-net v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-net)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:01.0608508Z     Checking spt-live v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-live)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:01.2296648Z     Checking spt-daemon v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt-daemon)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:02.2425859Z     Checking spt v0.0.0 (/home/runner/work/spt-core/spt-core/crates/spt)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:03.6395903Z     Checking mock-adapter v0.0.0 (/home/runner/work/spt-core/spt-core/adapters/mock)
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0046303Z error: variant `Unknown` is never constructed
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0065268Z   --> crates/spt/src/elevation.rs:29:5
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0075024Z    |
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0081142Z 22 | pub enum Elevation {
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0111959Z    |          --------- variant in this enum
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0112800Z ...
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0135326Z 29 |     Unknown,
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0165450Z    |     ^^^^^^^
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0180857Z    |
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0205952Z    = note: `Elevation` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
test (ubuntu-latest)	Clippy (deny warnings)	2026-06-03T22:02:04.0207547Z    = note: `-D dead-code` implied by `-D warnings`


`Elevation::Unknown` never constructed on Linux (geteuid can't fail; the Unknown-returning branches are `#[cfg(windows)]`/`cfg(not(any(unix,windows)))`). It's load-bearing on Windows/unsupported platforms — legit cross-platform variant. Allow dead_code on it with justification.


Edit

    /// Could not determine (unsupported platform, or the OS query failed). Treated as
    /// NOT elevated by [`gate_for`] — we never assume privilege we cannot confirm.
    Unknown,

    /// Could not determine (unsupported platform, or the OS query failed). Treated as
    /// NOT elevated by [`gate_for`] — we never assume privilege we cannot confirm.
    ///
    /// Constructed only on Windows (an `OpenProcessToken`/`GetTokenInformation`
    /// failure) and on unsupported platforms; on Unix `geteuid` cannot fail, so the
    /// variant is unreachable there. `allow(dead_code)` keeps the fail-safe arm in the
    /// cross-platform API without a per-target warning.
    #[allow(dead_code)]
    Unknown,


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

    /// Could not determine (unsupported platform, or the OS query failed). Treated as
    /// NOT elevated by [`gate_for`] — we never assume privilege we cannot confirm.
    ///
    /// Constructed only on Windows (an `OpenProcessToken`/`GetTokenInformation`
    /// failure) and on unsupported platforms; on Unix `geteuid` cannot fail, so the
    /// variant is unreachable there. `allow(dead_code)` keeps the fail-safe arm in the
    /// cross-platform API without a per-target warning.
    #[allow(dead_code)]
    Unknown,

//! OS privilege-elevation gate for the node-bound pairing-code fetch (REQ-PAIR-6).
//!
//! Surfacing a subnet's live TOTP code off a trusted node is the *privileged* fetch
//! path: it hands out subnet-joining authority, so the process must be elevated
//! (Windows UAC / Linux root-or-equivalent). When it is not, we refuse the node-bound
//! fetch and point the user at their authenticator app — where the same seed was
//! provisioned at pairing (the `otpauth://` URI), giving the code without privilege.
//!
//! ## Structure (a thin testable seam over an environment-dependent OS call)
//!
//! [`current`] is the only environment-dependent part: a `cfg`-split OS query that
//! cannot run hermetically in CI (the test process's real euid/token is whatever the
//! runner happens to be). So the *decision* — does this elevation level show the code
//! or fall back? — is factored into [`gate_for`], a pure function unit-tested both
//! ways. An unknown/unsupported platform maps to [`Elevation::Unknown`], which
//! [`gate_for`] treats as NOT elevated: **fail safe** — never leak the code when we
//! cannot positively confirm privilege.
// [impl->REQ-PAIR-6]

/// The process's OS privilege level, as far as we can positively determine it.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Elevation {
    /// Confirmed elevated: Windows token is elevated, or Unix euid == 0.
    Elevated,
    /// Confirmed NOT elevated.
    NotElevated,
    /// Could not determine (unsupported platform, or the OS query failed). Treated as
    /// NOT elevated by [`gate_for`] — we never assume privilege we cannot confirm.
    Unknown,
}

/// Whether the gated fetch may surface the code, or must fall back to the app.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Gate {
    /// Elevated — render the code + `otpauth://` URI.
    Show,
    /// Not elevated (or undeterminable) — refuse, point at the authenticator app.
    Fallback,
}

/// The pure gate decision (the testable seam). Only a *positively confirmed* elevation
/// shows the code; `NotElevated` and `Unknown` both fall back (fail safe).
// [impl->REQ-PAIR-6]
pub fn gate_for(elevation: Elevation) -> Gate {
    match elevation {
        Elevation::Elevated => Gate::Show,
        Elevation::NotElevated | Elevation::Unknown => Gate::Fallback,
    }
}

/// The fallback guidance shown when the fetch is refused. Names the authenticator app
/// explicitly (the seed was provisioned there at pairing via the `otpauth://` URI), so
/// the user has an unprivileged path to the same code.
pub fn fallback_message(subnet: &str) -> String {
    format!(
        "ELEVATION_REQUIRED: showing the code for subnet '{subnet}' off this node needs an \
         elevated process (run as administrator / root). Without elevation, read the current \
         code from your authenticator app instead — the seed was provisioned there at pairing."
    )
}

/// Query the OS for this process's elevation level. `cfg`-split; an unsupported
/// platform or a failed OS call returns [`Elevation::Unknown`] (→ fail safe).
// [impl->REQ-PAIR-6]
pub fn current() -> Elevation {
    detect()
}

#[cfg(unix)]
fn detect() -> Elevation {
    // Root (euid 0) is the Unix "elevated" equivalent. `geteuid` cannot fail.
    if unsafe { libc::geteuid() } == 0 {
        Elevation::Elevated
    } else {
        Elevation::NotElevated
    }
}

#[cfg(windows)]
fn detect() -> Elevation {
    use core::ffi::c_void;
    use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
    use windows_sys::Win32::Security::{
        GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY,
    };
    use windows_sys::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};

    // Open the current process token, query TokenElevation. Any failure → Unknown
    // (fail safe). GetCurrentProcess returns a pseudo-handle we must NOT close; only
    // the opened token handle is released.
    unsafe {
        let mut token: HANDLE = std::ptr::null_mut();
        if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token) == 0 {
            return Elevation::Unknown;
        }
        let mut info = TOKEN_ELEVATION { TokenIsElevated: 0 };
        let mut ret_len: u32 = 0;
        let ok = GetTokenInformation(
            token,
            TokenElevation,
            &mut info as *mut _ as *mut c_void,
            std::mem::size_of::<TOKEN_ELEVATION>() as u32,
            &mut ret_len,
        );
        CloseHandle(token);
        if ok == 0 {
            Elevation::Unknown
        } else if info.TokenIsElevated != 0 {
            Elevation::Elevated
        } else {
            Elevation::NotElevated
        }
    }
}

#[cfg(not(any(unix, windows)))]
fn detect() -> Elevation {
    // Unsupported platform: we cannot confirm privilege, so refuse to assume it.
    Elevation::Unknown
}

#[cfg(test)]
mod tests {
    use super::*;

    // [unit->REQ-PAIR-6] only confirmed elevation shows the code; NotElevated AND the
    // undeterminable Unknown both fall back (fail safe — no code without proof).
    #[test]
    fn gate_shows_only_when_confirmed_elevated() {
        assert_eq!(gate_for(Elevation::Elevated), Gate::Show);
        assert_eq!(gate_for(Elevation::NotElevated), Gate::Fallback);
        assert_eq!(gate_for(Elevation::Unknown), Gate::Fallback);
    }

    // [unit->REQ-PAIR-6] the fallback names the authenticator app (the unprivileged
    // path to the same code) and the subnet it concerns.
    #[test]
    fn fallback_message_names_authenticator_app_and_subnet() {
        let msg = fallback_message("home fleet");
        assert!(msg.contains("authenticator app"));
        assert!(msg.contains("home fleet"));
    }

    // The live OS probe is environment-dependent (the test runner's own privilege), so
    // we only assert it returns a determinate value here on the supported platforms —
    // the show/fallback *decision* is covered hermetically via `gate_for` above. Real
    // elevated-vs-not end-to-end verification is manual (todlando / D9).
    #[test]
    fn current_returns_a_determinate_level_on_supported_platforms() {
        let e = current();
        if cfg!(any(unix, windows)) {
            assert!(matches!(e, Elevation::Elevated | Elevation::NotElevated));
        }
    }
}

+    /// Constructed only on Windows (an `OpenProcessToken`/`GetTokenInformation`

+    /// failure) and on unsupported platforms; on Unix `geteuid` cannot fail, so the

+    /// variant is unreachable there. `allow(dead_code)` keeps the fail-safe arm in the

+    /// cross-platform API without a per-target warning.


Verify locally (Windows clippy still green with the attribute), then amend-commit and re-push.


Bash

cargo clippy -p spt --all-targets 2>&1 | grep -E "warning|error" | head; echo "=== local clippy done ===" && cargo test -p spt --lib 2>&1 | tail -3

Local clippy + lib tests after fix


=== local clippy done ===
error: no library targets found in package `spt`


Run bin unit tests


test api::worker::tests::worker_start_nests_under_parent ... ok

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


Make it a new commit (no force-push — f2cb019 already pushed). Commit the clippy fix.


git add -A && git commit -F - <<'MSG'
fix(net): silence D2g Elevation::Unknown dead_code on unix

clippy -D warnings (Linux) flagged `Elevation::Unknown` as never
constructed: on Unix `geteuid` cannot fail, so the variant is only built
on Windows (token-query failure) and unsupported platforms. It is a
load-bearing fail-safe arm of the cross-platform API, so allow(dead_code)
on the variant rather than removing it.

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

Commit clippy fix


warning: in the working copy of 'crates/spt/src/elevation.rs', LF will be replaced by CRLF the next time Git touches it
[dev-freeform a82446f] fix(net): silence D2g Elevation::Unknown dead_code on unix
 1 file changed, 6 insertions(+)
a82446f fix(net): silence D2g Elevation::Unknown dead_code on unix
f2cb019 feat(net): M4-D2g elevation-gated `spt pair show-totp` (REQ-PAIR-3/6)


git push 2>&1 | tail -3 && sleep 10 && rid=$(gh run list --limit 1 --json databaseId --jq '.[0].databaseId'); echo "run=$rid"; gh run watch "$rid" --exit-status 2>&1 | grep -vE "Node.js 20|github.blog|deprecat" | tail -25

Push + watch CI


To https://github.com/SaberMage/spt-core.git
   f2cb019..a82446f  dev-freeform -> dev-freeform
run=26916015978
  ✓ Post Run actions/checkout@v4
  ✓ Complete job
✓ test (ubuntu-latest) in 1m43s (ID 79405726802)
  ✓ Set up job
  ✓ Run actions/checkout@v4
  ✓ Install Rust (stable + clippy)
  ✓ Cache cargo
  ✓ Build
  ✓ Test
  ✓ Clippy (deny warnings)
  ✓ Post Cache cargo
  ✓ Post Run actions/checkout@v4
  ✓ Complete job
✓ traceability in 7s (ID 79405726866)
  ✓ Set up job
  ✓ Run actions/checkout@v4
  ✓ Install traceable-reqs
  ✓ Coverage gate (hard — fails PR on uncovered activated req)
  ✓ Quality audit (advisory)
  ✓ Post Run actions/checkout@v4
  ✓ Complete job

ANNOTATIONS
traceability: .github#2


CI green on a82446f — both `test` and `traceability` jobs pass. **D2g shipped. D2 complete** (REQ-PAIR-1..6 all `[impl,unit]`).

Commune the milestone status to Psyche.


Write

## D2g shipped — D2 COMPLETE

**Done (CI-green at a82446f):** M4-D2g elevation-gated `spt pair show-totp`.
- REQ-PAIR-3/6 now `[impl,unit]`. traceable-reqs green.
- `crates/spt/src/elevation.rs`: cfg-split OS probe (Linux `libc::geteuid()==0`;
  Windows `GetTokenInformation(TokenElevation)` via **windows-sys 0.59** — matched
  the codebase's existing windows-sys/libc usage, NOT the heavy `windows` crate the
  plan named). Pure `gate_for` seam unit-tested both ways; Unknown→Fallback fail-safe.
- `cli.rs`: `pair show-totp [--subnet <name>|--create-new <name>]` + `resolve`/
  `decide_show_totp` seam. Single auto-selects, multi refuses w/o `--subnet`,
  `--create-new` mints. Refused (not-elevated) leaks no code + persists no mint, exit 3.
- **Decision:** added `spt-net` as a dep of the `spt` binary to reuse `TotpSeed`
  (so the CLI code matches the ceremony exactly — never reimplemented). Justified by
  ADR-0002: net is default-on in the *reference binary*, which `spt` is. iroh already
  locked → no new crates. NOT debt.
- Two CI iterations: first red on Linux clippy (`Elevation::Unknown` dead on unix —
  geteuid can't fail); fixed with `#[allow(dead_code)]` on the variant (load-bearing
  on Windows/unsupported). Lesson: local Windows clippy can't see the `#[cfg(unix)]`
  arm — cfg-split code needs the cross-platform CI pass.

**Next:** D3 subnet registry (REQ-INST-7,9..13 + REQ-HAZARD-REGISTRY-EPOCH-LEASE #8) —
M4-PLAN D3a–f. Fresh milestone; needs its own JIT plan before impl.


File created successfully at: C:\Users\decid\Documents\projects\spt-core\.claude\doyle-commune.md (file state is current in your context — no need to Read it back)

## D2g shipped — D2 COMPLETE

**Done (CI-green at a82446f):** M4-D2g elevation-gated `spt pair show-totp`.
- REQ-PAIR-3/6 now `[impl,unit]`. traceable-reqs green.
- `crates/spt/src/elevation.rs`: cfg-split OS probe (Linux `libc::geteuid()==0`;
  Windows `GetTokenInformation(TokenElevation)` via **windows-sys 0.59** — matched
  the codebase's existing windows-sys/libc usage, NOT the heavy `windows` crate the
  plan named). Pure `gate_for` seam unit-tested both ways; Unknown→Fallback fail-safe.
- `cli.rs`: `pair show-totp [--subnet <name>|--create-new <name>]` + `resolve`/
  `decide_show_totp` seam. Single auto-selects, multi refuses w/o `--subnet`,
  `--create-new` mints. Refused (not-elevated) leaks no code + persists no mint, exit 3.
- **Decision:** added `spt-net` as a dep of the `spt` binary to reuse `TotpSeed`
  (so the CLI code matches the ceremony exactly — never reimplemented). Justified by
  ADR-0002: net is default-on in the *reference binary*, which `spt` is. iroh already
  locked → no new crates. NOT debt.
- Two CI iterations: first red on Linux clippy (`Elevation::Unknown` dead on unix —
  geteuid can't fail); fixed with `#[allow(dead_code)]` on the variant (load-bearing
  on Windows/unsupported). Lesson: local Windows clippy can't see the `#[cfg(unix)]`
  arm — cfg-split code needs the cross-platform CI pass.

**Next:** D3 subnet registry (REQ-INST-7,9..13 + REQ-HAZARD-REGISTRY-EPOCH-LEASE #8) —
M4-PLAN D3a–f. Fresh milestone; needs its own JIT plan before impl.


Commune dropped (Psyche ingests + deletes). Done.

## D2g shipped — D2 complete ✅

**CI green at `a82446f`** (test ubuntu + traceability both pass).

**Built — `spt pair show-totp [--subnet <name>|--create-new <name>]`:**
- `elevation.rs` (REQ-PAIR-6): cfg-split OS probe. Linux `libc::geteuid()==0`; Windows `GetTokenInformation(TokenElevation)`. Pure `gate_for` seam, fail-safe `Unknown→Fallback`. Used **windows-sys 0.59** (codebase convention) not the heavy `windows` crate the plan named.
- `cli.rs` (REQ-PAIR-3): `resolve`/`decide_show_totp` seam. Single subnet auto-selects, multi refuses without `--subnet` (no guessing), `--create-new` mints. Refused fetch leaks no code + persists no mint, distinct exit 3.
- **11 new unit tests; traceable-reqs green.** REQ-PAIR-3/6 → `[impl,unit]`.

**Decision made:** added `spt-net` dep to the `spt` binary to reuse `TotpSeed` — CLI code matches the ceremony exactly, never reimplemented. Justified by ADR-0002 (net default-on in the *reference binary*, which `spt` is). iroh already locked → no new crates. Not debt.

**One CI bounce:** first push red on Linux clippy — `Elevation::Unknown` dead on unix (`geteuid` can't fail). Local Windows clippy couldn't see the `#[cfg(unix)]` arm. Fixed with `#[allow(dead_code)]` on the load-bearing variant.

**D2 done** — REQ-PAIR-1..6 all `[impl,unit]`.

**Next:** D3 subnet registry (REQ-INST-7,9..13 + REQ-HAZARD-REGISTRY-EPOCH-LEASE #8). Fresh milestone — wants its own JIT plan before impl. Say the word and I'll plan D3.


proceed with D3


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


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


D3 = subnet registry. Need JIT plan first. Gather M4-PLAN D3 section + REQ-INST-7,9..13 + REQ-HAZARD-REGISTRY-EPOCH-LEASE + ADR-0006.


Bash

echo "=== M4-PLAN files ===" && ls M4*.md 2>/dev/null
echo "=== D3 section in M4-PLAN ==="
grep -n "D3\|registry\|Registry\|REGISTRY" M4-PLAN.md 2>/dev/null | head -40

Locate M4 plan + D3 section


=== M4-PLAN files ===
M4-D2-WIRE-PLAN.md
M4-D2f-PLAN.md
M4-D2g-PLAN.md
M4-PLAN.md
=== D3 section in M4-PLAN ===
19:pairing + the eventually-consistent subnet registry) and the multi-instance model
31:- **Subnet registry** — eventually-consistent `endpoint_id → [instances]` + resolution
61:Copy-verbatim only the sister's stable wire/registry **formats** that survive (ADR-0001);
74:**Sequencing.** D0→D1 are the transport floor. D2 (pairing) and D3 (registry) both sit on
75:D1 and can interleave, but D3's cross-node resolution wants D2's trust material to be real,
77:streams). D6 (Psyche sync) needs D3's per-subnet distribution. D8 (notif) reuses D3+D6
119:### D3 — Subnet registry + resolution policy
120:- **D3a** Per-subnet eventually-consistent registry `endpoint_id → [instances]` with
122:- **D3b** **Registry lease/epoch via monotonic per-node epochs** (NOT wall-clock) so
125:- **D3c** Resolution policy: local → most-recently-active → explicit `id@node`. Qualified
128:- **D3d** Multi-subnet membership (one node holds N trust-contexts/seeds; same-user only,
130:- **D3e** Endpoint visibility per-`(endpoint,subnet)`: excluded = not advertised AND not
132:- **D3f** `spt rename <id> <new_id>` rippled to all instances (registry, every perch,
134:- **Reqs:** REQ-INST-7,9,10,11,12,13. **New hazard req (rule 3):** `REQ-HAZARD-REGISTRY-EPOCH-LEASE` (#8).
145:  fault-injection acceptance matrix (crash/hang Iroh, mDNS, registry, PTY broker independently).
172:  version vector gives both cheaply and **unifies with D3b's epoch-lease (#8)** — one
173:  per-node monotonic epoch source serves registry leases *and* sync precedence. Wall-clock
212:  replicated spool (reuses D3 distribution), subnet-tagged, dismiss-state replicates
242:| D3 | REQ-INST-7,9,10,11,12,13 + `REQ-HAZARD-REGISTRY-EPOCH-LEASE` |
261:| #8 ambiguous resolution under skew | 0003 | D3 | monotonic per-node epoch lease + chaos test |


119	### D3 — Subnet registry + resolution policy
120	- **D3a** Per-subnet eventually-consistent registry `endpoint_id → [instances]` with
121	  status active/dormant/offline. · **REQ-INST-7**
122	- **D3b** **Registry lease/epoch via monotonic per-node epochs** (NOT wall-clock) so
123	  active/dormant transitions + partitions don't route to the wrong instance (red-team **#8**).
124	  Chaos-test stale entries + ambiguous active instance.
125	- **D3c** Resolution policy: local → most-recently-active → explicit `id@node`. Qualified
126	  addressing `[subnet:]id[@node]`; **ambiguity across visible subnets refuses + forces
127	  qualification** (no guessing). · **REQ-INST-10**
128	- **D3d** Multi-subnet membership (one node holds N trust-contexts/seeds; same-user only,
129	  cross-user seam shaped). Join-time bare-id collision check. · **REQ-INST-9**
130	- **D3e** Endpoint visibility per-`(endpoint,subnet)`: excluded = not advertised AND not
131	  routable; OR-of-defaults + per-`(E,S)` override; **visibility gates sync**. · **REQ-INST-12, REQ-INST-13**
132	- **D3f** `spt rename <id> <new_id>` rippled to all instances (registry, every perch,
133	  `a-<id>` context branch), collision-checked per target subnet, 6.5-reconciled. · **REQ-INST-11**
134	- **Reqs:** REQ-INST-7,9,10,11,12,13. **New hazard req (rule 3):** `REQ-HAZARD-REGISTRY-EPOCH-LEASE` (#8).
135	- **Acceptance:** an `endpoint_id` resolves to a live instance across nodes; ambiguous id refuses.
136
137	### D4 — QUIC-stream broker ownership (impl Spike #3 shape)
138	- **D4a** Move the Iroh endpoint + live QUIC streams into the **stable broker** per ADR-0004

### D3 — Subnet registry + resolution policy
- **D3a** Per-subnet eventually-consistent registry `endpoint_id → [instances]` with
  status active/dormant/offline. · **REQ-INST-7**
- **D3b** **Registry lease/epoch via monotonic per-node epochs** (NOT wall-clock) so
  active/dormant transitions + partitions don't route to the wrong instance (red-team **#8**).
  Chaos-test stale entries + ambiguous active instance.
- **D3c** Resolution policy: local → most-recently-active → explicit `id@node`. Qualified
  addressing `[subnet:]id[@node]`; **ambiguity across visible subnets refuses + forces
  qualification** (no guessing). · **REQ-INST-10**
- **D3d** Multi-subnet membership (one node holds N trust-contexts/seeds; same-user only,
  cross-user seam shaped). Join-time bare-id collision check. · **REQ-INST-9**
- **D3e** Endpoint visibility per-`(endpoint,subnet)`: excluded = not advertised AND not
  routable; OR-of-defaults + per-`(E,S)` override; **visibility gates sync**. · **REQ-INST-12, REQ-INST-13**
- **D3f** `spt rename <id> <new_id>` rippled to all instances (registry, every perch,
  `a-<id>` context branch), collision-checked per target subnet, 6.5-reconciled. · **REQ-INST-11**
- **Reqs:** REQ-INST-7,9,10,11,12,13. **New hazard req (rule 3):** `REQ-HAZARD-REGISTRY-EPOCH-LEASE` (#8).
- **Acceptance:** an `endpoint_id` resolves to a live instance across nodes; ambiguous id refuses.

### D4 — QUIC-stream broker ownership (impl Spike #3 shape)
- **D4a** Move the Iroh endpoint + live QUIC streams into the **stable broker** per ADR-0004


Read REQ-INST entries, ADR-0006, + scout existing registry/instance code.


echo "=== REQ-INST-7,9-13 ===" && grep -n "REQ-INST-7\|REQ-INST-9\|REQ-INST-10\|REQ-INST-11\|REQ-INST-12\|REQ-INST-13\|REQ-HAZARD-REGISTRY" traceable-reqs.toml
echo "=== ADR-0006 file ==="
ls docs/adr/ | grep -i "0006\|registry\|subnet"
echo "=== existing registry/instance code ==="
grep -rln "endpoint_id\|InstanceRegistry\|registry\|Instance\b\|active.*dormant\|epoch" crates/spt-net/src crates/spt-store/src 2>/dev/null | head

REQ-INST entries + ADR-0006 + existing code scout


=== REQ-INST-7,9-13 ===
186:id = "REQ-INST-7"
195:id = "REQ-INST-9"
199:id = "REQ-INST-10"
203:id = "REQ-INST-11"
207:id = "REQ-INST-12"
211:id = "REQ-INST-13"
472:id = "REQ-HAZARD-REGISTRY-STALE-CLEAN"
476:id = "REQ-HAZARD-REGISTRY-CONCURRENT"
=== ADR-0006 file ===
0006-multi-subnet-membership-model.md
0007-subnet-notification-primitive.md
0010-immutable-home-subnet-fork-not-rehome.md
=== existing registry/instance code ===
crates/spt-net/src/lib.rs
crates/spt-net/src/net/endpoint.rs
crates/spt-net/src/net/pairing/rendezvous.rs
crates/spt-net/src/net/pairing/spake.rs
crates/spt-net/src/net/pairing/totp.rs
crates/spt-net/src/net/pairing/transcript.rs
crates/spt-net/src/net/pairing/wire.rs
crates/spt-net/src/net/pairing.rs
crates/spt-net/src/net.rs
crates/spt-store/src/atomic.rs


184	required_stages = []
185	[[requirements]]
186	id = "REQ-INST-7"
187	title = "Subnet registry + bare-id resolution policy"
188	required_stages = []
189	[[requirements]]
190	id = "REQ-INST-8"
191	title = "Remote-control mode distinct from local operation"
192	required_stages = []
193	# ── Multi-subnet membership model (ADR-0006, 2026-06-01; activate M4) ──
194	[[requirements]]
195	id = "REQ-INST-9"
196	title = "Multi-subnet membership (same-user N subnets; cross-user seam)"
197	required_stages = []
198	[[requirements]]
199	id = "REQ-INST-10"
200	title = "Qualified addressing [subnet:]id[@node] + ambiguity forces qualification"
201	required_stages = []
202	[[requirements]]
203	id = "REQ-INST-11"
204	title = "spt rename <id> rippled to all instances (collision-checked, 6.5-reconciled)"
205	required_stages = []
206	[[requirements]]
207	id = "REQ-INST-12"
208	title = "Endpoint visibility per-(endpoint,subnet): excluded semantics, OR-of-defaults + override, gates sync"
209	required_stages = []
210	[[requirements]]
211	id = "REQ-INST-13"
212	title = "Subnet-exclusive sync + per-endpoint subnet-membership list"
213	required_stages = []
214	[[requirements]]
215	id = "REQ-INST-14"
216	title = "Resource advertisement (subnet resource registry): free-text blurb, both-authored, registry projection, visibility/whitelist-gated"
217	required_stages = []
218	[[requirements]]

required_stages = []
[[requirements]]
id = "REQ-INST-7"
title = "Subnet registry + bare-id resolution policy"
required_stages = []
[[requirements]]
id = "REQ-INST-8"
title = "Remote-control mode distinct from local operation"
required_stages = []
# ── Multi-subnet membership model (ADR-0006, 2026-06-01; activate M4) ──
[[requirements]]
id = "REQ-INST-9"
title = "Multi-subnet membership (same-user N subnets; cross-user seam)"
required_stages = []
[[requirements]]
id = "REQ-INST-10"
title = "Qualified addressing [subnet:]id[@node] + ambiguity forces qualification"
required_stages = []
[[requirements]]
id = "REQ-INST-11"
title = "spt rename <id> rippled to all instances (collision-checked, 6.5-reconciled)"
required_stages = []
[[requirements]]
id = "REQ-INST-12"
title = "Endpoint visibility per-(endpoint,subnet): excluded semantics, OR-of-defaults + override, gates sync"
required_stages = []
[[requirements]]
id = "REQ-INST-13"
title = "Subnet-exclusive sync + per-endpoint subnet-membership list"
required_stages = []
[[requirements]]
id = "REQ-INST-14"
title = "Resource advertisement (subnet resource registry): free-text blurb, both-authored, registry projection, visibility/whitelist-gated"
required_stages = []
[[requirements]]