    /// `CreateProcessWithTokenW` under the same flags as
    /// `detached_no_inherit`, command line quoted by the shared
    /// [`quote_windows_arg`] rules. Environment NULL = inherit ours — same
    /// user profile either way on Windows (elevation never changes the
    /// user), so `SPT_HOME`/`LOCALAPPDATA` resolve identically.
    fn create_with_token(token: isize, program: &str, args: &[String]) -> io::Result<u32> {
        use std::os::windows::ffi::OsStrExt;

        let mut cmdline = String::new();
        quote_windows_arg(&mut cmdline, program);
        for a in args {
            cmdline.push(' ');
            quote_windows_arg(&mut cmdline, a);
        }
        let mut cmdline_w: Vec<u16> =
            std::ffi::OsStr::new(&cmdline).encode_wide().chain(std::iter::once(0)).collect();
        let mut si: StartupInfoW = unsafe { std::mem::zeroed() };
        si.cb = std::mem::size_of::<StartupInfoW>() as u32;
        let mut pi: ProcessInformation = unsafe { std::mem::zeroed() };
        let ok = unsafe {
            CreateProcessWithTokenW(
                token,
                0, // no LOGON_WITH_PROFILE: same session, profile already loaded
                std::ptr::null(),
                cmdline_w.as_mut_ptr(),
                FLAGS,
                std::ptr::null_mut(),
                std::ptr::null(),
                &mut si,
                &mut pi,
            )
        };
        if ok == 0 {
            return Err(io::Error::last_os_error());
        }
        unsafe {
            CloseHandle(pi.process);
            CloseHandle(pi.thread);
        }
        Ok(pi.pid)
    }

    /// `CreateProcessWithTokenW` under the same flags as
    /// `detached_no_inherit`, command line quoted by the shared
    /// [`quote_windows_arg`] rules. The environment is BUILT FOR THE TOKEN
    /// (`CreateEnvironmentBlock`) — inheriting the elevated caller's
    /// variables would point the child at the wrong `%LOCALAPPDATA%`
    /// universe when UAC elevated through a different admin account. A
    /// failed block build falls back to inheriting ours (same-account
    /// elevation resolves identically there).
    fn create_with_token(token: isize, program: &str, args: &[String]) -> io::Result<u32> {
        use std::os::windows::ffi::OsStrExt;

        let mut cmdline = String::new();
        quote_windows_arg(&mut cmdline, program);
        for a in args {
            cmdline.push(' ');
            quote_windows_arg(&mut cmdline, a);
        }
        let mut cmdline_w: Vec<u16> =
            std::ffi::OsStr::new(&cmdline).encode_wide().chain(std::iter::once(0)).collect();
        let mut si: StartupInfoW = unsafe { std::mem::zeroed() };
        si.cb = std::mem::size_of::<StartupInfoW>() as u32;
        let mut pi: ProcessInformation = unsafe { std::mem::zeroed() };
        let mut env: *mut core::ffi::c_void = std::ptr::null_mut();
        let env_built = unsafe { CreateEnvironmentBlock(&mut env, token, 0) != 0 };
        let ok = unsafe {
            CreateProcessWithTokenW(
                token,
                1, // LOGON_WITH_PROFILE: the desktop user's profile (usually loaded; cheap then)
                std::ptr::null(),
                cmdline_w.as_mut_ptr(),
                FLAGS,
                if env_built { env } else { std::ptr::null_mut() },
                std::ptr::null(),
                &mut si,
                &mut pi,
            )
        };
        let err = io::Error::last_os_error();
        if env_built {
            unsafe { DestroyEnvironmentBlock(env) };
        }
        if ok == 0 {
            return Err(err);
        }
        unsafe {
            CloseHandle(pi.process);
            CloseHandle(pi.thread);
        }
        Ok(pi.pid)
    }

-    /// [`quote_windows_arg`] rules. Environment NULL = inherit ours — same

-    /// user profile either way on Windows (elevation never changes the

-    /// user), so `SPT_HOME`/`LOCALAPPDATA` resolve identically.

+    /// [`quote_windows_arg`] rules. The environment is BUILT FOR THE TOKEN

+    /// (`CreateEnvironmentBlock`) — inheriting the elevated caller's

+    /// variables would point the child at the wrong `%LOCALAPPDATA%`

+    /// universe when UAC elevated through a different admin account. A

+    /// failed block build falls back to inheriting ours (same-account

+    /// elevation resolves identically there).

+        let mut env: *mut core::ffi::c_void = std::ptr::null_mut();

+        let env_built = unsafe { CreateEnvironmentBlock(&mut env, token, 0) != 0 };

-                0, // no LOGON_WITH_PROFILE: same session, profile already loaded

+                1, // LOGON_WITH_PROFILE: the desktop user's profile (usually loaded; cheap then)

+                if env_built { env } else { std::ptr::null_mut() },

+        let err = io::Error::last_os_error();

+            unsafe { DestroyEnvironmentBlock(env) };

-            return Err(io::Error::last_os_error());


Bash

cd C:/Users/decid/Documents/projects/spt-core && cargo test -p spt-daemon --lib deelevate 2>&1 | tail -3 && cargo clippy -p spt-daemon 2>&1 | grep -E "^(warning|error)" | head -5; cargo build --release -p spt 2>&1 | tail -1

Test + clippy + release build shell-token fix


Command running in background with ID: bql2wrcit. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bql2wrcit.output. You will be notified when it completes. To check interim output, use Read on that file path.


PowerShell

Get-Process spt -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Id) start=$($_.StartTime) path=$($_.Path)" }

List all spt processes


69560 start=06/06/2026 06:04:28 path=


<task-notification>
<task-id>bql2wrcit</task-id>
<tool-use-id>toolu_018bZQxNZJXn28xeTm6B8NJV</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bql2wrcit.output</output-file>
<status>completed</status>
<summary>Background command "Test + clippy + release build shell-token fix" completed (exit code 0)</summary>
</task-notification>


ScheduleWakeup

fallback while shell-token fix builds (task bql2wrcit); primary signal is its notification

Prompt: Shell-token de-elevation fix was building (task bql2wrcit). When done: verify tests/clippy clean, commit+push (fix(daemon): shell-token de-elevation — linked token fails 1346 without TCB; env block for cross-account UAC), swap HFENDULEAM binary + restart daemon + lea, deploy gravity per memory procedure, then ask user to re-run elevated subnet create to verify DEELEVATED spawn, and give them elevated-PS cleanup commands for stray admin-universe daemon 69560 + admin LOCALAPPDATA\spt-core dir.


Next wakeup scheduled for 06:19:00 (in 611s). Nothing more to do this turn — the harness re-invokes you when the wakeup fires or a task-notification arrives.


Prompt:
<task-notification>
<task-id>bql2wrcit</task-id>
<tool-use-id>toolu_018bZQxNZJXn28xeTm6B8NJV</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bql2wrcit.output</output-file>
<status>completed</status>
<summary>Background command "Test + clippy + release build shell-token fix" completed (exit code 0)</summary>
</task-notification>


Proceed with bug root cause analysis and fixes


Bash

Build/test/clippy result


test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 180 filtered out; finished in 0.00s

    Finished `release` profile [optimized] target(s) in 15.51s


Green. Commit + push + redeploy both:


cd C:/Users/decid/Documents/projects/spt-core && git add crates/spt-daemon/src/deelevate.rs && git commit -m "fix(daemon): de-elevate via the desktop SHELL token — linked token fails 1346

Live elevated verification (M7 closeout, 2026-06-06) hit
ERROR_BAD_IMPERSONATION_LEVEL: without SeTcbPrivilege the UAC linked
token comes back at IDENTIFICATION level and can never become a primary
token, so CreateProcessWithTokenW refuses — the linked-token approach
cannot work for a normal elevated admin. Replaced with the shell-window
token (GetShellWindow → explorer's process token → DuplicateTokenEx
primary): the desktop user's own unelevated token, vetted not-elevated
before use (an elevated shell — UAC-off admin desktop — is no target).

Cross-account UAC face (also observed live: the elevated prompt runs a
DIFFERENT admin account, whose universe minted a fresh node key and
swallowed a subnet create): the child now gets the TOKEN user's
environment block (CreateEnvironmentBlock + CREATE_UNICODE_ENVIRONMENT),
so %LOCALAPPDATA% resolves the desktop user's universe, not the admin's,
and LOGON_WITH_PROFILE loads their profile. The elevated CLI's own
wrong-universe reads/writes remain — that is the account-election model
(DEFERRED, M8, shared with the Linux row).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>" && git push 2>&1 | tail -1 && git rev-parse --short HEAD

Commit + push shell-token fix


warning: in the working copy of 'crates/spt-daemon/src/deelevate.rs', LF will be replaced by CRLF the next time Git touches it
[dev-freeform ea0268b] fix(daemon): de-elevate via the desktop SHELL token — linked token fails 1346
 1 file changed, 105 insertions(+), 46 deletions(-)
   b3b8104..ea0268b  dev-freeform -> dev-freeform
ea0268b


PowerShell

$mine = Get-Process spt -ErrorAction SilentlyContinue | Where-Object { $_.Path }; if ($mine) { $mine | Stop-Process -Force -Confirm:$false }; Start-Sleep 1; Copy-Item "C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe" "$env:LOCALAPPDATA\spt-core\bin\spt.exe" -Force; & "$env:LOCALAPPDATA\spt-core\bin\spt.exe" subnet status BIGNET --nodes 2>&1 | Select-Object -First 5; Start-Process -FilePath "$env:LOCALAPPDATA\spt-core\bin\spt.exe" -ArgumentList "ready","lea" -WindowStyle Hidden -RedirectStandardOutput "$env:TEMP\lea.log" -RedirectStandardError "$env:TEMP\lea.err.log"; Start-Sleep 2; (Get-Process spt -ErrorAction SilentlyContinue | Measure-Object).Count

Swap HFENDULEAM to ea0268b, restart daemon + lea


Error: Exit code 2
Copy-Item: The process cannot access the file 'C:\Users\decid\AppData\Local\spt-core\bin\spt.exe' because it is being used by another process.
NO_SUCH_SUBNET:BIGNET
2


Worse than expected — `NO_SUCH_SUBNET:BIGNET` in *my* universe. Inspect state before anything else:


Get-Content "$env:LOCALAPPDATA\spt-core\identity\subnet.json" -Raw; Get-ChildItem "$env:LOCALAPPDATA\spt-core\identity" | Select-Object Name, LastWriteTime | Format-Table -HideTableHeaders | Out-String

Inspect subnet store + identity dir


{
  "subnets": [
    {
      "name": "TELENONNURA",
      "seed_hex": "134cc2059cb0063609423b87cf8f17bbe92b3976",
      "epoch": 1,
      "created": "1780751068",
      "hide_new_endpoints": false
    }
  ]
}

registry        6/6/2026 6:09:28 AM
epoch           6/6/2026 6:09:28 AM
node.key        6/6/2026 6:04:28 AM
subnet.json     6/6/2026 6:04:28 AM
visibility.json 6/6/2026 6:09:23 AM


State forensics — this is the universe-flip bug live on Windows, same account. Before touching anything:


"SPT_HOME=[$env:SPT_HOME]"; Get-ChildItem "$env:LOCALAPPDATA\spt-core\identity" -Recurse | Select-Object FullName, LastWriteTime, Length | Format-Table -AutoSize | Out-String -Width 200

Env + full identity tree


SPT_HOME=[]

FullName                                                                 LastWriteTime       Length
--------                                                                 -------------       ------
C:\Users\decid\AppData\Local\spt-core\identity\registry                  6/6/2026 6:10:29 AM
C:\Users\decid\AppData\Local\spt-core\identity\epoch                     6/6/2026 6:10:29 AM 1
C:\Users\decid\AppData\Local\spt-core\identity\node.key                  6/6/2026 6:04:28 AM 64
C:\Users\decid\AppData\Local\spt-core\identity\subnet.json               6/6/2026 6:04:28 AM 208
C:\Users\decid\AppData\Local\spt-core\identity\visibility.json           6/6/2026 6:09:23 AM 107
C:\Users\decid\AppData\Local\spt-core\identity\registry\TELENONNURA.json 6/6/2026 6:10:29 AM 222


Get-ChildItem "$env:LOCALAPPDATA\spt-core" | Select-Object Name, LastWriteTime | Format-Table -AutoSize | Out-String; Get-ChildItem "$env:LOCALAPPDATA\spt-core\owlery" -ErrorAction SilentlyContinue | Select-Object Name, LastWriteTime | Format-Table -AutoSize | Out-String -Width 120

Scope: spt-core root + owlery mtimes


Name               LastWriteTime
----               -------------
bin                6/6/2026 12:13:58 AM
identity           6/6/2026 6:10:59 AM
owlery             6/6/2026 6:09:24 AM
daemon-effects.log 6/6/2026 6:04:28 AM
daemon.pid         6/6/2026 6:04:28 AM

Name      LastWriteTime
----      -------------
lea       6/6/2026 6:11:01 AM
.registry 6/6/2026 6:09:24 AM


crates\spt\tests\shell_sleepwake_e2e.rs:180:    let _ = std::fs::remove_file(&keeper_evidence); // second life writes fresh
crates\xtask\src\main.rs:301:        std::fs::remove_dir_all(&rustdoc_out).unwrap();
crates\xtask\src\main.rs:484:    let _ = std::fs::remove_dir_all(&work);
crates\spt-live\src\ingest.rs:155:        std::fs::remove_file(&drop_path)?;
crates\spt\src\cli.rs:816:        let _ = std::fs::remove_file(perch::resolve_ready_file(src, ParentHint::Infer));
crates\spt\src\cli.rs:818:        if let Err(e) = std::fs::remove_dir_all(&src_perch) {
crates\spt\src\cli.rs:1019:    let _ = std::fs::remove_file(perch::resolve_ready_file(&id, ParentHint::Infer));
crates\spt\src\cli.rs:1469:    let removed = std::fs::remove_file(perch::resolve_ready_file(id, ParentHint::Infer)).is_ok();
crates\spt\src\cli.rs:2534:                        let _ = std::fs::remove_dir_all(&dest);
crates\spt-msg\src\ready.rs:134:        let _ = fs::remove_file(perch::resolve_ready_file(&self.id, ParentHint::Infer));
crates\spt-msg\src\ring.rs:135:    let _ = fs::remove_file(perch::resolve_ready_file(from, ParentHint::Infer));
crates\spt-msg\src\ring.rs:136:    let _ = fs::remove_file(perch::resolve_info_file(from, ParentHint::Infer));
crates\spt-msg\src\ring.rs:137:    let _ = fs::remove_file(perch::resolve_spool_db(from, ParentHint::Infer));
crates\spt-msg\src\ring.rs:138:    let _ = fs::remove_dir(&perch_path);
crates\spt-live\src\pulse.rs:87:        let _ = std::fs::remove_file(&gate);
crates\spt-live\src\signoff.rs:102:    match std::fs::remove_file(&stale) {
crates\spt-store\src\branchstore.rs:409:        if meta.len() == 0 && old_enough && std::fs::remove_file(&lock).is_ok() {
crates\spt-store\src\contextstore.rs:239:            std::fs::remove_file(p)?;
crates\spt\src\api\worker.rs:65:    let removed = std::fs::remove_file(perch::resolve_ready_file(id, ParentHint::Infer)).is_ok();
crates\spt-store\src\atomic.rs:66:            let _ = fs::remove_file(&tmp);
crates\spt\src\api\live.rs:83:            let _ = std::fs::remove_file(perch::resolve_ready_file(id, ParentHint::Infer));
crates\spt\src\api\delivery.rs:52:            let _ = std::fs::remove_file(&idle);
crates\spt\src\api\delivery.rs:78:            let _ = std::fs::remove_file(&gate);
crates\spt\src\api\reporting.rs:151:        let _ = std::fs::remove_file(perch::resolve_ready_file(id, ParentHint::Infer));
crates\spt\src\api\reporting.rs:160:        let _ = std::fs::remove_file(perch::resolve_ready_file(id, ParentHint::Infer));
crates\spt\src\api\reporting.rs:172:    if let Err(e) = std::fs::remove_dir_all(&perch_path) {
crates\spt-store\src\shellinfo.rs:250:    std::fs::remove_dir_all(perch::resolve_shell_perch_path_in(owlery, owner, &id))?;
crates\spt-daemon\src\applyhost.rs:107:    let _ = std::fs::remove_file(&aside); // stale prior apply of this version
crates\spt-store\src\syncmerge.rs:256:                    std::fs::remove_file(&artifact)?;
crates\spt-store\src\syncmerge.rs:304:        std::fs::remove_file(&bundle).unwrap();

[Showing results with pagination = limit: 30]


Stopping the forensics spiral — here's where it stands, straight:

## What your elevated test revealed (severity up: state destroyer)

**Damage on HFENDULEAM (decid universe):**
- `node.key` **replaced** 06:04:28 — fb29977f's private key is gone (46e4dee9 is the machine's identity now)
- `subnet.json` — **BIGNET membership wiped**, only TELENONNURA remains
- `identity/` rebuilt: trust rows, BIGNET registry snapshot, epoch counter (reset to 1) — gone
- `owlery/` (lea perch, spools) untouched; gravity unaffected

**The mystery:** at 06:04:28 the elevated process behaved as if `identity/` was *empty* — regenerated everything fresh — while the same path demonstrably held the BIGNET universe minutes before and after. Same account, same `LOCALAPPDATA`, `SPT_HOME` unset. No code path deletes that dir. This is a second, worse bug than the token issue (which I've also fixed meanwhile — shell-token replaces the 1346-failing linked-token, pushed as `ea0268b`).

## Recovery (~10 min, by design survivable)
Identity loss = re-pair. Gravity still holds the BIGNET seed + live responder.

From your **elevated** PS (it holds the lock + the stray daemon):
```powershell
taskkill /PID 69560 /F
```
Then I'll: swap in the `ea0268b` binary, clean TELENONNURA out of subnet.json (test artifact — say if you want it kept), fetch the join code off gravity, and run the guided `subnet join BIGNET` here. Old fb29977f ghosts on gravity decay via the new eviction.

## RCA repro (before trusting any elevated command again)
I'll stage an isolated `SPT_HOME` seeded with fake identity state and hand you **one elevated command** to run against it — diff before/after shows exactly what the elevated view does to existing files.

Run the `taskkill`, then say go?


Shell-token de-elevation fix was building (task bql2wrcit). When done: verify tests/clippy clean, commit+push (fix(daemon): shell-token de-elevation — linked token fails 1346 without TCB; env block for cross-account UAC), swap HFENDULEAM binary + restart daemon + lea, deploy gravity per memory procedure, then ask user to re-run elevated subnet create to verify DEELEVATED spawn, and give them elevated-PS cleanup commands for stray admin-universe daemon 69560 + admin LOCALAPPDATA\spt-core dir.


Claude resuming /loop wakeup (Jun 6 6:19am)


<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.


Stale wakeup — that list's done through the push (`ea0268b`); now blocked on your `taskkill /PID 69560 /F` (it holds the installed exe lock). Prepping the RCA repro meanwhile so you get one elevated paste:


$rca = "C:\tmp\spt-elev-rca"; Remove-Item $rca -Recurse -Force -ErrorAction SilentlyContinue; New-Item -ItemType Directory -Force "$rca\identity\registry" | Out-Null; New-Item -ItemType Directory -Force "$rca\identity\trust" | Out-Null; Copy-Item "$env:LOCALAPPDATA\spt-core\identity\node.key" "$rca\identity\node.key"; Copy-Item "$env:LOCALAPPDATA\spt-core\identity\subnet.json" "$rca\identity\subnet.json"; Set-Content "$rca\identity\epoch" -Value "424242" -NoNewline; Set-Content "$rca\identity\trust\peers.json" -Value '{"peers":[]}' -NoNewline; Set-Content "$rca\identity\registry\TELENONNURA.json" -Value '{"by_id":{}}' -NoNewline; Get-ChildItem $rca -Recurse | Get-FileHash -Algorithm SHA256 -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Hash.Substring(0,12)) $($_.Path)" }

Stage isolated RCA home with seeded identity


Error: Exit code 1
833DFC7E3EB1 C:\tmp\spt-elev-rca\identity\epoch
6DB6D2E9165C C:\tmp\spt-elev-rca\identity\node.key
3CF4BCBAA256 C:\tmp\spt-elev-rca\identity\subnet.json
4DEFDB8861E1 C:\tmp\spt-elev-rca\identity\registry\TELENONNURA.json
F4D849192EE9 C:\tmp\spt-elev-rca\identity\trust\peers.json


$env:SPT_HOME = "C:\tmp\spt-elev-rca"; & "C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe" subnet status 2>&1 | Select-Object -First 4; $env:SPT_HOME = $null; Get-ChildItem "C:\tmp\spt-elev-rca\identity" -Recurse -File | Get-FileHash -Algorithm SHA256 | ForEach-Object { "$($_.Hash.Substring(0,12)) $($_.Path.Split('\')[-1])" }

Unelevated control run against RCA home


SUBNET       NODES  ENDPOINTS
TELENONNURA  1      0

hint: `spt subnet create <name>` mints a new subnet on this machine
833DFC7E3EB1 epoch
6DB6D2E9165C node.key
3CF4BCBAA256 subnet.json
4DEFDB8861E1 TELENONNURA.json
F4D849192EE9 peers.json


Control clean — all hashes identical unelevated. The destroyer needs elevation. Your turn — paste this **whole block into your elevated PS**:

```powershell
taskkill /PID 69560 /F
$env:SPT_HOME = 'C:\tmp\spt-elev-rca'
C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe subnet status
C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe subnet create RCATEST
$env:SPT_HOME = $null
```

Line 1 frees the locked installed exe (stray elevated daemon). Lines 2-4 replay your destructive sequence against the sacrificial home — `status` (pure read) separated from `create` (the write) so we see which one regenerates state. Paste the output back; I re-hash the test home the moment you're done.

(`46e4dee9` node.key + TELENONNURA seeded as the test fixture — the real recovery re-pair happens after RCA.)


it wasn't a bug. i wiped SPT_HOME, then ran spt subnet create TELENONNURA. i was experimenting.


Ha — mystery dissolved. Everything fits: empty home → fresh node.key (46e4dee9) + sole TELENONNURA = correct behavior, not a destroyer. Withdrawn.

What stays real from your experiment:
1. **1346 DEELEVATE_FAIL** — genuine bug, already fixed (`ea0268b`: shell-window token instead of the TCB-gated linked token, + target-user env block)
2. **Stray elevated daemon 69560** — the designed fallback after that fail; it locks the installed exe so I can't swap in the fix
3. **fb29977f is gone** (your wipe) — HFENDULEAM no longer in BIGNET; gravity still seed-holds it with a live responder

So:
- run `taskkill /PID 69560 /F` in the elevated window (or tell me if it's gone already)
- want me to **re-join BIGNET** under the new 46e4dee9 identity (guided join, code from gravity)? Or keeping the fresh-universe experiment going?
- after swap, your elevated `spt subnet create` re-run becomes the real verification: should print a *de-elevated* daemon spawn instead of `DEELEVATE_FAIL` — i.e. the daemon lands unelevated even though the CLI is admin

Scrapping the `C:\tmp\spt-elev-rca` fixture meanwhile.


ok, killed that process and wiped SPT_HOME again. please swap in the fix


Remove-Item "C:\tmp\spt-elev-rca" -Recurse -Force -ErrorAction SilentlyContinue; $bin = "$env:LOCALAPPDATA\spt-core\bin"; New-Item -ItemType Directory -Force $bin | Out-Null; Copy-Item "C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe" "$bin\spt.exe" -Force; Get-Item "$bin\spt.exe" | Select-Object LastWriteTime, Length; Get-ChildItem "$env:LOCALAPPDATA\spt-core" | Select-Object Name | Format-Table -HideTableHeaders | Out-String

Swap installed binary to ea0268b, clean rca fixture


LastWriteTime         Length
-------------         ------
6/6/2026 6:08:35 AM 22600704

bin


Fix installed (`ea0268b`, clean universe — `bin/` only). Verify from your **elevated** PS:

```powershell
spt subnet create TELENONNURA
```

Expected this time:
- **no `DEELEVATE_FAIL`** — daemon spawns via the desktop shell token, unelevated
- banner mints a fresh identity (empty home — expected)

Then I'll confirm from this unelevated side that the daemon is reachable (the original M7 failure mode) and visibly running as you, not admin.


[Image #14]


[Image: source: C:\Users\decid\Documents\ShareX\Screenshots\2026-06\WindowsTerminal_9A65kZt3Zm.png]


Progress — shell token acquired, but `CreateProcessWithTokenW` rejects the flags: error 87. RCA: that API's allowed creation-flag set excludes `DETACHED_PROCESS` and `CREATE_NO_WINDOW` (which I inherited from `detached_no_inherit`). Allowed: `CREATE_NEW_CONSOLE` + hidden window via `STARTUPINFO`. Patching:


Edit

    // DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW — the
    // same long-lived-child flags as detached_no_inherit — plus
    // CREATE_UNICODE_ENVIRONMENT (the CreateEnvironmentBlock block is wide).
    const FLAGS: u32 = 0x0000_0008 | 0x0000_0200 | 0x0800_0000 | 0x0000_0400;

    // CreateProcessWithTokenW accepts only a RESTRICTED creation-flag set —
    // DETACHED_PROCESS and CREATE_NO_WINDOW (the detached_no_inherit combo)
    // are rejected with ERROR_INVALID_PARAMETER (87; hit live, second
    // elevated verification round). Detach therefore rides
    // CREATE_NEW_CONSOLE with the console window HIDDEN via the startup
    // info (STARTF_USESHOWWINDOW + SW_HIDE) — the child still owns no
    // caller console and no window appears. CREATE_NEW_PROCESS_GROUP keeps
    // its own signal group; CREATE_UNICODE_ENVIRONMENT matches the wide
    // CreateEnvironmentBlock.
    const FLAGS: u32 = 0x0000_0010 | 0x0000_0200 | 0x0000_0400;
    /// STARTUPINFOW.dwFlags: honor wShowWindow.
    const STARTF_USESHOWWINDOW: u32 = 0x0000_0001;


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

    // DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW — the
    // same long-lived-child flags as detached_no_inherit — plus
    // CREATE_UNICODE_ENVIRONMENT (the CreateEnvironmentBlock block is wide).
    const FLAGS: u32 = 0x0000_0008 | 0x0000_0200 | 0x0800_0000 | 0x0000_0400;

    // CreateProcessWithTokenW accepts only a RESTRICTED creation-flag set —
    // DETACHED_PROCESS and CREATE_NO_WINDOW (the detached_no_inherit combo)
    // are rejected with ERROR_INVALID_PARAMETER (87; hit live, second
    // elevated verification round). Detach therefore rides
    // CREATE_NEW_CONSOLE with the console window HIDDEN via the startup
    // info (STARTF_USESHOWWINDOW + SW_HIDE) — the child still owns no
    // caller console and no window appears. CREATE_NEW_PROCESS_GROUP keeps
    // its own signal group; CREATE_UNICODE_ENVIRONMENT matches the wide
    // CreateEnvironmentBlock.
    const FLAGS: u32 = 0x0000_0010 | 0x0000_0200 | 0x0000_0400;
    /// STARTUPINFOW.dwFlags: honor wShowWindow.
    const STARTF_USESHOWWINDOW: u32 = 0x0000_0001;

/// SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation / TokenPrimary.

-    // DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW — the

-    // same long-lived-child flags as detached_no_inherit — plus

-    // CREATE_UNICODE_ENVIRONMENT (the CreateEnvironmentBlock block is wide).

+    // CreateProcessWithTokenW accepts only a RESTRICTED creation-flag set —

+    // DETACHED_PROCESS and CREATE_NO_WINDOW (the detached_no_inherit combo)

+    // are rejected with ERROR_INVALID_PARAMETER (87; hit live, second

+    // elevated verification round). Detach therefore rides

+    // CREATE_NEW_CONSOLE with the console window HIDDEN via the startup

+    // info (STARTF_USESHOWWINDOW + SW_HIDE) — the child still owns no

+    // caller console and no window appears. CREATE_NEW_PROCESS_GROUP keeps

+    // its own signal group; CREATE_UNICODE_ENVIRONMENT matches the wide

+    /// STARTUPINFOW.dwFlags: honor wShowWindow.

+    const STARTF_USESHOWWINDOW: u32 = 0x0000_0001;

/// Whether this process runs with an elevated token. A failed probe

/// reads `false` — the caller then spawns `Inherit`, which is exactly


        let mut si: StartupInfoW = unsafe { std::mem::zeroed() };
        si.cb = std::mem::size_of::<StartupInfoW>() as u32;
        let mut pi: ProcessInformation = unsafe { std::mem::zeroed() };
        let mut env: *mut core::ffi::c_void = std::ptr::null_mut();

        let mut si: StartupInfoW = unsafe { std::mem::zeroed() };
        si.cb = std::mem::size_of::<StartupInfoW>() as u32;
        // Hide the CREATE_NEW_CONSOLE window (SW_HIDE = 0).
        si.flags = STARTF_USESHOWWINDOW;
        si.show_window = 0;
        let mut pi: ProcessInformation = unsafe { std::mem::zeroed() };
        let mut env: *mut core::ffi::c_void = std::ptr::null_mut();


        let mut si: StartupInfoW = unsafe { std::mem::zeroed() };
        si.cb = std::mem::size_of::<StartupInfoW>() as u32;
        let mut pi: ProcessInformation = unsafe { std::mem::zeroed() };
        let mut env: *mut core::ffi::c_void = std::ptr::null_mut();

        let mut si: StartupInfoW = unsafe { std::mem::zeroed() };
        si.cb = std::mem::size_of::<StartupInfoW>() as u32;
        // Hide the CREATE_NEW_CONSOLE window (SW_HIDE = 0).
        si.flags = STARTF_USESHOWWINDOW;
        si.show_window = 0;
        let mut pi: ProcessInformation = unsafe { std::mem::zeroed() };
        let mut env: *mut core::ffi::c_void = std::ptr::null_mut();

+        // Hide the CREATE_NEW_CONSOLE window (SW_HIDE = 0).

+        si.flags = STARTF_USESHOWWINDOW;

let env_built = unsafe { CreateEnvironmentBlock(&mut env, token, 0) != 0 };


Bash

cd C:/Users/decid/Documents/projects/spt-core && cargo build --release -p spt 2>&1 | tail -1

Rebuild with token-flags fix


Finished `release` profile [optimized] target(s) in 31.47s


PowerShell

$p = Get-Process spt -ErrorAction SilentlyContinue | Where-Object { $_.Path }; if ($p) { $p | Stop-Process -Force -Confirm:$false; Start-Sleep 1 }; Copy-Item "C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe" "$env:LOCALAPPDATA\spt-core\bin\spt.exe" -Force; "swapped: $((Get-Item "$env:LOCALAPPDATA\spt-core\bin\spt.exe").LastWriteTime)"

Swap in flags-fixed binary


swapped: 06/06/2026 14:38:38


Get-Process spt -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Id) path=[$($_.Path)]" }; "---"; Get-ChildItem "$env:LOCALAPPDATA\spt-core" -ErrorAction SilentlyContinue | Select-Object Name | Format-Table -HideTableHeaders | Out-String

Check stray daemons + universe state


---

bin
identity
daemon-effects.log
daemon.pid


No stray daemons; universe carries the cc42d786 identity + TELENONNURA from the last attempt. Fixed binary in place — from your **elevated** PS:

```powershell
spt subnet status TELENONNURA --nodes
```

(`create` would refuse — TELENONNURA already exists. Status `--nodes` triggers the same daemon auto-spawn path.)

Expected: **no `DEELEVATE_FAIL`** → daemon spawns under your desktop token. I'll then verify from this unelevated side: daemon process visible *with* path (= unelevated, queryable) + pipes answer me.


given that a DEELEVATE_FAIL means SPT won't function properly, it should abort running SPT at all. --- that time, fresh creation worked. no DEELEVATE_FAIL


Confirmed working — and agreed on policy: a *failed* de-elevation (target existed, spawn broke) = known-torn state → abort, never limp along elevated. Keeping the no-target case (UAC-off box, SYSTEM — uniformly-elevated universe, nothing to be torn against) as run-with-warning. Implementing abort semantics:


Edit

    #[cfg(windows)]
    {
        let exe = exe.to_string_lossy();
        let args = ["daemon".to_string()];
        match crate::deelevate::spawn_deelevated(&exe, &args) {
            Ok(Some(_pid)) => return Ok(()), // de-elevated child running
            Ok(None) => {
                if crate::deelevate::is_elevated() {
                    eprintln!(
                        "ELEVATED_DAEMON: no unelevated linked token — daemon inherits the \
                         elevated token (unelevated clients may be denied)"
                    );
                }
            }
            Err(e) => eprintln!("DEELEVATE_FAIL: {e} — falling back to inherited token"),
        }
        detached_no_inherit(&exe, &args)?;
        Ok(())
    }

    #[cfg(windows)]
    {
        let exe = exe.to_string_lossy();
        let args = ["daemon".to_string()];
        match crate::deelevate::spawn_deelevated(&exe, &args) {
            Ok(Some(_pid)) => return Ok(()), // de-elevated child running
            Ok(None) => {
                if crate::deelevate::is_elevated() {
                    // No unelevated identity exists (UAC-off admin desktop,
                    // SYSTEM): the whole universe is uniformly elevated, so
                    // an elevated daemon is consistent there. Loud anyway.
                    eprintln!(
                        "ELEVATED_DAEMON: no unelevated identity to drop to — daemon inherits \
                         the elevated token"
                    );
                }
            }
            // A de-elevation TARGET existed but the spawn failed: an
            // elevated daemon here is a known-torn state (its pipes deny
            // the unelevated clients that target exists for). ABORT — do
            // not start a daemon that cannot serve (user-ratified
            // 2026-06-06: DEELEVATE_FAIL means spt won't function; refuse,
            // don't limp).
            Err(e) => {
                return Err(io::Error::other(format!(
                    "DEELEVATE_FAIL: {e} — refusing to start an ELEVATED daemon (it would deny \
                     unelevated clients); run spt from an unelevated shell"
                )));
            }
        }
        detached_no_inherit(&exe, &args)?;
        Ok(())
    }


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

    #[cfg(windows)]
    {
        let exe = exe.to_string_lossy();
        let args = ["daemon".to_string()];
        match crate::deelevate::spawn_deelevated(&exe, &args) {
            Ok(Some(_pid)) => return Ok(()), // de-elevated child running
            Ok(None) => {
                if crate::deelevate::is_elevated() {
                    eprintln!(
                        "ELEVATED_DAEMON: no unelevated linked token — daemon inherits the \
                         elevated token (unelevated clients may be denied)"
                    );
                }
            }
            Err(e) => eprintln!("DEELEVATE_FAIL: {e} — falling back to inherited token"),
        }
        detached_no_inherit(&exe, &args)?;
        Ok(())
    }

    #[cfg(windows)]
    {
        let exe = exe.to_string_lossy();
        let args = ["daemon".to_string()];
        match crate::deelevate::spawn_deelevated(&exe, &args) {
            Ok(Some(_pid)) => return Ok(()), // de-elevated child running
            Ok(None) => {
                if crate::deelevate::is_elevated() {
                    // No unelevated identity exists (UAC-off admin desktop,
                    // SYSTEM): the whole universe is uniformly elevated, so
                    // an elevated daemon is consistent there. Loud anyway.
                    eprintln!(
                        "ELEVATED_DAEMON: no unelevated identity to drop to — daemon inherits \
                         the elevated token"
                    );
                }
            }
            // A de-elevation TARGET existed but the spawn failed: an
            // elevated daemon here is a known-torn state (its pipes deny
            // the unelevated clients that target exists for). ABORT — do
            // not start a daemon that cannot serve (user-ratified
            // 2026-06-06: DEELEVATE_FAIL means spt won't function; refuse,
            // don't limp).
            Err(e) => {
                return Err(io::Error::other(format!(
                    "DEELEVATE_FAIL: {e} — refusing to start an ELEVATED daemon (it would deny \
                     unelevated clients); run spt from an unelevated shell"
                )));
            }
        }
        detached_no_inherit(&exe, &args)?;
        Ok(())
    }

+                    // No unelevated identity exists (UAC-off admin desktop,

+                    // SYSTEM): the whole universe is uniformly elevated, so

+                    // an elevated daemon is consistent there. Loud anyway.

-                        "ELEVATED_DAEMON: no unelevated linked token — daemon inherits the \

-                         elevated token (unelevated clients may be denied)"

+                        "ELEVATED_DAEMON: no unelevated identity to drop to — daemon inherits \

+                         the elevated token"

-            Err(e) => eprintln!("DEELEVATE_FAIL: {e} — falling back to inherited token"),

+            // A de-elevation TARGET existed but the spawn failed: an

+            // elevated daemon here is a known-torn state (its pipes deny

+            // the unelevated clients that target exists for). ABORT — do

+            // not start a daemon that cannot serve (user-ratified

+            // 2026-06-06: DEELEVATE_FAIL means spt won't function; refuse,

+                return Err(io::Error::other(format!(

+                    "DEELEVATE_FAIL: {e} — refusing to start an ELEVATED daemon (it would deny \

+                     unelevated clients); run spt from an unelevated shell"


        #[cfg(unix)]
        if let Some(invoker) = crate::deelevate::sudo_invoker() {
            match invoker.drop_in_process() {
                Ok(()) => eprintln!("DEELEVATED: daemon dropped to uid {}", invoker.uid),
                Err(e) => {
                    eprintln!("DEELEVATE_FAIL: {e} — daemon continues elevated (state may be root-owned)")
                }
            }
        }
        #[cfg(windows)]
        if crate::deelevate::is_elevated() {
            let exe = std::env::current_exe()?;
            match crate::deelevate::spawn_deelevated(
                &exe.to_string_lossy(),
                &["daemon".to_string()],
            ) {
                Ok(Some(pid)) => {
                    eprintln!("DEELEVATED_RESPAWN: unelevated daemon pid {pid}; elevated copy exits");
                    return Ok(());
                }
                Ok(None) => eprintln!(
                    "ELEVATED_DAEMON: no unelevated linked token — serving with the elevated \
                     token (unelevated clients may be denied)"
                ),
                Err(e) => eprintln!(
                    "DEELEVATE_FAIL: {e} — serving with the elevated token (unelevated clients \
                     may be denied)"
                ),
            }
        }

        #[cfg(unix)]
        if let Some(invoker) = crate::deelevate::sudo_invoker() {
            match invoker.drop_in_process() {
                Ok(()) => eprintln!("DEELEVATED: daemon dropped to uid {}", invoker.uid),
                // A drop target existed but the drop failed: serving as
                // root would root the user's state universe — a known-torn
                // state. ABORT (user-ratified 2026-06-06: refuse, don't limp).
                Err(e) => {
                    return Err(io::Error::other(format!(
                        "DEELEVATE_FAIL: {e} — refusing to serve as root over a user universe; \
                         run spt unelevated"
                    )));
                }
            }
        }
        #[cfg(windows)]
        if crate::deelevate::is_elevated() {
            let exe = std::env::current_exe()?;
            match crate::deelevate::spawn_deelevated(
                &exe.to_string_lossy(),
                &["daemon".to_string()],
            ) {
                Ok(Some(pid)) => {
                    eprintln!("DEELEVATED_RESPAWN: unelevated daemon pid {pid}; elevated copy exits");
                    return Ok(());
                }
                // Uniformly-elevated universe (no unelevated identity):
                // serving elevated is consistent there. Loud anyway.
                Ok(None) => eprintln!(
                    "ELEVATED_DAEMON: no unelevated identity to drop to — serving with the \
                     elevated token"
                ),
                // Target existed, respawn failed: an elevated daemon is a
                // known-torn state. ABORT (user-ratified 2026-06-06).
                Err(e) => {
                    return Err(io::Error::other(format!(
                        "DEELEVATE_FAIL: {e} — refusing to serve with the elevated token; run \
                         spt from an unelevated shell"
                    )));
                }
            }
        }


        #[cfg(unix)]
        if let Some(invoker) = crate::deelevate::sudo_invoker() {
            match invoker.drop_in_process() {
                Ok(()) => eprintln!("DEELEVATED: daemon dropped to uid {}", invoker.uid),
                Err(e) => {
                    eprintln!("DEELEVATE_FAIL: {e} — daemon continues elevated (state may be root-owned)")
                }
            }
        }
        #[cfg(windows)]
        if crate::deelevate::is_elevated() {
            let exe = std::env::current_exe()?;
            match crate::deelevate::spawn_deelevated(
                &exe.to_string_lossy(),
                &["daemon".to_string()],
            ) {
                Ok(Some(pid)) => {
                    eprintln!("DEELEVATED_RESPAWN: unelevated daemon pid {pid}; elevated copy exits");
                    return Ok(());
                }
                Ok(None) => eprintln!(
                    "ELEVATED_DAEMON: no unelevated linked token — serving with the elevated \
                     token (unelevated clients may be denied)"
                ),
                Err(e) => eprintln!(
                    "DEELEVATE_FAIL: {e} — serving with the elevated token (unelevated clients \
                     may be denied)"
                ),
            }
        }

        #[cfg(unix)]
        if let Some(invoker) = crate::deelevate::sudo_invoker() {
            match invoker.drop_in_process() {
                Ok(()) => eprintln!("DEELEVATED: daemon dropped to uid {}", invoker.uid),
                // A drop target existed but the drop failed: serving as
                // root would root the user's state universe — a known-torn
                // state. ABORT (user-ratified 2026-06-06: refuse, don't limp).
                Err(e) => {
                    return Err(io::Error::other(format!(
                        "DEELEVATE_FAIL: {e} — refusing to serve as root over a user universe; \
                         run spt unelevated"
                    )));
                }
            }
        }
        #[cfg(windows)]
        if crate::deelevate::is_elevated() {
            let exe = std::env::current_exe()?;
            match crate::deelevate::spawn_deelevated(
                &exe.to_string_lossy(),
                &["daemon".to_string()],
            ) {
                Ok(Some(pid)) => {
                    eprintln!("DEELEVATED_RESPAWN: unelevated daemon pid {pid}; elevated copy exits");
                    return Ok(());
                }
                // Uniformly-elevated universe (no unelevated identity):
                // serving elevated is consistent there. Loud anyway.
                Ok(None) => eprintln!(
                    "ELEVATED_DAEMON: no unelevated identity to drop to — serving with the \
                     elevated token"
                ),
                // Target existed, respawn failed: an elevated daemon is a
                // known-torn state. ABORT (user-ratified 2026-06-06).
                Err(e) => {
                    return Err(io::Error::other(format!(
                        "DEELEVATE_FAIL: {e} — refusing to serve with the elevated token; run \
                         spt from an unelevated shell"
                    )));
                }
            }
        }

+                // A drop target existed but the drop failed: serving as

+                // root would root the user's state universe — a known-torn

+                // state. ABORT (user-ratified 2026-06-06: refuse, don't limp).

-                    eprintln!("DEELEVATE_FAIL: {e} — daemon continues elevated (state may be root-owned)")

+                    return Err(io::Error::other(format!(

+                        "DEELEVATE_FAIL: {e} — refusing to serve as root over a user universe; \

+                         run spt unelevated"

+                // Uniformly-elevated universe (no unelevated identity):

+                // serving elevated is consistent there. Loud anyway.

-                    "ELEVATED_DAEMON: no unelevated linked token — serving with the elevated \

-                     token (unelevated clients may be denied)"

+                    "ELEVATED_DAEMON: no unelevated identity to drop to — serving with the \

-                    "DEELEVATE_FAIL: {e} — serving with the elevated token (unelevated clients \

+                // Target existed, respawn failed: an elevated daemon is a

+                // known-torn state. ABORT (user-ratified 2026-06-06).

+                        "DEELEVATE_FAIL: {e} — refusing to serve with the elevated token; run \

+                         spt from an unelevated shell"


Same policy at the unix CLI entry:


    #[cfg(unix)]
    if let Some(invoker) = spt_daemon::deelevate::sudo_invoker() {
        match invoker.drop_in_process() {
            Ok(()) => {
                elevation::mark_proven();
                eprintln!(
                    "DEELEVATED: running as uid {} (elevation stays proven for gated commands)",
                    invoker.uid
                );
            }
            Err(e) => eprintln!(
                "DEELEVATE_FAIL: {e} — continuing elevated (state written now may be root-owned)"
            ),
        }
    }

    #[cfg(unix)]
    if let Some(invoker) = spt_daemon::deelevate::sudo_invoker() {
        match invoker.drop_in_process() {
            Ok(()) => {
                elevation::mark_proven();
                eprintln!(
                    "DEELEVATED: running as uid {} (elevation stays proven for gated commands)",
                    invoker.uid
                );
            }
            // A drop target existed but the drop failed: continuing would
            // run root over the user's universe — a known-torn state.
            // ABORT (user-ratified 2026-06-06: DEELEVATE_FAIL means spt
            // won't function properly; refuse, don't limp).
            Err(e) => {
                eprintln!("DEELEVATE_FAIL: {e} — refusing to run elevated over a user universe");
                std::process::exit(1);
            }
        }
    }


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

    #[cfg(unix)]
    if let Some(invoker) = spt_daemon::deelevate::sudo_invoker() {
        match invoker.drop_in_process() {
            Ok(()) => {
                elevation::mark_proven();
                eprintln!(
                    "DEELEVATED: running as uid {} (elevation stays proven for gated commands)",
                    invoker.uid
                );
            }
            // A drop target existed but the drop failed: continuing would
            // run root over the user's universe — a known-torn state.
            // ABORT (user-ratified 2026-06-06: DEELEVATE_FAIL means spt
            // won't function properly; refuse, don't limp).
            Err(e) => {
                eprintln!("DEELEVATE_FAIL: {e} — refusing to run elevated over a user universe");
                std::process::exit(1);
            }
        }
    }

//! `spt` — the single spt-core binary. A **thin** command layer over `spt-msg`:
//! it owns I/O (stdin/stdout/stderr) and process exit codes; all messaging
//! logic lives in the crate (clean-room separation per the M1 plan).
//!
//! Subcommands (REQ-MSG-2 stable surface): `send` · `ring` · `ready` · `poll` ·
//! `list` · `stop` · `whoami`. The harness-contract inbound surface lives under
//! the `api` group (REQ-API-1), dispatched from [`api`].
// [impl->REQ-MSG-2]

mod api;
mod cli;
mod elevation;
mod roster;
mod wansend;

#[cfg(test)]
mod testutil;

fn main() {
    // The sudo de-elevation drop (KNOWN-HAZARDS 5.7) runs BEFORE anything
    // touches state: a sudo'd `spt` otherwise lives in root's universe
    // (sudo flips $HOME, so spt_home — state, node identity, the daemon
    // socket names — all resolve wrong) and roots whatever it writes. Drop
    // to the invoking user (uid/gid/HOME) while keeping the elevation
    // PROOF for the gated commands (`subnet create`/`join`, show-code):
    // the user paid for the gate by sudo'ing; the drop is state safety,
    // not authz revocation. Genuine root (no SUDO_*) is left alone — root's
    // universe IS the invoking user's universe then.
    // [impl->REQ-HAZARD-ELEVATED-DAEMON-SPAWN]
    #[cfg(unix)]
    if let Some(invoker) = spt_daemon::deelevate::sudo_invoker() {
        match invoker.drop_in_process() {
            Ok(()) => {
                elevation::mark_proven();
                eprintln!(
                    "DEELEVATED: running as uid {} (elevation stays proven for gated commands)",
                    invoker.uid
                );
            }
            Err(e) => eprintln!(
                "DEELEVATE_FAIL: {e} — continuing elevated (state written now may be root-owned)"
            ),
        }
    }
    let code = cli::run();
    std::process::exit(code);
}

-                "DEELEVATE_FAIL: {e} — continuing elevated (state written now may be root-owned)"

+            // A drop target existed but the drop failed: continuing would

+            // run root over the user's universe — a known-torn state.

+            // ABORT (user-ratified 2026-06-06: DEELEVATE_FAIL means spt

+            // won't function properly; refuse, don't limp).

+                eprintln!("DEELEVATE_FAIL: {e} — refusing to run elevated over a user universe");


Bash

cd C:/Users/decid/Documents/projects/spt-core && cargo test -p spt-daemon --lib 2>&1 | tail -2 && cargo clippy -p spt-daemon -p spt 2>&1 | grep -cE "^warning: |^error" ; cargo build --release -p spt 2>&1 | tail -1

Test, clippy, rebuild abort-policy change


Command running in background with ID: bubfuc1d5. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bubfuc1d5.output. You will be notified when it completes. To check interim output, use Read on that file path.


Building. Once green: commit abort policy + flags-fix together, push, swap here, parity-deploy gravity (unix abort path changed there too).


<task-notification>
<task-id>bubfuc1d5</task-id>
<tool-use-id>toolu_012bEcNg9GdNBmFQQCgdcTmX</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bubfuc1d5.output</output-file>
<status>completed</status>
<summary>Background command "Test, clippy, rebuild abort-policy change" completed (exit code 0)</summary>
</task-notification>


Build/test result


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

0
    Finished `release` profile [optimized] target(s) in 15.45s


cd C:/Users/decid/Documents/projects/spt-core && git add crates/spt-daemon/src/deelevate.rs crates/spt-daemon/src/daemon.rs crates/spt/src/main.rs && git commit -m "fix(daemon,cli): token-restricted flags for CreateProcessWithTokenW + DEELEVATE_FAIL aborts

Two findings from the live elevated verification rounds (2026-06-06):

- ERROR_INVALID_PARAMETER (87): CreateProcessWithTokenW accepts only a
  restricted creation-flag set — DETACHED_PROCESS and CREATE_NO_WINDOW
  (the detached_no_inherit combo) are rejected. Detach now rides
  CREATE_NEW_CONSOLE with the console hidden via STARTF_USESHOWWINDOW +
  SW_HIDE; verified live: elevated 'subnet create' spawns the daemon
  de-elevated with no DEELEVATE_FAIL.

- Policy (user-ratified): a FAILED de-elevation where a target existed
  is a known-torn state (elevated daemon denies the unelevated clients
  the target exists for; root daemon roots the user universe) — ABORT
  instead of falling back: spawn_detached and the Daemon::run guard
  refuse with a DEELEVATE_FAIL error, and the unix main-entry drop
  exits 1. The no-target case (UAC-off admin desktop, SYSTEM — a
  uniformly elevated universe) still runs, loudly: there is no
  unelevated identity to be torn against.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>" && git push 2>&1 | tail -1 && git rev-parse --short HEAD

Commit + push flags fix + abort policy


warning: in the working copy of 'crates/spt-daemon/src/daemon.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt-daemon/src/deelevate.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
[dev-freeform c7e7d9e] fix(daemon,cli): token-restricted flags for CreateProcessWithTokenW + DEELEVATE_FAIL aborts
 3 files changed, 59 insertions(+), 17 deletions(-)
   ea0268b..c7e7d9e  dev-freeform -> dev-freeform
c7e7d9e


PowerShell

$p = Get-Process spt -ErrorAction SilentlyContinue | Where-Object { $_.Path }; if ($p) { $p | Stop-Process -Force -Confirm:$false; Start-Sleep 1 }; Copy-Item "C:\Users\decid\Documents\projects\spt-core\target\release\spt.exe" "$env:LOCALAPPDATA\spt-core\bin\spt.exe" -Force; "HFENDULEAM on c7e7d9e"

Swap HFENDULEAM to c7e7d9e


HFENDULEAM on c7e7d9e


Bash

ssh -o BatchMode=yes david@100.100.62.43 "cd ~/spt-core-deploy && git fetch -q origin dev-freeform && git checkout -q c7e7d9e && nohup \$HOME/.cargo/bin/cargo build --release -p spt > /tmp/spt-deploy-build.log 2>&1 & echo BUILDING"; until ssh -o BatchMode=yes david@100.100.62.43 "grep -qE 'Finished|error\[|error:' /tmp/spt-deploy-build.log" 2>/dev/null; do sleep 20; done; ssh -o BatchMode=yes david@100.100.62.43 "tail -1 /tmp/spt-deploy-build.log; pkill -x spt; sleep 1; cp ~/spt-core-deploy/target/release/spt ~/.local/bin/spt; setsid nohup ~/.local/bin/spt daemon > /tmp/spt-daemon.log 2>&1 < /dev/null & sleep 3; setsid nohup ~/.local/bin/spt ready sergey > /tmp/sergey.log 2>&1 < /dev/null & sleep 2; pgrep -af '\\.local/bin/spt' | grep -v bash"

Gravity parity deploy c7e7d9e


Command running in background with ID: bczmyhk17. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bczmyhk17.output. You will be notified when it completes. To check interim output, use Read on that file path.


what happens if a user tries to run a hosted endpoint elevated? that needs to be possible.


HFENDULEAM swapped to `c7e7d9e`; gravity parity build running. Open question from before your experiments: this machine's universe is now the fresh one (cc42d786, TELENONNURA only) — **re-join BIGNET** when you're done experimenting? Gravity's responder is live; one guided `spt subnet join BIGNET` (elevated — which now works properly) restores the fleet, and gravity's eviction cleans the old fb29977f ghosts itself.


<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.


Good probe. Walk the paths — check what the per-endpoint listener actually binds first (that's where it bites):


grep -n -E "TcpListener|LocalSocket|interprocess|bind" C:/Users/decid/Documents/projects/spt-core/crates/spt-msg/src/listener.rs | head -10; grep -n -E "TcpStream|connect|is_online" C:/Users/decid/Documents/projects/spt-core/crates/spt-msg/src/deliver.rs | head -10

Listener + deliver transport


9://! Lifecycle: [`PollListener::bind`] grabs an ephemeral `127.0.0.1:0` port and
25:use std::net::{SocketAddr, TcpListener};
33:    listener: TcpListener,
46:fn poll_ready(listener: &TcpListener, timeout_ms: i32) -> bool {
67:fn poll_ready(listener: &TcpListener, timeout_ms: i32) -> bool {
82:    pub fn bind(id: &str) -> Result<Self, String> {
83:        Self::bind_inner(id, None)
88:    pub fn bind_blocking(id: &str, timeout: Duration) -> Result<Self, String> {
90:        Self::bind_inner(id, Some(ms))
93:    fn bind_inner(id: &str, timeout_ms: Option<i32>) -> Result<Self, String> {
12://! 2. TCP `connect_timeout` + framed write. **Success is the only thing that
14://! 3. Any failure (no address, parse error, connect refused, write error) falls
20://!   is real. The structural guard is that *connect must succeed* — a recycled
21://!   process is not listening on the old ephemeral port, so the connect refuses
34:use std::net::{SocketAddr, TcpStream};
40:/// TCP connect timeout for a delivery attempt. Loopback connects resolve in
80:pub fn is_online(target: &str) -> bool {
93:/// return instead of re-implementing the resolve/connect/recycle-guard steps.
99:            match TcpStream::connect_timeout(&addr, CONNECT_TIMEOUT) {
110:                    // refused connect already prevented misdelivery — the caller


It already works — by architecture, luckily-but-also-deliberately:

## Elevated hosted endpoint, Windows

**Per-endpoint listeners are TCP loopback (`127.0.0.1:0`), not named pipes.** TCP has no elevation barrier — unelevated senders connect to an elevated endpoint's listener freely. Only the *daemon's* channels are named pipes (where the original bug lived). So an elevated agent session:

- `spt ready <id>` / `api listen` → binds TCP, receives live deliveries + rings from anyone ✅
- sends/rings out → elevated client connecting *down* to unelevated daemon pipes — works (field-proven) ✅
- daemon auto-spawn from the elevated session → now de-elevates via shell token, daemon lands unelevated, consistent for every later client ✅ (your verified fix)
- state writes → same-account universe, ACL inheritance keeps normal access ✅

## Elevated (sudo'd) hosted endpoint, unix

`spt` self-drops to `SUDO_UID` at entry — so the *messaging plumbing* (listener, perch state, daemon) always runs as the user, while the **agent process itself keeps root** for its actual work. Privilege and plumbing separated. True-root login (no sudo) = uniform root universe, also fine.

## What the abort policy actually blocks

Only this: de-elevation **target exists but spawn fails** → refuses to *auto-spawn the daemon* from that elevated process. The elevated endpoint itself is never blocked — remedy is "daemon already up" (its normal state). One genuine odd corner: headless elevated session (no desktop shell) on a machine that *also* has unelevated desktop use — shell token absent → elevated daemon would be inconsistent. That's the OS-service registration row's territory (M8).

Want live proof? Run `spt ready eltest` in your elevated window — I'll send to it unelevated from here and you'll see the message arrive.


<task-notification>
<task-id>bczmyhk17</task-id>
<tool-use-id>toolu_01ArrKZ6m7XQHyNQeYLGV84n</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\648159b6-16b2-4568-b643-7b0c98c1871d\tasks\bczmyhk17.output</output-file>
<status>completed</status>
<summary>Background command "Gravity parity deploy c7e7d9e" completed (exit code 0)</summary>
</task-notification>


Gravity parity deploy result


BUILDING
    Finished `release` profile [optimized] target(s) in 1m 29s
2498732 /home/david/.local/bin/spt daemon
2498865 /home/david/.local/bin/spt ready sergey


Both machines on `c7e7d9e` (gravity daemon 2498732, sergey listening).

Fleet picture right now:
- **gravity** — BIGNET seed-holder, sergey live, all fixes deployed
- **HFENDULEAM** — fixed binary installed, but universe is your fresh experiment (cc42d786, TELENONNURA only); not in BIGNET, no daemon currently running (next `spt` invocation auto-starts it — de-elevated even from an admin shell now)

Open items, your call:
1. **Re-join BIGNET** from here (elevated `spt subnet join BIGNET` + code from gravity — I can fetch it via ssh and walk it, or you drive)
2. **eltest live proof** of the elevated-hosted-endpoint answer (elevated `spt ready eltest`, I send to it unelevated)
3. Or done for the night — fleet's consistent, M7 closed, all fixes rig-bound (CI on `c7e7d9e` will confirm the unix abort path)


you answered the question assuming harness-hosted endpoint. what about spt-hosted endpoint, which uses the broker? won't an elevated spt-hosted endpoint break since that means broker is elevated while daemon is not?


Right — sharper than my answer. Broker lives **inside** the daemon process (ADR-0004 broker-kernel + brain, one process), so broker elevation ≡ daemon elevation; they can't differ. The real consequence of the always-unelevated invariant:

**spt-hosted endpoints inherit the broker's token → always unelevated. An *elevated* spt-hosted endpoint is now impossible — deterministically.**

Worth being precise about what changed though: it was never *soundly* possible. Before the fix you could get an elevated broker only via the accident (elevated command spawning the daemon) — and that broker's pipes then locked out every unelevated client, the M7 field bug. There's no silent path from an unelevated daemon up to an elevated child on either OS — that's the UAC/sudo security model itself, not our limitation: silent elevation is the vulnerability class those exist to prevent.

So the capability matrix today:
- **Harness-hosted elevated** — works (TCP listeners, talk-down to daemon pipes) ← the answer for "agent needs admin" right now
- **spt-hosted elevated** — refused by construction

The legit future path for spt-hosted elevated: a **consented elevation satellite** — broker asks (UAC prompt / polkit), the consent spawns a small *elevated PTY-host* process that holds just the elevated children and links back to the unelevated daemon. Slots exactly into the existing consent-escalation framework (REQ-CONSENT-2: allow-once / allow-always) + the reserved-but-refusing capability pattern. Logging it:


Edit

| Trust-row prune verb (`spt subnet prune <node>` or similar): registry GHOST rows now decay (4.10), but the dead identity's TRUST rows persist by design (trust is a user decision) — they cost dead dials every pump tick and clutter status views. BIGNET carries two such rows (09ef831e, both sides) | Ghost-eviction fix (2026-06-06) | Trust mutation = security surface; wants the elevation gate + the M8 noun shapes | M8 CLI nounification |

| Trust-row prune verb (`spt subnet prune <node>` or similar): registry GHOST rows now decay (4.10), but the dead identity's TRUST rows persist by design (trust is a user decision) — they cost dead dials every pump tick and clutter status views. BIGNET carries two such rows (09ef831e, both sides) | Ghost-eviction fix (2026-06-06) | Trust mutation = security surface; wants the elevation gate + the M8 noun shapes | M8 CLI nounification |
| Elevated spt-hosted endpoints — a consented elevation satellite: the broker lives inside the always-unelevated daemon (KH 5.7), so spt-hosted children are unelevated by construction; there is NO silent unelevated→elevated path on either OS (that is UAC/sudo's whole point). An agent needing admin powers is harness-hosted-elevated today (works: TCP listeners + talk-down pipes). The spt-hosted form needs a per-grant CONSENTED elevation: UAC prompt / polkit spawns a small elevated PTY-host satellite holding only the elevated children, linked back to the unelevated daemon — rides the REQ-CONSENT-2 escalation framework (allow-once/always) + the reserved-but-refusing capability pattern | Elevated-endpoint design grill (user 2026-06-06) | Real elevation-granting UX + a second privileged process = its own deliverable; the consent framework it rides already ships | First spt-hosted agent that needs admin powers (or the instantiate-anywhere milestone) |


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

| Trust-row prune verb (`spt subnet prune <node>` or similar): registry GHOST rows now decay (4.10), but the dead identity's TRUST rows persist by design (trust is a user decision) — they cost dead dials every pump tick and clutter status views. BIGNET carries two such rows (09ef831e, both sides) | Ghost-eviction fix (2026-06-06) | Trust mutation = security surface; wants the elevation gate + the M8 noun shapes | M8 CLI nounification |
| Elevated spt-hosted endpoints — a consented elevation satellite: the broker lives inside the always-unelevated daemon (KH 5.7), so spt-hosted children are unelevated by construction; there is NO silent unelevated→elevated path on either OS (that is UAC/sudo's whole point). An agent needing admin powers is harness-hosted-elevated today (works: TCP listeners + talk-down pipes). The spt-hosted form needs a per-grant CONSENTED elevation: UAC prompt / polkit spawns a small elevated PTY-host satellite holding only the elevated children, linked back to the unelevated daemon — rides the REQ-CONSENT-2 escalation framework (allow-once/always) + the reserved-but-refusing capability pattern | Elevated-endpoint design grill (user 2026-06-06) | Real elevation-granting UX + a second privileged process = its own deliverable; the consent framework it rides already ships | First spt-hosted agent that needs admin powers (or the instantiate-anywhere milestone) |

| ~~**Non-admin daemon spawn (both OSes)**~~ **SHIPPED 2026-06-06** (KNOWN-HAZARDS 5.7, REQ-HAZARD-ELEVATED-DAEMON-SPAWN): de-elevated spawn at `spawn_detached` (Windows: UAC linked token via `CreateProcessWithTokenW`; Linux: drop child to SUDO_UID/GID) + `Daemon::run` entry guard + the unix `spt` main-entry sudo drop (whole process re-anchored to the invoker's universe, elevation kept PROVEN for the gated commands). Remaining Linux follow-up = the install-symlink + default-account election row below (M8) | M7 acceptance run (2026-06-06) | The membership-implies-reachability activation made elevated commands daemon-spawners — correct goal, wrong token | DONE (real elevated-spawn verification on both OSes rides the next acceptance pass) |

| ~~**Ghost registry row eviction**~~ **SHIPPED 2026-06-06** (KNOWN-HAZARDS 4.10, REQ-HAZARD-REGISTRY-GHOST-ROWS): silent-peer decay — rows from a node unheard for `registry_evict_after_ms` (default 300s ≈ 10 pump cadences) evict on the registry pump tick, snapshots rewritten; own rows never decay. STALE trust rows for a dead identity still need a manual prune verb (below) | M7 acceptance run (2026-06-06) | Needs a decay/eviction policy (e.g. drop rows unrefreshed for N pump cadences; trust-row pruning verb) | DONE (fleet cleanup: 09ef831e ghost rows on both BIGNET nodes decay once the new build deploys) |

+| Elevated spt-hosted endpoints — a consented elevation satellite: the broker lives inside the always-unelevated daemon (KH 5.7), so spt-hosted children are unelevated by construction; there is NO silent unelevated→elevated path on either OS (that is UAC/sudo's whole point). An agent needing admin powers is harness-hosted-elevated today (works: TCP listeners + talk-down pipes). The spt-hosted form needs a per-grant CONSENTED elevation: UAC prompt / polkit spawns a small elevated PTY-host satellite holding only the elevated children, linked back to the unelevated daemon — rides the REQ-CONSENT-2 escalation framework (allow-once/always) + the reserved-but-refusing capability pattern | Elevated-endpoint design grill (user 2026-06-06) | Real elevation-granting UX + a second privileged process = its own deliverable; the consent framework it rides already ships | First spt-hosted agent that needs admin powers (or the instantiate-anywhere milestone) |

| ~~AMBIGUOUS render~~ **SHIPPED 2026-06-06** (rode the ghost-eviction fix): resolution refusals render valid copy-paste targets at the wansend boundary (`render_refusal`) — labels preferred, key-prefix on label collision, `subnet:id` for cross-subnet | M7 acceptance run (user 2026-06-06) | Pure render fix at the wansend/CLI boundary; carries into the M8 nounification sweep | DONE |

| Post-join address seeding: the pairing ceremony holds a live, authenticated connection to the peer, but the peer pumps then re-find each other from scratch via id-only discovery (fresh node ids must propagate to n0 DNS first) — observed live as ~1 min to first `status --nodes` convergence after a join. Seed the pump's address cache from the ceremony connection (both sides) for instant first sync | M7 acceptance run (2026-06-06) | Convergence is correct, just slow on first contact; needs an addr-cache seam the pumps consult before the resolver | M8 polish |

| Clock source priority for TOTP/rendezvous: query a well-known world clock (NTP) FIRST, fall back to local time — machines with skewed local clocks currently derive wrong steps/rendezvous tokens silently | M7 acceptance grill (user 2026-06-06) | Needs an NTP client dep + offset caching + offline fallback semantics; ±1 window covers small skew today | First field report of clock-skew join failures, or M8 polish |


Bash

cd C:/Users/decid/Documents/projects/spt-core && git add docs/DEFERRED.md && git commit -m "docs(deferred): elevated spt-hosted endpoints — consented elevation satellite

The always-unelevated daemon (KH 5.7) makes spt-hosted children
unelevated by construction (the broker lives in the daemon process; no
silent unelevated→elevated path exists on either OS by design). Harness-
hosted elevated sessions cover the need today; the spt-hosted form is a
per-grant consented elevation (UAC/polkit → elevated PTY-host satellite
linked to the unelevated daemon), riding the REQ-CONSENT-2 escalation
framework. From the 2026-06-06 elevated-endpoint design grill.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>" && git push 2>&1 | tail -1

Commit + push satellite DEFERRED row


warning: in the working copy of 'docs/DEFERRED.md', LF will be replaced by CRLF the next time Git touches it
[dev-freeform bedb0dd] docs(deferred): elevated spt-hosted endpoints — consented elevation satellite
 1 file changed, 1 insertion(+)
   c7e7d9e..bedb0dd  dev-freeform -> dev-freeform


Logged + pushed (`bedb0dd`). Summary of the design position:

- **Invariant holds:** daemon (and its broker) always unelevated — that's what keeps every unelevated client working
- **Elevated agents today:** harness-hosted elevated sessions, fully functional
- **Elevated spt-hosted:** deferred behind a *consented* elevation satellite — an elevated PTY-host the user explicitly grants into existence via the existing escalation framework, holding only the elevated children. No silent elevation, ever — that's the security model working, not a gap in it

Still open from before: BIGNET re-join for this machine, and/or the `eltest` live proof. Or call it here.


re-joined BIGNET. of note, the join had zero tolerance for a late code (strict 30s window). i tried twice and the code had shifted by the time i pressed enter, and both times was denied. i thought it was meant to be permissive of a +/-1 code window? --- after joining BIGNET, `spt subnet status` with or without `--nodes` only shows 1 endpoint (gravity-linux), even though this machine KNOWS it's an additional endpoint on that network.


re-joined BIGNET. of note, the join had zero tolerance for a late code (strict 30s window). i tried twice and the code had shifted by the time i pressed enter, and both times was denied. i thought it…


Two real reports. Check both — first, actual status output here:


PowerShell

& "$env:LOCALAPPDATA\spt-core\bin\spt.exe" subnet status 2>&1 | Select-Object -First 6; "==="; & "$env:LOCALAPPDATA\spt-core\bin\spt.exe" subnet status BIGNET --nodes 2>&1 | Select-Object -First 8

Reproduce status views post-join


SUBNET       NODES  ENDPOINTS
TELENONNURA  1      0
BIGNET       1      1

hint: `spt subnet create <name>` mints a new subnet on this machine
hint: `spt subnet join <name>` pairs this machine into one (elevated)
===
SUBNET BIGNET
  NODE                       STATUS   ENDPOINTS
  gravity-linux (03854a12…)  online   [1/1]

hint: `spt subnet create <name>` mints a new subnet on this machine
hint: `spt subnet join <name>` pairs this machine into one (elevated)
hint: `spt subnet show-code [name]` shows a subnet's joining code (elevated)


Bash

grep -n -E "fn cmd_subnet_status|NODES|node_count|peers_in" C:/Users/decid/Documents/projects/spt-core/crates/spt/src/cli.rs | head -10

Find status node-count source


1844:        out.push_str(&format!("{:<pad$}  NODES  ENDPOINTS\n", "SUBNET"));
2036:fn cmd_subnet_status(name: Option<String>, nodes: bool) -> i32 {


1800
1801	/// Build the status rows from the subnet store + registry snapshots. Pure over
1802	/// its inputs so the view is unit-tested hermetically. Counts are
1803	/// gossip-derived and stale-tolerant: a missing snapshot renders as this node
1804	/// alone with no advertised endpoints (counts catch up as gossip lands).
1805	// [impl->REQ-SUBNET-1]
1806	fn subnet_status_rows(
1807	    store: &SubnetStore,
1808	    regs: &std::collections::BTreeMap<String, spt_net::net::registry::SubnetRegistry>,
1809	    only: Option<&str>,
1810	) -> Vec<SubnetStatusRow> {
1811	    store
1812	        .subnets
1813	        .iter()
1814	        .filter(|s| only.is_none_or(|n| n == s.name))
1815	        .map(|s| {
1816	            let (mut nodes, mut endpoints) = (std::collections::BTreeSet::new(), 0usize);
1817	            if let Some(reg) = regs.get(&s.name) {
1818	                for id in reg.endpoint_ids() {
1819	                    endpoints += 1;
1820	                    for inst in reg.instances(id) {
1821	                        nodes.insert(inst.node.clone());
1822	                    }
1823	                }
1824	            }
1825	            // This node is a member even before its first row gossips in.
1826	            SubnetStatusRow { name: s.name.clone(), nodes: nodes.len().max(1), endpoints }
1827	        })
1828	        .collect()
1829	}
1830
1831	/// Render the status view (M7 plan decision 5): aligned rows, the hint footer
1832	/// always, explanatory standalone-node text on zero subnets. D2 adds
1833	/// `--nodes` per-node rows + hybrid liveness; D3 adds the join hint.
1834	// [impl->REQ-SUBNET-1]
1835	fn render_subnet_status(rows: &[SubnetStatusRow]) -> String {
1836	    let mut out = String::new();
1837	    if rows.is_empty() {
1838	        out.push_str(
1839	            "This node belongs to no subnet — a standalone node. Local messaging \
1840	             works without one; a subnet links your machines into one fabric.\n",
1841	        );
1842	    } else {
1843	        let pad = rows.iter().map(|r| r.name.len()).max().unwrap_or(0).max("SUBNET".len());
1844	        out.push_str(&format!("{:<pad$}  NODES  ENDPOINTS\n", "SUBNET"));
1845	        for r in rows {
1846	            out.push_str(&format!("{:<pad$}  {:<5}  {}\n", r.name, r.nodes, r.endpoints));
1847	        }
1848	    }
1849	    out.push_str(HINT_FOOTER);
1850	    out
1851	}
1852
1853	/// The status views' standing hint footer (M7 plan decision 5: always
1854	/// printed — the next verb is never a doc lookup away).
1855	const HINT_FOOTER: &str = "\nhint: `spt subnet create <name>` mints a new subnet on this machine\n\
1856	     hint: `spt subnet join <name>` pairs this machine into one (elevated)\n\
1857	     hint: `spt subnet show-code [name]` shows a subnet's joining code (elevated)\n";
1858
1859	/// One node's `status --nodes` row (M7 plan decision 6): identity, advertised
1860	/// label, endpoint counts, and the gossip-recency liveness verdict.
1861	struct NodeRow {
1862	    node: String,
1863	    label: Option<String>,
1864	    /// Active (listening-now) endpoint rows on this node.
1865	    active: usize,
1866	    /// All endpoint rows on this node.
1867	    total: usize,
1868	    liveness: NodeLiveness,
1869	}
1870
1871	/// The gossip-recency half of the hybrid liveness decision (M7 plan decision
1872	/// 6): the cheap signals settle most rows; only [`Probe`](NodeLiveness::Probe)
1873	/// rows cost a dial.
1874	#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1875	enum NodeLiveness {
1876	    Online,
1877	    Offline,
1878	    /// Gossip can't say (not heard recently, rows not all-Offline) — dial it.
1879	    Probe,
1880	}
1881
1882	/// A node's render form: `LABEL (keypfx…)` when labeled, `keypfx…` bare
1883	/// (REQ-SUBNET-3 — e.g. `HFENDULEAM (bcead52b…)`).
1884	fn node_display(node: &str, label: Option<&str>) -> String {
1885	    let pfx = spt_net::net::registry::key_prefix(node);
1886	    match label {
1887	        Some(l) => format!("{l} ({pfx}…)"),
1888	        None => format!("{pfx}…"),
1889	    }
1890	}
1891
1892	/// Build one subnet's per-node rows with the gossip-recency verdict. Pure
1893	/// over its inputs (the probe is the caller's impure follow-up): own node →
1894	/// online (we are running); all rows Offline → offline; heard within
1895	/// `stale_after_ms` → online; otherwise → probe.
1896	// [impl->REQ-SUBNET-1]
1897	fn node_status_rows(
1898	    reg: &spt_net::net::registry::SubnetRegistry,
1899	    heard: &std::collections::BTreeMap<String, u64>,
1900	    own_hex: &str,
1901	    now_ms: u64,
1902	    stale_after_ms: u64,
1903	) -> Vec<NodeRow> {
1904	    use spt_net::net::registry::Status;
1905	    // node → (label, active, total, any_routable)
1906	    let mut by_node: std::collections::BTreeMap<String, (Option<String>, usize, usize, bool)> =
1907	        std::collections::BTreeMap::new();
1908	    for id in reg.endpoint_ids() {
1909	        for inst in reg.instances(id) {
1910	            let e = by_node.entry(inst.node.clone()).or_default();
1911	            if e.0.is_none() {
1912	                e.0 = inst.node_label.clone();
1913	            }
1914	            e.1 += usize::from(inst.status == Status::Active);
1915	            e.2 += 1;
1916	            e.3 |= inst.status.routable();
1917	        }
1918	    }
1919	    by_node
1920	        .into_iter()
1921	        .map(|(node, (label, active, total, any_routable))| {
1922	            let liveness = if node == own_hex {
1923	                NodeLiveness::Online
1924	            } else if !any_routable {
1925	                NodeLiveness::Offline
1926	            } else if heard
1927	                .get(&node)
1928	                .is_some_and(|&at| now_ms.saturating_sub(at) <= stale_after_ms)
1929	            {
1930	                NodeLiveness::Online
1931	            } else {
1932	                NodeLiveness::Probe
1933	            };
1934	            NodeRow { node, label, active, total, liveness }
1935	        })
1936	        .collect()
1937	}
1938
1939	/// Render one subnet's `--nodes` table from probe-settled rows.

/// Build the status rows from the subnet store + registry snapshots. Pure over
/// its inputs so the view is unit-tested hermetically. Counts are
/// gossip-derived and stale-tolerant: a missing snapshot renders as this node
/// alone with no advertised endpoints (counts catch up as gossip lands).
// [impl->REQ-SUBNET-1]
fn subnet_status_rows(
    store: &SubnetStore,
    regs: &std::collections::BTreeMap<String, spt_net::net::registry::SubnetRegistry>,
    only: Option<&str>,
) -> Vec<SubnetStatusRow> {
    store
        .subnets
        .iter()
        .filter(|s| only.is_none_or(|n| n == s.name))
        .map(|s| {
            let (mut nodes, mut endpoints) = (std::collections::BTreeSet::new(), 0usize);
            if let Some(reg) = regs.get(&s.name) {
                for id in reg.endpoint_ids() {
                    endpoints += 1;
                    for inst in reg.instances(id) {
                        nodes.insert(inst.node.clone());
                    }
                }
            }
            // This node is a member even before its first row gossips in.
            SubnetStatusRow { name: s.name.clone(), nodes: nodes.len().max(1), endpoints }
        })
        .collect()
}

/// Render the status view (M7 plan decision 5): aligned rows, the hint footer
/// always, explanatory standalone-node text on zero subnets. D2 adds
/// `--nodes` per-node rows + hybrid liveness; D3 adds the join hint.
// [impl->REQ-SUBNET-1]
fn render_subnet_status(rows: &[SubnetStatusRow]) -> String {
    let mut out = String::new();
    if rows.is_empty() {
        out.push_str(
            "This node belongs to no subnet — a standalone node. Local messaging \
             works without one; a subnet links your machines into one fabric.\n",
        );
    } else {
        let pad = rows.iter().map(|r| r.name.len()).max().unwrap_or(0).max("SUBNET".len());
        out.push_str(&format!("{:<pad$}  NODES  ENDPOINTS\n", "SUBNET"));
        for r in rows {
            out.push_str(&format!("{:<pad$}  {:<5}  {}\n", r.name, r.nodes, r.endpoints));
        }
    }
    out.push_str(HINT_FOOTER);
    out
}

/// The status views' standing hint footer (M7 plan decision 5: always
/// printed — the next verb is never a doc lookup away).
const HINT_FOOTER: &str = "\nhint: `spt subnet create <name>` mints a new subnet on this machine\n\
     hint: `spt subnet join <name>` pairs this machine into one (elevated)\n\
     hint: `spt subnet show-code [name]` shows a subnet's joining code (elevated)\n";

/// One node's `status --nodes` row (M7 plan decision 6): identity, advertised
/// label, endpoint counts, and the gossip-recency liveness verdict.
struct NodeRow {
    node: String,
    label: Option<String>,
    /// Active (listening-now) endpoint rows on this node.
    active: usize,
    /// All endpoint rows on this node.
    total: usize,
    liveness: NodeLiveness,
}

/// The gossip-recency half of the hybrid liveness decision (M7 plan decision
/// 6): the cheap signals settle most rows; only [`Probe`](NodeLiveness::Probe)
/// rows cost a dial.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum NodeLiveness {
    Online,
    Offline,
    /// Gossip can't say (not heard recently, rows not all-Offline) — dial it.
    Probe,
}

/// A node's render form: `LABEL (keypfx…)` when labeled, `keypfx…` bare
/// (REQ-SUBNET-3 — e.g. `HFENDULEAM (bcead52b…)`).
fn node_display(node: &str, label: Option<&str>) -> String {
    let pfx = spt_net::net::registry::key_prefix(node);
    match label {
        Some(l) => format!("{l} ({pfx}…)"),
        None => format!("{pfx}…"),
    }
}

/// Build one subnet's per-node rows with the gossip-recency verdict. Pure
/// over its inputs (the probe is the caller's impure follow-up): own node →
/// online (we are running); all rows Offline → offline; heard within
/// `stale_after_ms` → online; otherwise → probe.
// [impl->REQ-SUBNET-1]
fn node_status_rows(
    reg: &spt_net::net::registry::SubnetRegistry,
    heard: &std::collections::BTreeMap<String, u64>,
    own_hex: &str,
    now_ms: u64,
    stale_after_ms: u64,
) -> Vec<NodeRow> {
    use spt_net::net::registry::Status;
    // node → (label, active, total, any_routable)
    let mut by_node: std::collections::BTreeMap<String, (Option<String>, usize, usize, bool)> =
        std::collections::BTreeMap::new();
    for id in reg.endpoint_ids() {
        for inst in reg.instances(id) {
            let e = by_node.entry(inst.node.clone()).or_default();
            if e.0.is_none() {
                e.0 = inst.node_label.clone();
            }
            e.1 += usize::from(inst.status == Status::Active);
            e.2 += 1;
            e.3 |= inst.status.routable();
        }
    }
    by_node
        .into_iter()
        .map(|(node, (label, active, total, any_routable))| {
            let liveness = if node == own_hex {
                NodeLiveness::Online
            } else if !any_routable {
                NodeLiveness::Offline
            } else if heard
                .get(&node)
                .is_some_and(|&at| now_ms.saturating_sub(at) <= stale_after_ms)
            {
                NodeLiveness::Online
            } else {
                NodeLiveness::Probe
            };
            NodeRow { node, label, active, total, liveness }
        })
        .collect()
}

/// Render one subnet's `--nodes` table from probe-settled rows.


grep -n -E "pub struct|pub fn|pub [a-z_]+:" C:/Users/decid/Documents/projects/spt-core/crates/spt-store/src/trust.rs | head -25

TrustStore API shape


90:pub struct TrustedPeer {
92:    pub pubkey_hex: String,
94:    pub subnet: String,
98:    pub label: Option<String>,
101:    pub user: Option<String>,
103:    pub paired: String,
108:pub struct TrustStore {
111:    pub peers: Vec<TrustedPeer>,
117:    pub fn load() -> TrustStore {
125:    pub fn load_from(path: &Path) -> TrustStore {
133:    pub fn save(&self) -> Result<(), TrustError> {
140:    pub fn save_to(&self, path: &Path) -> Result<(), TrustError> {
152:    pub fn is_trusted(&self, subnet: &str, pubkey_hex: &str) -> bool {
159:    pub fn peers_in<'a>(&'a self, subnet: &'a str) -> impl Iterator<Item = &'a TrustedPeer> {
172:    pub fn record(
210:    pub fn repin(
233:    pub fn revoke(&mut self, subnet: &str, pubkey_hex: &str) -> bool {


1939	/// Render one subnet's `--nodes` table from probe-settled rows.
1940	// [impl->REQ-SUBNET-1] [impl->REQ-SUBNET-3]
1941	fn render_node_rows(subnet: &str, rows: &[(NodeRow, bool)]) -> String {
1942	    let mut out = format!("SUBNET {subnet}\n");
1943	    if rows.is_empty() {
1944	        out.push_str("  (no gossip yet — pair another machine, or wait one pump cadence)\n");
1945	        return out;
1946	    }
1947	    let names: Vec<String> =
1948	        rows.iter().map(|(r, _)| node_display(&r.node, r.label.as_deref())).collect();
1949	    let pad = names.iter().map(|n| n.chars().count()).max().unwrap_or(0).max("NODE".len());
1950	    out.push_str(&format!("  {:<pad$}  STATUS   ENDPOINTS\n", "NODE"));
1951	    for ((row, online), name) in rows.iter().zip(&names) {
1952	        // Pad by char count, not byte len ('…' is multi-byte).
1953	        let fill = " ".repeat(pad - name.chars().count());
1954	        out.push_str(&format!(
1955	            "  {name}{fill}  {:<7}  [{}/{}]\n",
1956	            if *online { "online" } else { "offline" },
1957	            row.active,
1958	            row.total,
1959	        ));
1960	    }
1961	    out
1962	}
1963
1964	/// Probe a stale node: dial it over the broker's QUIC endpoint (the hybrid
1965	/// liveness's expensive half — spent only on rows gossip could not settle).
1966	/// Any failure (daemon down, no address, dial refused/timed out) reads
1967	/// offline — fail-quiet, this is a status view.
1968	fn probe_node(node_hex: &str) -> bool {
1969	    crate::wansend::probe_node(node_hex)
1970	}
1971
1972	/// Render the coming-online banner's "spt subnets joined" section + the
1973	/// concluding divider: header, underline, one `NAME: <state>` row per held
1974	/// subnet (`(none)` when empty), divider. Pure for tests.
1975	// [impl->REQ-DAEMON-3]
1976	fn render_subnets_joined(rows: &[(String, &'static str)]) -> String {
1977	    let mut out = String::from("spt subnets joined\n──────────────────\n");
1978	    if rows.is_empty() {
1979	        out.push_str("  (none)\n");
1980	    } else {
1981	        for (name, state) in rows {
1982	            out.push_str(&format!("  {name}: {state}\n"));
1983	        }
1984	    }
1985	    out.push_str("────────────────────────────────────────\n");
1986	    out
1987	}
1988
1989	/// Ensure the per-machine daemon is up for a daemon-dependent command —
1990	/// silent when it already runs; otherwise announce the transition on
1991	/// stderr (stdout stays payload-pure) and conclude with a divider before
1992	/// the command's own output (grill 2026-06-06). The membership-creating
1993	/// verbs call this because **membership implies reachability** (CONTEXT
1994	/// §subnet attachment): a sole seed-holder with no responder daemon is a
1995	/// contradiction of the subnet's purpose.
1996	// [impl->REQ-SUBNET-2] [impl->REQ-DAEMON-3]
1997	fn ensure_daemon_announced() -> Result<(), i32> {
1998	    if spt_daemon::is_running() {
1999	        return Ok(());
2000	    }
2001	    eprintln!("spt-core daemon is offline - coming online...");
2002	    if let Err(e) = spt_daemon::ensure_running() {
2003	        eprintln!("DAEMON_START_FAIL: {e}");
2004	        return Err(1);
2005	    }
2006	    let ident = match (
2007	        spt_store::hostlabel::os_hostname(),
2008	        spt_store::nodeid::load_or_create().ok().map(|i| i.public_key().to_hex()),
2009	    ) {
2010	        (Some(l), Some(hex)) => {
2011	            format!("{l} ({}…)", spt_net::net::registry::key_prefix(&hex))
2012	        }
2013	        (None, Some(hex)) => format!("{}…", spt_net::net::registry::key_prefix(&hex)),
2014	        _ => "this node".to_string(),
2015	    };
2016	    eprintln!("spt-core daemon: online - {ident}");
2017	    // Attachment states: every held subnet is attached while the daemon is
2018	    // up (CONTEXT §subnet attachment — detach verbs are deferred); a
2019	    // net-less daemon (endpoint bind failed) serves nothing: no connection.
2020	    let net_up = spt_daemon::brain::Brain::cold_start(&spt_daemon::broker_socket_name(), now_ms())
2021	        .ok()
2022	        .and_then(|mut b| b.net_status().ok())
2023	        .map(|s| s.enabled)
2024	        .unwrap_or(true); // can't ask ⇒ assume serving rather than alarm
2025	    let state = if net_up { "attached" } else { "no connection" };
2026	    let rows: Vec<(String, &'static str)> =
2027	        SubnetStore::load().subnets.iter().map(|s| (s.name.clone(), state)).collect();
2028	    eprint!("{}", render_subnets_joined(&rows));
2029	    Ok(())
2030	}
2031
2032	/// `spt subnet [status [NAME] [--nodes]]` — the membership view (REQ-SUBNET-1,
2033	/// M7 plan decisions 5 + 6). Read-only and ungated: prints membership shape,
2034	/// never secrets.
2035	// [impl->REQ-SUBNET-1]
2036	fn cmd_subnet_status(name: Option<String>, nodes: bool) -> i32 {
2037	    let store = SubnetStore::load();
2038	    if let Some(n) = &name {
2039	        if store.find(n).is_none() {
2040	            eprintln!("NO_SUCH_SUBNET:{n}");
2041	            return 2;
2042	        }
2043	    }
2044	    let snap_dir = perch::identity_dir().join("registry");
2045	    let regs = crate::wansend::load_snapshots(&snap_dir);
2046	    if !nodes {
2047	        let rows = subnet_status_rows(&store, &regs, name.as_deref());
2048	        print!("{}", render_subnet_status(&rows));
2049	        let _ = std::io::stdout().flush();
2050	        return 0;
2051	    }
2052
2053	    // --nodes: per-node rows under the hybrid liveness (decision 6).
2054	    let own_hex = spt_store::nodeid::load_or_create()
2055	        .map(|i| i.public_key().to_hex())
2056	        .unwrap_or_default();
2057	    let heard: std::collections::BTreeMap<String, u64> =
2058	        std::fs::read(spt_daemon::registryhost::RegistryHost::heard_path(&snap_dir))
2059	            .ok()
2060	            .and_then(|b| serde_json::from_slice(&b).ok())
2061	            .unwrap_or_default();
2062	    // Stale = silent for 3 advertisement cadences (the daemon re-gossips
2063	    // every pump period; missing a couple is jitter, missing three is news).
2064	    let stale_after_ms =
2065	        3 * spt_daemon::DaemonConfig::load().registry_pump_period.as_millis() as u64;
2066	    let mut out = String::new();
2067	    for sub in &store.subnets {
2068	        if name.as_deref().is_some_and(|n| n != sub.name) {

/// Render one subnet's `--nodes` table from probe-settled rows.
// [impl->REQ-SUBNET-1] [impl->REQ-SUBNET-3]
fn render_node_rows(subnet: &str, rows: &[(NodeRow, bool)]) -> String {
    let mut out = format!("SUBNET {subnet}\n");
    if rows.is_empty() {
        out.push_str("  (no gossip yet — pair another machine, or wait one pump cadence)\n");
        return out;
    }
    let names: Vec<String> =
        rows.iter().map(|(r, _)| node_display(&r.node, r.label.as_deref())).collect();
    let pad = names.iter().map(|n| n.chars().count()).max().unwrap_or(0).max("NODE".len());
    out.push_str(&format!("  {:<pad$}  STATUS   ENDPOINTS\n", "NODE"));
    for ((row, online), name) in rows.iter().zip(&names) {
        // Pad by char count, not byte len ('…' is multi-byte).
        let fill = " ".repeat(pad - name.chars().count());
        out.push_str(&format!(
            "  {name}{fill}  {:<7}  [{}/{}]\n",
            if *online { "online" } else { "offline" },
            row.active,
            row.total,
        ));
    }
    out
}

/// Probe a stale node: dial it over the broker's QUIC endpoint (the hybrid
/// liveness's expensive half — spent only on rows gossip could not settle).
/// Any failure (daemon down, no address, dial refused/timed out) reads
/// offline — fail-quiet, this is a status view.
fn probe_node(node_hex: &str) -> bool {
    crate::wansend::probe_node(node_hex)
}

/// Render the coming-online banner's "spt subnets joined" section + the
/// concluding divider: header, underline, one `NAME: <state>` row per held
/// subnet (`(none)` when empty), divider. Pure for tests.
// [impl->REQ-DAEMON-3]
fn render_subnets_joined(rows: &[(String, &'static str)]) -> String {
    let mut out = String::from("spt subnets joined\n──────────────────\n");
    if rows.is_empty() {
        out.push_str("  (none)\n");
    } else {
        for (name, state) in rows {
            out.push_str(&format!("  {name}: {state}\n"));
        }
    }
    out.push_str("────────────────────────────────────────\n");
    out
}

/// Ensure the per-machine daemon is up for a daemon-dependent command —
/// silent when it already runs; otherwise announce the transition on
/// stderr (stdout stays payload-pure) and conclude with a divider before
/// the command's own output (grill 2026-06-06). The membership-creating
/// verbs call this because **membership implies reachability** (CONTEXT
/// §subnet attachment): a sole seed-holder with no responder daemon is a
/// contradiction of the subnet's purpose.
// [impl->REQ-SUBNET-2] [impl->REQ-DAEMON-3]
fn ensure_daemon_announced() -> Result<(), i32> {
    if spt_daemon::is_running() {
        return Ok(());
    }
    eprintln!("spt-core daemon is offline - coming online...");
    if let Err(e) = spt_daemon::ensure_running() {
        eprintln!("DAEMON_START_FAIL: {e}");
        return Err(1);
    }
    let ident = match (
        spt_store::hostlabel::os_hostname(),
        spt_store::nodeid::load_or_create().ok().map(|i| i.public_key().to_hex()),
    ) {
        (Some(l), Some(hex)) => {
            format!("{l} ({}…)", spt_net::net::registry::key_prefix(&hex))
        }
        (None, Some(hex)) => format!("{}…", spt_net::net::registry::key_prefix(&hex)),
        _ => "this node".to_string(),
    };
    eprintln!("spt-core daemon: online - {ident}");
    // Attachment states: every held subnet is attached while the daemon is
    // up (CONTEXT §subnet attachment — detach verbs are deferred); a
    // net-less daemon (endpoint bind failed) serves nothing: no connection.
    let net_up = spt_daemon::brain::Brain::cold_start(&spt_daemon::broker_socket_name(), now_ms())
        .ok()
        .and_then(|mut b| b.net_status().ok())
        .map(|s| s.enabled)
        .unwrap_or(true); // can't ask ⇒ assume serving rather than alarm
    let state = if net_up { "attached" } else { "no connection" };
    let rows: Vec<(String, &'static str)> =
        SubnetStore::load().subnets.iter().map(|s| (s.name.clone(), state)).collect();
    eprint!("{}", render_subnets_joined(&rows));
    Ok(())
}

/// `spt subnet [status [NAME] [--nodes]]` — the membership view (REQ-SUBNET-1,
/// M7 plan decisions 5 + 6). Read-only and ungated: prints membership shape,
/// never secrets.
// [impl->REQ-SUBNET-1]
fn cmd_subnet_status(name: Option<String>, nodes: bool) -> i32 {
    let store = SubnetStore::load();
    if let Some(n) = &name {
        if store.find(n).is_none() {
            eprintln!("NO_SUCH_SUBNET:{n}");
            return 2;
        }
    }
    let snap_dir = perch::identity_dir().join("registry");
    let regs = crate::wansend::load_snapshots(&snap_dir);
    if !nodes {
        let rows = subnet_status_rows(&store, &regs, name.as_deref());
        print!("{}", render_subnet_status(&rows));
        let _ = std::io::stdout().flush();
        return 0;
    }

    // --nodes: per-node rows under the hybrid liveness (decision 6).
    let own_hex = spt_store::nodeid::load_or_create()
        .map(|i| i.public_key().to_hex())
        .unwrap_or_default();
    let heard: std::collections::BTreeMap<String, u64> =
        std::fs::read(spt_daemon::registryhost::RegistryHost::heard_path(&snap_dir))
            .ok()
            .and_then(|b| serde_json::from_slice(&b).ok())
            .unwrap_or_default();
    // Stale = silent for 3 advertisement cadences (the daemon re-gossips
    // every pump period; missing a couple is jitter, missing three is news).
    let stale_after_ms =
        3 * spt_daemon::DaemonConfig::load().registry_pump_period.as_millis() as u64;
    let mut out = String::new();
    for sub in &store.subnets {
        if name.as_deref().is_some_and(|n| n != sub.name) {