---
name: subnet-peer-pump-stall-rca
description: "RCA 2026-07-08: peer pump stall = a POST-DIAL peer_step brain-IPC read hits the 30s deadline (dial EXONERATED by enlyzeam field capture — it fast-completes ~100ms). Not network, not the dial."
metadata: 
  node_type: memory
  type: project
  originSessionId: b8785184-d487-4bba-9217-84d045b5c5d5
---

**Symptom (operator /diagnose 2026-07-08):** HFENDULEAM + ENLYZEAM (and a 0.29.x DESKTOP on BS-Resources) `spt subnet status` shows member counts but `nodes: []` — no node sees any peer. `peer pump STALLED (Ns since last tick)`.

**ROOT (captured, definitive):** the peer pump's **brain-IPC read to the broker times out every round** — foreground `spt daemon run` stderr shows `PEER_PUMP_FAIL: brain IPC read deadline elapsed` + `PEER_PUMP_RESTART: supervised restart in 10s/20s/...`. Chain:
1. Pump dials its paired peers through the broker (`brain.net_dial`, bounded by `PUMP_PEER_IO_TIMEOUT` = 30s, pump/mod.rs).
2. Most paired peers are OFFLINE. The broker's iroh dial to an offline/unreachable-but-resolvable peer does NOT fast-fail — it blocks on iroh's own longer connect timeout (>30s). Proof: trace had ZERO `PUMP_PEER_FAIL:{peer}` (ordinary fast-fail) lines — only the 30s deadline timeouts → the dial HUNG, didn't fail fast.
3. A `TimedOut` brain-IPC read POISONS the pump client (REQ-HAZARD-PUMP-IPC-DEADLINE, peer_outcome pump/mod.rs:601) → `run_peer_pump` returns Err → `supervise_pump` restarts with DOUBLING backoff (`next_backoff`, fast death <60s doubles): 5→10→20→40→80→160→300s cap.
4. So the pump sits in backoff ~all the time → never completes a round → never advertises this node's live presence nor connects peers → `nodes:[]` on every node → mutual blindness.

**Why it correlated with the BS-Resources join** (operator's key clue): enlyzeam had JUST joined BS-Resources (2→3 subnets), adding ~5 mostly-offline paired member nodes to the pump's fan-out. That makes a >30s offline-peer dial hit CERTAIN every round → pump wedged permanently.

**Network is HEALTHY — exonerated 4 ways:** (a) the BS-Resources join ceremony reached its peers moments before; (b) a traced standalone iroh probe (built as spt-net example `connprobe`, reusing `NetEndpoint::bind` — SAME path as daemon) dialed enlyzeam→HFENDULEAM and REACHED the peer in 339ms (discovery+relay+holepunch+QUIC handshake all worked); (c) HFENDULEAM's discovery TXT (`_iroh.<z32>.dns.iroh.link`) is globally resolvable via 1.1.1.1/8.8.8.8/enlyzeam; (d) relay `usw1-1.relay.n0.iroh-canary.iroh.link` is a live iroh relay. Clocks synced (w32time healthy both — NOT the [[join-truth-build-progress]] KH7.35 clock-step). Family-gate (v0.17.0) correctly binds IPv4-only on HFENDULEAM's broken public-v6 (Tailscale-ULA-only, no ::/0). Broker is fine (serves messaging; `PAIR_MEET_UP` rendezvous rotation runs normally every ~30s TOTP step per subnet).

**FIX DIRECTION — OPERATOR RULING (2026-07-08): one peer must NOT block all others; peer discovery must be async / per-peer-independent.** Two coupled defects in `run_peer_pump`: (1) SEQUENTIAL fan-out (`for peer in fan_targets` dials one-at-a-time, each up to 30s → peer N+1 waits behind peer N); (2) WHOLE-ROUND POISON (`peer_outcome(...)?` — a TimedOut aborts the ENTIRE round via `?` → supervise_pump doubling-backoff restart, resetting ALL conns).
- **ARCHITECTURAL (durable):** per-peer concurrency + fault isolation. Pump issues NON-BLOCKING dial requests; broker (already async tokio+iroh) returns connection/presence results as async events (D4c presence seam) — no serial per-peer block. A peer TimedOut drops ONLY that peer + reschedules ONLY it; NEVER aborts the round or restarts the pump. Supervised-restart reserved for a dead BROKER conn, not a dead peer. (Single-thread+bounded-read `REQ-HAZARD-PUMP-IPC-DEADLINE` was defensive — stopped infinite wedge but coupled every peer's fate.)
- **TACTICAL stopgap — CORRECTED (doyle/todlando 2026-07-08):** my naive "add a broker per-dial bound ≪30s" is WRONG — that bound ALREADY SHIPPED v0.8.3 (KH7.8, wraps `NetHost::dial` connect in `timeout(10s)`) yet 0.29.x STILL stalls with ZERO `PUMP_PEER_FAIL`. So the 10s bound does NOT bite a RESOLVABLE-offline iroh peer (v0.8.3 test used an UNREACHABLE addr, not resolvable-dead). My field pin: zero `PUMP_PEER_FAIL` + the 30s BRAIN-IPC deadline (not a 10s dial fail) → the hang is NOT in the wrapped iroh dial; the broker never returns at all within 30s. todlando is RCA-ing WHY (W1 REQ-PUMP-DIAL-FASTFAIL) before building. See [[pump-truth-progress]].
- **LANE:** doyle owns/scopes + REQ, todlando builds, doyle gates, deployah publishes. Routed to doyle 2026-07-08 (RCA + design). NOT deployah's build lane.

**PUMP-TRUTH W1 ARBITER (todlando hermetic repro 2026-07-08, `rca/pump-w1-fastfail` @f366860, `tests/pump_blackhole_rca.rs`):** DURABLE finding — **the 10s wrap BITES in every reproducible mode.** A real `NetHost` (`BindScope::All`, `membership:None`→connect-only) dialing an RFC5737 TEST-NET-1 black-hole (`192.0.2.1:9999`) under a 500ms bound: direct/relay-off 510ms, direct/relay-on(prod N0Default) 501ms, id-only-discovery(NXDOMAIN) 504ms — ALL cut with the ordinary `broker QUIC op exceeded the bound` error. So `block_on(timeout(dur,connect))` fires; **"iroh connect escapes the wrap" (my earlier hypothesis) is REFUTED**; W1-as-scoped (fast-fail the dial) is ALREADY satisfied. **Reframe (doyle CONCUR):** if `host.dial` always returns ≤10s the brain's 30s IPC deadline can't elapse — yet the field shows it — so the >30s hang is OFF the wrapped dial. **deployah field pre-fact (decisive): enlyzeam has NO `peer-addrs.json`** → `dial_seeded` has no seed → EVERY dial is id-only-discovery (seeded-direct path skipped). With seeded + id-only-FAIL both fast-failing, by elimination the field escape = **id-only-discovery-SUCCEEDS** (a real stale TXT resolves → iroh relay-connect → waits for the ABSENT peer). Root candidates now: (a) the DNS-discovery-RESOLVE span, or (b) the relay-WAIT after resolve, escaping the bound — OR full-bound × sequential N peers > 30s (= the W2 sequential-fan-out defect, W1 satisfied). **Two residuals need real-fleet evidence** (hermetic can't synth a stale TXT): id-only-discovery-succeeds relay-wait + time-driver STARVATION under 3-subnet load (my repro ran an idle runtime). **deployah field instrument (primary, post-musl-CI): `host.dial` entry/exit timestamps + `dial_seeded` kind eprintln + offline-peer TXT-resolvability** — settles which sub-mode AND in-wrap-starvation vs off-wrap. todlando partial synth (inject a real relay-url onto an absent-peer addr → relay-wait half only; post-CI cross-check). **RELAY-WAIT SYNTH RAN 2026-07-08 (@3d95788, box free post-musl-v0.30.0): Half-2 BITES the bound — 510ms.** Home relay usw1-1.n0-canary assigned + injected onto an absent-peer addr; iroh relay-connect + wait-for-absent-peer CUT at the 500ms bound. So direct BITES + relay-wait BITES → by elimination the escape (if deployah's field confirms >30s) is **Half-1 the DNS-discovery-RESOLVE span** — the ONE half a hermetic synth can't hit (needs a real stale TXT; my synth injects the relay-url + bypasses DNS). **deployah's field (real stale TXT + host.dial entry/exit) is the sole arbiter for Half-1 = the root-lock.** Likely FIX SITE (pending field, doyle-refined): the resolve is probably a BLOCKING/un-cancellable span (a DNS syscall or a pkarr await `tokio::timeout` can't cut) while the QUIC connect is a proper cancellable future (why the whole-connect wrap already bites). Fix = SURGICAL to the resolve: `spawn_blocking` it, or use iroh's own discovery timeout, or a cancel-token around the resolve — NOT re-wrapping the whole `connect-by-id` (already cut). Do NOT re-wrap connect. NO fix, REQ-PUMP-DIAL-FASTFAIL activation HELD pending 3-way root-lock. Shared-box: no builds on hfenduleam while musl-0.30.0 CI runs there.

**SYNTH SUITE COMPLETE (2026-07-08, @1ac6c27) — EVERY hermetically-isolable segment BITES the wrap; refutation-count 5.** Half-1 DNS-resolve REFUTED too (deployah measured the real iroh-TXT resolver = 2.9s, empirical beats by-elimination). Full result: direct-connect BITES (×2), relay-wait-no-session BITES (510ms), discovery-resolve 2.9s (deployah), stale-session-drop-B BITES 502ms (CAVEATED — drop(b) gracefully closes the relay session → degrades to no-session fast-reject → does NOT hold a stale-LIVE session), prove_membership BITES 506ms (A membership:Some connects B membership:None+alive loopback, connect instant, A's seed-proof READ hangs on B's silence, bound cuts it → prove IS cancellable). **CONCLUSION: no isolated segment escapes the 10s wrap. SOLE remaining suspect = a truly stale-LIVE relay session** (peer dies ABRUPTLY so the relay session persists → relay forwards A's handshake to the dead-but-session-live peer → the composite the field shows). in-process `drop()` CAN'T emulate it (graceful close). Untested because: my synths used membership:None (skip prove) + no persisted session; the FIELD has membership:Some + real stale-live sessions together. **ABRUPT-KILL SYNTH DONE (@6653bae): taskkill /F TEARS the session.** examples/stale_peer stands a real relay session; A PRE-KILL-connected to live B via the relay (187ms = session live confirmed); `taskkill /F` B; POST-KILL dial BITES 505ms → process death → OS RST → relay tears B's session → no-session fast path. **Hermetic-KILL route EXHAUSTED** — no LOCAL kill holds a stale-live session (kill = OS RST → relay tears it instantly; the field's persistence needs a NETWORK-dead peer: machine off/partitioned → NO RST reaches the relay → session lingers via TCP keepalive-timeout, minutes). **NEXT FORK (awaiting doyle):** (1) todlando SUSPEND-B synth — freeze the child (NtSuspendProcess/pssuspend, no elevation, I own it) instead of killing → a frozen B keeps its relay TCP socket OPEN (no RST) so the session lingers, but frozen magicsock won't answer the forwarded handshake = the field mode; OR (2) deployah's field with a REAL network-dead peer (was Windows-elevation-blocked — now the fallback if suspend also fails). Worktree `.worktrees/pump-w1-stale` (off rca/pump-w1-fastfail @6653bae, has stale_peer example + all synths) kept for the suspend synth.

**SUSPEND-B SYNTH DONE 2026-07-08 (@a7a3d41, todlando) — refutation #6, the SOLE remaining hermetic suspect EXONERATED; hermetic route EXHAUSTED.** Froze B via `NtSuspendProcess` (GetProcAddress ntdll, no elevation — own the child; raw-extern posture like daemon.rs; unix fallback `kill -STOP`) instead of killing → no RST → relay socket stays open. Baseline A1 live-connected B via relay (176ms, session live). Freeze ok. Fresh A2 (no cached path) dialed frozen B via relay-url only. **Result: BITES 514ms @ 500ms bound.** DECISIVE LINGER-PROBE (12s bound re-run): rode to **12.0155s** before the wrap cut it — a no-session relay fast-rejects ~500ms, so the full-12s wait PROVES the relay STILL HELD B's session + forwarded A2's handshake to the frozen non-answering peer. So **(1) the session LINGERED** (the faithful field composite `drop()`/`taskkill` could NOT emulate — those RST-tear the session) **AND (2) the stale-live-session handshake is CANCELLABLE** — the wrap cuts it at ANY bound (500ms→514ms, 12s→12.0155s). ⇒ a 10s field bound WOULD fire this as ordinary `PUMP_PEER_FAIL`, NOT the >30s brain deadline. **doyle's #1 suspect (stale-LIVE-relay-session handshake) is REFUTED.** Every synthesizable segment now bites; no in-process synth can produce the field's >30s escape. Remaining candidates are real-fleet-only: **tokio time-driver STARVATION under real 3-subnet fan-out load** (idle synth runtimes can't reproduce — the timer that fires `tokio::timeout` is itself starved) and/or **sequential-fan-out ACCUMULATION** (N peers × up-to-bound each > 30s = the W2 sequential defect, meaning W1's per-dial bound is fine and the real fix is W2). **RECOMMENDATION to doyle (sent, 2nd msg QUEUED — offline): FALL TO deployah's field** (world-writable DIAG + forced-SPT_HOME de-elevated child) per the pre-agreed fork; no further hermetic synth will move this. W1 gate HELD; W2 build blocked (post-W1-gate). Awaiting doyle's ruling.

**doyle W1 INTERIM RULING 2026-07-08 (received):** hermetic EXHAUSTED, deployah's field is now THE arbiter. **REQ-PUMP-DIAL-FASTFAIL as-scoped ('dial doesn't fast-fail') REFUTED** — the bound WORKS at every segment (all cancellable, bite at any bound). **LEADING ROOT = tokio TIME-DRIVER STARVATION under real 3-subnet fan-out** — the 10s timer can't FIRE so the dial rides to the 30s brain deadline (= zero PUMP_PEER_FAIL, real-fleet-only, why every hermetic single-dial bit). **FINAL W1 ruling GATED on deployah's field:** DIAL_ENTER print + EXIT>30s with NO 10s bite = starvation CONFIRMED. Likely re-scope: starvation-resistant bound (dedicated time-driver / offload the dial off the timer thread) AND/OR fold into W2 (concurrency kills per-runtime load + sequential accumulation). **todlando: REST — high context, NO build till the field pins it.** Next actor = deployah (field instrument); then doyle final W1 ruling → then W1/W2 build. Bindings: `membership()` = `Arc::new(move|| creds.clone())`; `SubnetCred{name,seed:vec![b;20],epoch,prev:None}`; relay-url from `host.addr().relay_urls().next().cloned()`; `with_relay_url`/`with_ip_addr` on EndpointAddr; RFC5737 `192.0.2.1` = silent black-hole.

**PUMP-TRUTH W1 — REFUTATION #5 + constrained root (deployah field, 2026-07-08 late):** Half-1 "DNS-discovery-RESOLVE hangs" was by-elimination, never measured. **deployah MEASURED → REFUTED:** SYSTEM resolver (= iroh hickory DnsDiscovery's) on a REAL published iroh TXT = OK in **2.9s** (public 1.1.1.1 = 1.2s). NOT >30s. So NXDOMAIN 504ms + relay-wait 510ms + resolve 2.9s = **ALL THREE fast-paths fast-complete**, yet field = ONE dial >30s. **Constrained root — >30s is in ONE of:** (1) pre-`bounded_block_on` delta (unwrapped → wrap it), (2) **QUIC-HANDSHAKE to a LIVE-but-STALE relay session** (relay has a live session for the dead peer → forwards → handshake waits; DIFFERS from todlando's NO-session 510ms; UNTESTED, hermetic-synthesizable), (3) **prove_membership** (nethost.rs:901-918). (2)+(3) are INSIDE the wrap — if the 10s bound isn't cutting, the await is **uncancellable/blocking** → **FIX = make that segment cancellable, NOT re-wrap.** **CAPTURE BLOCKED:** deployah's host.dial 4-segment file-log instrument (verified correct via broker.rs:3670 dispatch_net_dial→host.dial) ran 3× on enlyzeam = EMPTY — elevated ssh → `is_elevated()` → `spawn_deelevated` respawns a DETACHED de-elevated daemon dropping to the ELECTED user (≠ decid) → different SPT_HOME (no BS-Res dials) + null stdio + can't write decid-path DIAG. The lone capturing run (b1th3cpkz PEER_PUMP_FAIL) hit `Ok(None)` (no-elected-user-then=in-process-as-decid). To capture: force `spawn_deelevated→None` OR todlando hermetic-synth the stale-LIVE-relay-session (proposed to doyle; deciding). **5 refutations this RCA** (clock, infra, family-gate, 10s-bound-escape, DNS-resolve-hang) — all killed EMPIRICALLY; the gate never accepted consensus as the lock.

**Instrument used:** daemon writes NO disk trace (`pairhost.rs:572` "no daemon tracing facility"); RUST_LOG does nothing (no subscriber). BUT `supervise_pump` already `eprintln!`s `PEER_PUMP_FAIL/PANIC/RESTART` to stderr — run `spt daemon run` FOREGROUND with `Start-Process -RedirectStandardError` (NOT a `Select-Object -First` pipe, which blocks) to capture. This is the go-to for pump-stall RCA.

**Separate unconfirmed symptom same session:** new endpoint bringup ("chert"/"diagchert") stalls UNBOUND — harness launches (ccs/Claude Code process chain alive) but never registers its perch. Local perch-bind path, likely distinct from the pump/WAN issue; not root-caused.

**State left:** enlyzeam daemon restored (detached); its `ball-b` live agent was taken down for the foreground trace — operator relaunch. HFENDULEAM untouched. Diagnostic litter cleaned from repo (connprobe example + Cargo.toml dev-dep reverted). See [[spt-core-findings-backlog]], [[pump-ipc-deadline-fix]], [[broker-QUIC-deadline]].

---

**★ FIELD ARBITER — DECISIVE, dial EXONERATED (deployah, enlyzeam capture 2026-07-08 late). Refutes the dial-centric framing AND the "starvation makes the dial ride to 30s" theory.** deployah self-served the capture via `ssh decid@enlyzeam` (operator granted the hop; NOT elevation-blocked this time). **ISOLATED repro that dodges both prior blockers** (de-elevation + live-daemon disruption): copied enlyzeam's REAL `identity/` → `C:\spt-diag\home`, DROPPED `node.key` (fresh iroh key → no relay collision) + stale `notifs.db`/`pump-ops.json`; `home_tag()=hash(SPT_HOME)` (endpoint.rs:23) so the broker socket is DISTINCT → zero collision with the live 0.28.0 daemon. Fresh daemon loads the copied 3-subnet roster (SPT_DEV/BIGNET/BS-Resources, ~8 peers) → reproduces the fan-out load, identity-agnostic (dead peers hang at iroh CONNECT, before seed-proof). Instrument = env-gated `pump_diag!` (SPT_PUMP_DIAG), 3 markers: `NET_DIAL_DISPATCH` (broker.rs dispatch_net_dial arm), `DIAL_ENTER`/`DIAL_EXIT ms=.. ok/err` (nethost.rs `NetHost::dial`). Rides persistent daemon stderr (LIFECYCLE-TRUTH W3 logs/daemon.stderr.log) + world-writable file. New module `crates/spt-daemon/src/pumpdiag.rs` + 3 call sites (broker/nethost/lib), uncommitted on main, v0.30.0 build at `C:\spt-diag\spt.exe`.

**RESULT (120s run):** 3 dials, ALL `NET_DIAL_DISPATCH`→`DIAL_ENTER`→`DIAL_EXIT ms=119/88/119 **ok** conn=1/3/4`. **The dial is HEALTHY + FAST (~100ms), fully cancellable — 10s bound never even needed.** Every dial targets `14efb80c`=HFENDULEAM (a **LIVE** peer, the first fan target). Between dials, stderr: `PEER_PUMP_FAIL: brain IPC read deadline elapsed` (the 30s `PUMP_PEER_IO_TIMEOUT`) → `PEER_PUMP_RESTART in 10s`→`20s` (doubling backoff). **NO `DISPATCH` ever fires for any other peer** — the pump NEVER reaches peer #2 (the offline peers are never dialed = RED HERRINGS). Each supervised restart re-primes, re-dials ONLY peer #1 (ok), wedges again on the SAME post-dial IPC, dies at 30s. Perpetual.

**⇒ ROOT REDIRECT: the stall is DOWNSTREAM of the dial.** After peer #1's successful dial, a post-dial `peer_step` **brain-IPC READ** hits the 30s brain deadline (A-half poison → `peer_outcome` `TimedOut` → `Err` → `supervise_pump` restart). The v0.8.3 10s `bounded_block_on` (KH7.8) covers dial/open_stream/send_stream but **NOT the await-inbound-stream-data read** — so the brain's 30s deadline fires first, never the ordinary 10s per-peer error (explains the ALWAYS-zero `PUMP_PEER_FAIL`). **PRIME SUSPECT: the SYNC-PULL leg's reply read** (`sync` worker, the ONLY leg that awaits a peer response) — a peer that CONNECTS but never answers the sync request wedges the single-threaded pump 30s → whole fan-out starves. Trigger = ANY connect-then-silent peer at fan position #1 (here a LIVE cross-version 0.30-diag↔hfenduleam peer); the 3-subnet "load" worsens it (more peers, pump never drains). ALL prior hermetic theories (time-driver starvation, stale-live relay session, DNS-resolve) are moot for THIS signature — the dial exits fast+ok, nothing rides to 30s in the dial.

**★★ ROUND-2 EMPIRICAL PIN — CONFIRMED + CORRECTED (deployah, enlyzeam 2026-07-08). The wedge is the UPDATE leg, NOT sync.** Added leg-level `LEG_ENTER/LEG_EXIT i=<0..3>` markers (pump/mod.rs run_due closure) + `SYNC_REQ_SENT` (sync.rs). Every round, identical: `DIAL_EXIT ms=96 ok` → `LEG i=0 registry ms=0 ok` → `LEG i=1 notif ms=8 ok` → `LEG i=2 sync ms=72 ok` → `LEG i=3 update ms=30025 err[TimedOut] brain IPC read deadline elapsed` → `PEER_PUMP_FAIL` → restart 10s/20s. **THE WEDGE = the UPDATE leg's reply-read: `propagate.rs:373-375` `request_update`** — `let mut deadline = brain.call_deadline()` (=30s); `loop { brain.read_event_until(deadline)? }`. request_update ALWAYS runs per peer (opens stream + subscribes + sends `UpdRecord::Query` finish=false @365, then blocks reading the peer's Offer/UpToDate reply). Peer #1 (HFENDULEAM, first fan target, LIVE) accepts the conn + update stream but never answers the Query → 30s no-progress → TimedOut → request_update Err → peer_outcome POISON (pump/mod.rs:601) → whole-round abort. **Why my static "sync" guess was wrong: sync SKIPS the reply-read when the want-set is empty (this node had nothing to pull → 72ms, no read); update has NO empty-skip → always reply-reads → always eats the connect-then-silent 30s.** SAME LATENT BUG in `sync.rs:374-376` (identical read_event_until pattern) — bites the moment a sync want-set is non-empty vs a silent peer. **doyle W1 ROOT-LOCK + FIX RULING (docs/PUMP-TRUTH-TRIAGE.md @f16e2e0):** W1 = (a) reclassify the peer-response reply-read TimedOut as an ORDINARY per-peer DROP (reserve peer_outcome POISON strictly for a real broker-IPC-CARRIER desync where the wrong-stream-id safety matters) + (b) decouple/shorten the reply budget <30s (~10s, off the brain deadline) — **must cover BOTH request_update AND request_sync**; (a) alone unblocks the round. W2 = (c) concurrency (REQ-PUMP-PEER-ISOLATION — this root validates it: fan#1 HOL-blocks the whole round). LANE: doyle scoped → **todlando builds** → doyle gates → deployah publishes (counter 52). Instrument (env-gated `pump_diag!`, module `pumpdiag.rs` + call sites in broker/nethost/pump-mod/sync) is uncommitted on main @ hfenduleam working tree = EVIDENCE; reusable ssh harness `C:\spt-diag\{setup,run}.ps1` + isolated home on enlyzeam.

**(superseded static guess, kept for the trail) NEXT (proposed to doyle, awaiting steer): round-2 instrument the 4 post-dial legs** (open_stream / send_stream / **sync-reply-read** / update-read) to pinpoint the exact unbounded brain-IPC, then BOUND that read (extend deadline coverage to the reply-read path / make it cancellable like the QUIC ops) — NOT touch the dial. Capture preserved: enlyzeam `C:\spt-diag\pump-diag.log` + `C:\spt-diag\home\logs\`. Live 0.28.0 daemon untouched (pids 17088/48572 unchanged); no `C:\spt-diag` proc leak (scoped Stop-Process). ssh capture harness reusable: `C:\spt-diag\{setup,run}.ps1`.
