1	//! `spt rc <id>` — the operator-side attach pump (M12-W1, REQ-RC-1): attach a
2	//! local terminal to a broker-held PTY session.
3	//!
4	//! **One pump, swappable transport** (the doyle invariant). The attach protocol
5	//! is `serve_attach` on the target side ⇄ this pump on the operator side, both
6	//! speaking `AttachRecord` over a broker net-stream. *Local* attach is the
7	//! degenerate single-node case: the operator dials its OWN node (loopback peer)
8	//! and the broker's inbound-stream dispatch (`dispatch.rs`) runs `serve_attach`
9	//! against the same broker — the exact cross-node accept+serve path, no local
10	//! special-case branch. The one-path invariant lives at this pump, not the
11	//! transport under the stream.
12	//!
13	//! **Detach never kills the session.** The broker owns the PTY; closing our send
14	//! side ends the viewport with the session still running (`serve_attach` →
15	//! `Detached`). PTY ownership stays with the broker (the KNOWN-HAZARDS
16	//! attach-lifecycle invariant).
17	//!
18	//! **Single-Brain pump.** A `Brain` is `&mut`-single-threaded, so the main thread
19	//! owns it: a stdin reader thread only *produces* raw bytes onto an mpsc channel
20	//! (and watches for the detach keybind); the main loop interleaves draining that
21	//! channel into `send_attach_input` with `read_event_until` for inbound `Output`.
22	// [impl->REQ-RC-1]
23
24	use std::io::{Read, Write};
25	use std::sync::atomic::{AtomicU64, Ordering};
26	use std::sync::mpsc;
27	use std::time::{Duration, Instant};
28
29	use spt_daemon::attach::{request_attach, send_attach_input, send_attach_resize};
30	use spt_daemon::brain::{now_ms, Brain, BrokerEvent};
31	use spt_daemon::msg::decode_bytes;
32	use spt_net::net::attach::{AttachDecoder, AttachIntent, AttachRecord};
33
34	/// The detach prefix: ctrl-b (0x02), matching the legacy capsule's prefix so the
35	/// muscle memory carries over. `ctrl-b d` detaches; `ctrl-b ctrl-b` sends one
36	/// literal ctrl-b to the session; any other byte after the prefix is sent
37	/// through verbatim (prefix + byte). Documented in the CLI help.
38	const DETACH_PREFIX: u8 = 0x02; // ctrl-b
39	const DETACH_KEY: u8 = b'd';
40
41	/// How long the main loop blocks for an inbound event before looping back to
42	/// drain stdin — the full-duplex interleave granularity.
43	const POLL_SLICE: Duration = Duration::from_millis(40);
44
45	/// A message from the stdin reader thread to the pump.
46	enum StdinMsg {
47	    /// Raw bytes to forward to the session as `AttachRecord::Input`.
48	    Bytes(Vec<u8>),
49	    /// The operator hit the detach keybind — end the viewport, leave the session.
50	    Detach,
51	}
52
53	/// Mint operator op ids from a random 64-bit base so two `spt rc` sessions never
54	/// collide in the broker's net-op journal (a journaled `send_attach_input` op is
55	/// exactly-once at the PTY — a reused id from a prior session would be deduped,
56	/// dropping the keystroke). Random base + monotonic counter.
57	struct OpMinter(AtomicU64);
58	impl OpMinter {
59	    fn new() -> Self {
60	        let seed = spt_proto::identity::Identity::generate().seed();
61	        let base = u64::from_le_bytes(seed[..8].try_into().expect("8 bytes"));
62	        // Keep it well below u64::MAX so the counter can't wrap into another
63	        // session's base within any realistic session length.
64	        OpMinter(AtomicU64::new(base >> 1))
65	    }
66	    fn next(&self) -> u64 {
67	        self.0.fetch_add(1, Ordering::Relaxed)
68	    }
69	}
70
71	/// Translate one Windows console **key event** into standard **xterm VT** bytes
72	/// (REQ-RC-KEY-VT-TRANSLATE). The Windows legacy console delivers arrows / Home /
73	/// End / PgUp / PgDn / Insert / Delete / F-keys as KEY_EVENTs, not stdin bytes, so
74	/// the old raw byte-pump never saw them (dead keys). Reading crossterm events +
75	/// emitting STANDARD xterm VT here makes every key reach the harness as the
76	/// universal terminal contract — harness-AGNOSTIC (no win32-input-mode, no
77	/// CC-specific assumption). Pure (no I/O) so the whole mapping is unit-asserted
78	/// against a known-correct xterm table; an unknown key maps to empty (dropped,
79	/// never garbage). Ctrl+B is the detach prefix, intercepted in [`key_event_step`]
80	/// BEFORE this, so it never arrives here as `^B`.
81	// [impl->REQ-RC-KEY-VT-TRANSLATE]
82	#[cfg(windows)]
83	fn translate_key_event(ke: crossterm::event::KeyEvent) -> Vec<u8> {
84	    use crossterm::event::{KeyCode, KeyModifiers};
85	    const ESC: u8 = 0x1b;
86	    let m = ke.modifiers;
87	    let ctrl = m.contains(KeyModifiers::CONTROL);
88	    let alt = m.contains(KeyModifiers::ALT);
89	    let shift = m.contains(KeyModifiers::SHIFT);
90	    // xterm modifier parameter: 1 + Shift + 2*Alt + 4*Ctrl.
91	    let modp = 1 + shift as u8 + 2 * alt as u8 + 4 * ctrl as u8;
92	    match ke.code {
93	        KeyCode::Char(c) => {
94	            // Ctrl+<letter> → the C0 control byte (^A=1 … ^Z=26). Ctrl+B is the
95	            // detach prefix (consumed upstream), so it never reaches here.
96	            if ctrl {
97	                let lc = c.to_ascii_lowercase();
98	                if lc.is_ascii_alphabetic() {
99	                    let b = lc as u8 - b'a' + 1;
100	                    return if alt { vec![ESC, b] } else { vec![b] };
101	                }
102	            }
103	            // Plain (or Alt-prefixed) character → its UTF-8 bytes.
104	            let mut buf = [0u8; 4];
105	            let s = c.encode_utf8(&mut buf).as_bytes();
106	            if alt {
107	                let mut v = Vec::with_capacity(s.len() + 1);
108	                v.push(ESC);
109	                v.extend_from_slice(s);
110	                v
111	            } else {
112	                s.to_vec()
113	            }
114	        }
115	        KeyCode::Enter => vec![b'\r'],
116	        KeyCode::Tab => vec![b'\t'],
117	        KeyCode::BackTab => vec![ESC, b'[', b'Z'],
118	        KeyCode::Esc => vec![ESC],
119	        // [impl->REQ-HAZARD-RC-INPUT-KEY-ENCODING] Backspace=char-delete (0x7f),
120	        // Ctrl+Backspace=word-delete (0x08 ^H) — the W7 swap, native in the
121	        // translator (normalize_key_byte superseded).
122	        KeyCode::Backspace => vec![if ctrl { 0x08 } else { 0x7f }],
123	        KeyCode::Delete => csi_tilde(3, modp),
124	        KeyCode::Insert => csi_tilde(2, modp),
125	        KeyCode::PageUp => csi_tilde(5, modp),
126	        KeyCode::PageDown => csi_tilde(6, modp),
127	        KeyCode::Up => csi_final(b'A', modp),
128	        KeyCode::Down => csi_final(b'B', modp),
129	        KeyCode::Right => csi_final(b'C', modp),
130	        KeyCode::Left => csi_final(b'D', modp),
131	        KeyCode::Home => csi_final(b'H', modp),
132	        KeyCode::End => csi_final(b'F', modp),
133	        KeyCode::F(n) => f_key(n, modp),
134	        _ => Vec::new(),
135	    }
136	}
137
138	/// A CSI final-byte key (arrows / Home / End): `ESC[<final>` unmodified, else the
139	/// xterm `ESC[1;<m><final>` modified form.
140	// [impl->REQ-RC-KEY-VT-TRANSLATE]
141	#[cfg(windows)]
142	fn csi_final(final_byte: u8, modp: u8) -> Vec<u8> {
143	    if modp == 1 {
144	        vec![0x1b, b'[', final_byte]
145	    } else {
146	        let mut v = vec![0x1b, b'[', b'1', b';'];
147	        v.extend_from_slice(modp.to_string().as_bytes());
148	        v.push(final_byte);
149	        v
150	    }
151	}
152
153	/// A CSI tilde key (Insert / Delete / PgUp / PgDn / F5+): `ESC[<n>~` unmodified,
154	/// else `ESC[<n>;<m>~` modified.
155	// [impl->REQ-RC-KEY-VT-TRANSLATE]
156	#[cfg(windows)]
157	fn csi_tilde(n: u8, modp: u8) -> Vec<u8> {
158	    let mut v = vec![0x1b, b'['];
159	    v.extend_from_slice(n.to_string().as_bytes());
160	    if modp != 1 {
161	        v.push(b';');
162	        v.extend_from_slice(modp.to_string().as_bytes());
163	    }
164	    v.push(b'~');
165	    v
166	}
167
168	/// F-keys: F1–F4 = `ESC O P/Q/R/S` (modified: `ESC[1;<m>` + final); F5–F12 = the
169	/// `ESC[<n>~` tilde codes (15/17/18/19/20/21/23/24).
170	// [impl->REQ-RC-KEY-VT-TRANSLATE]
171	#[cfg(windows)]
172	fn f_key(n: u8, modp: u8) -> Vec<u8> {
173	    match n {

... [904 lines truncated] ...


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


<owl_messages>
<owl_message from="todlando-w180" priority="info">[WORKING_PERCH_NOTICE] Subagent working perch created.
Perch: todlando-w180
Agent type: spt-test-engineer
To message it: $OWL send todlando-w180 todlando</owl_message>
</owl_messages>

[OWL SYSTEM] Informational owl messages above — no acknowledgment needed. Continue your current task.

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


Engineer done: both units green (8 rc tests pass), clippy `-D warnings`=0, xterm sequences spot-checked against the ctlseqs standard — no discrepancies. Now the remaining gates: traceable + docs-drift + real bin:


PowerShell

traceable-reqs check > $null 2>&1; "TRACEABLE_EXIT=$LASTEXITCODE"; "---XTASK---"; cargo run -p xtask -- check 2>&1 | Select-Object -Last 6; "---BUILD---"; cargo build -p spt --bin spt 2>&1 | Select-Object -Last 2

Traceable + docs-drift xtask check + real bin build


TRACEABLE_EXIT=0
---XTASK---
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.53s
     Running `target\debug\xtask.exe check`
xtask check: OK
---BUILD---
   Compiling spt v0.12.1 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 29.79s


All gates green: traceable EXIT=0 · `xtask check: OK` (docs-drift clean) · real bin builds · clippy `-D warnings`=0 · 8 rc unit tests (incl the 2 new). Bug 2 complete. Commit:


Stage bug-2 changes


M  CONTEXT.md
M  crates/spt/src/rc.rs
M  docs/KNOWN-HAZARDS.md
M  traceable-reqs.toml


git commit -m @'
feat(rc): Windows key-event → xterm-VT translator — all special keys reach the harness (REQ-RC-KEY-VT-TRANSLATE)

bug 2 (operator HITL ruling: proper agnostic translator, the last v0.13.0 build
item + ship-blocker). `spt rc` read raw stdin BYTES, but the Windows legacy console
(no ENABLE_VIRTUAL_TERMINAL_INPUT) delivers arrows/Home/End/PgUp/PgDn/Insert/Delete/
F-keys as KEY EVENTS, not bytes — so the byte-pump left them DEAD.

FIX (agnostic, full fidelity): on Windows, read crossterm key EVENTS and translate
each to STANDARD xterm VT via a pure translate_key_event (verbatim xterm table:
arrows ESC[A..D, Home ESC[H/End ESC[F, tilde keys ESC[<n>~, modified ESC[1;<m><final>
/ ESC[<n>;<m>~ with m=1+Shift+2*Alt+4*Ctrl, F1-4 ESC O P..S / F5-12 ESC[<n>~),
forwarded through the SAME rc pump — harness-AGNOSTIC, NOT win32-input-mode (the W7
rejected lever). Press-only. spawn_stdin_reader cfg-splits: Windows tty → crossterm
events; Windows non-tty (piped/tests) → byte fallback (e2e injection preserved);
Unix → byte-pump unchanged (already VT). Detach stays the ctrl-b d PREFIX,
event-sourced (Option B, doyle ruling): Ctrl+B arms; armed+plain-'d'⇒Detach;
armed+Ctrl+B⇒literal 0x02; armed+other⇒0x02+translated; detach key is plain 'd' only.

SUPERSEDES the W7 normalize_key_byte swap on Windows — Backspace→0x7f and
Ctrl+Backspace→0x08 are native in the translator; normalize_key_byte + its unit
removed, REQ-HAZARD-RC-INPUT-KEY-ENCODING evidence RELOCATED into translate_key_event
(kept covered). NO int (live console = HITL); the exhaustive non-vacuous mapping unit
(every key/modifier asserts exact xterm bytes, spot-checked vs the xterm ctlseqs
standard) + the event-detach SM unit ARE the surface.

Gates: clippy --workspace -D warnings = 0; 8 rc unit tests green (incl the 2 new);
traceable EXIT=0 (REQ-RC-KEY-VT-TRANSLATE [doc,impl,unit]); docs-drift xtask check OK;
real spt bin rebuilds. KNOWN-HAZARDS 7.16 (+ 7.13 supersede) + CONTEXT note.
HITL acceptance = operator (arrows/Home/End/F-keys/Backspace/Ctrl+Backspace/detach in
a real CC rc session). doyle gates next — the last ship-blocker.

Co-authored by: todlando
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NVVByRoZnz85acTkVJ1uAP
'@

Commit the RC VT translator


[v0.13.0-delivery-control bf32b8c] feat(rc): Windows key-event → xterm-VT translator — all special keys reach the harness (REQ-RC-KEY-VT-TRANSLATE)
 4 files changed, 444 insertions(+), 68 deletions(-)


Committed @bf32b8c. Surface bug 2 to doyle — the last ship-blocker:


Bash

$OWL send doyle <<'EOF'
BUG 2 (RC VT translator) READY FOR GATE @bf32b8c — REQ-RC-KEY-VT-TRANSLATE [doc,impl,unit] registry-first, the LAST v0.13.0 build item. Built per your design + Option-B detach ruling.

IMPL (rc.rs): pure translate_key_event(KeyEvent)->Vec<u8> = standard xterm VT (verbatim table: arrows ESC[A..D, Home/End ESC[H/F, tilde ESC[<n>~, modified ESC[1;<m><final> / ESC[<n>;<m>~ m=1+Shift+2Alt+4Ctrl, F1-4 ESC O P..S / F5-12 ESC[<n>~ incl the 15/17/.. gaps) + csi_final/csi_tilde/f_key + key_event_step (event detach SM). spawn_stdin_reader cfg-split: Windows tty→crossterm events / Windows non-tty→byte fallback (e2e injection preserved) / Unix→byte-pump UNCHANGED. Press-only. Detach = ctrl-b d prefix event-sourced (Ctrl+B arms; armed+plain-'d'⇒Detach; armed+Ctrl+B⇒literal 0x02; armed+other⇒0x02+translated; Ctrl+D does NOT detach → 0x02+0x04). normalize_key_byte REMOVED; REQ-HAZARD-RC-INPUT-KEY-ENCODING evidence relocated into translate_key_event's Backspace(0x7f)/Ctrl+Backspace(0x08) arm + unit (stays covered).

UNITS (NO int — live console = HITL): exhaustive non-vacuous mapping (every key/modifier full-vec assert_eq, spot-checked vs the xterm ctlseqs standard — engineer found NO discrepancies) + event-detach SM (all 6 arms incl the load-bearing Ctrl+D-not-detach). DOCS: KNOWN-HAZARDS 7.16 + 7.13 supersede note + table row + CONTEXT note ([doc->REQ-RC-KEY-VT-TRANSLATE]).

GATES: clippy --workspace -D warnings=0; 8 rc unit tests green; traceable EXIT=0; docs-drift `xtask check: OK`; real spt bin rebuilds. Unix path untouched (cfg-split); non-tty byte fallback preserved.

Your gate criteria mapped: exhaustive mapping unit ✓ · detach-event unit ✓ · normalize_key_byte removed w/o regressing Backspace/Ctrl+Backspace ✓ · Unix untouched ✓ · non-tty fallback preserved ✓ · clippy/traceable/docs-drift ✓. Then operator HITL = real acceptance (arrows/Home/End/PgUp/Dn/Del/F-keys + Backspace=char/Ctrl+Backspace=word + ctrl-b d detach in a real CC session). On your gate-pass → batched PATH deploy → operator HITL everything → PR → deployah cuts v0.13.0. ALL build waves now done pending your gate. Surfacing.
EOF

Surface bug 2 to doyle for gate


➜ SENT:doyle


**Bug 2 (RC VT translator) shipped @bf32b8c → surfaced to doyle.** All v0.13.0 build waves complete, pending doyle's gate.

**This session — 4 ship-blockers built + gated/surfaced:**
- W4 picker UX @ed1aa04
- WMI daemon-window fix @082f5ed
- Bugs 3+4 attach-online race @5c0870c
- Bug 2 RC VT translator @bf32b8c (last build item)

**Bug 2 delivered:** Windows `spt rc` now reads crossterm key events → standard xterm VT (`translate_key_event`, verbatim table), so arrows/Home/End/PgUp/PgDn/Insert/Delete/F-keys all reach the harness — agnostic, not win32-input-mode. cfg-split (events on tty / byte fallback non-tty / Unix unchanged); `ctrl-b d` detach event-sourced (Option B); `normalize_key_byte` superseded. Exhaustive non-vacuous mapping unit (spot-checked vs xterm ctlseqs) + detach-SM unit; no int (live console = HITL). All gates green.

On doyle's gate-pass: batched PATH deploy → operator HITL → PR (gravity-linux hard-legs) → deployah cuts v0.13.0. Nothing more to build on my side — waiting on the gate.


<task-notification>
<task-id>bv8r78fk1</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/4" id="793fcdd8" type="msg" from="doyle">BUG 2 GATE-PASS @bf32b8c (REQ-RC-KEY-VT-TRANSLATE). Full re-verify, all green:
- clippy --workspace --all-targets -D warnings = exit 0
- 8 rc units (incl translate_key_event_emits_exact_xterm_vt exact-byte non-vacuous + key_event_step_detach_sm all 6 arms incl Ctrl+D-not-detach)
- traceable EXIT=0: REQ-RC-KEY-V</EVENT-PART>
<EVENT-PART seq="2/4" id="793fcdd8">T-TRANSLATE [doc,impl,unit] + REQ-HAZARD-RC-INPUT-KEY-ENCODING [impl,unit] STILL covered (relocated to translate_key_event Backspace arm — clean)
- docs-drift xtask check: OK
- xterm table verified verbatim vs ctlseqs standard; Unix untouched (cfg-split); non-tty byte fallback intact; detach event SM mirrors byte path

ALL v0.13.</EVENT-PART>
<EVENT-PART seq="3/4" id="793fcdd8">0 build items now GATE-PASSED (window + 3+4 + bug2). Last build item done.

NON-BLOCKING follow-up note (do NOT hold ship): Ctrl+&lt;non-letter&gt; (Ctrl+], Ctrl+\, Ctrl+_, Ctrl+@) falls to literal char, not its C0 control byte — design scoped Ctrl→C0 to letters only, so in-scope; mint a follow-up REQ next session IF a harness needs </EVENT-PART>
<EVENT-PART seq="4/4" id="793fcdd8">those. Logged, not a gate fail.

NEXT = batched PATH deploy (operator-facing: stop daemon + close rc + Copy-Item opbuild→PATH + verify SHA) → operator HITL on the deployed bin → PR (gravity-linux hard-legs, I track) → deployah v0.13.0 MINOR. Surfacing the deploy to the operator now.</EVENT-PART></event>
</task-notification>


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


doyle **BUG 2 GATE-PASS @bf32b8c** — full re-verify all green, REQ-HAZARD-RC-INPUT-KEY-ENCODING still covered (relocated cleanly). **ALL v0.13.0 build items now gate-passed** (window + 3+4 + bug 2). Last build item done.

Non-blocking note logged: Ctrl+`<non-letter>` (Ctrl+]/\\/_/@) falls to literal char, not C0 — in-scope (design scoped Ctrl→C0 to letters); follow-up REQ next session only if a harness needs it. Correctly NOT gold-plating it now (no REQ, no request).

Next is doyle/operator-driven (batched PATH deploy → operator HITL → PR → deployah v0.13.0). My build work is complete. Update the Psyche commune to reflect completion (the queued one still said "resume bug 2"):


Write

<live-context>
# v0.13.0 BUILD COMPLETE — all items gate-passed (supersedes the prior "resume bug 2" commune)

Bug 2 (RC VT translator) is DONE + doyle GATE-PASS @bf32b8c (REQ-RC-KEY-VT-TRANSLATE [doc,impl,unit]). That was the LAST v0.13.0 build item. ALL build items now gate-passed this session: W4 picker UX @ed1aa04, WMI daemon-window @082f5ed, bugs 3+4 attach-online race @5c0870c, bug 2 @bf32b8c. Plans/design @b26f2b3.

## Bug 2 as shipped
Windows `spt rc` reads crossterm key EVENTS → standard xterm VT (pure translate_key_event, verbatim ctlseqs table) so arrows/Home/End/PgUp/Dn/Ins/Del/F-keys + modifiers all reach the harness — AGNOSTIC, not win32-input-mode. spawn_stdin_reader cfg-split: Windows tty→events / Windows non-tty→byte fallback (e2e injection preserved) / Unix→byte-pump UNCHANGED. Detach = ctrl-b d PREFIX event-sourced (Option B: Ctrl+B arms; armed+plain-'d'⇒Detach; armed+Ctrl+B⇒literal 0x02; armed+other⇒0x02+translated; Ctrl+D does NOT detach). normalize_key_byte REMOVED; REQ-HAZARD-RC-INPUT-KEY-ENCODING evidence relocated into translate_key_event's Backspace(0x7f)/Ctrl+Backspace(0x08) arm + unit (still covered). NO int (live console = HITL); exhaustive non-vacuous mapping unit + event-detach SM unit. Gates: clippy 0, 8 rc units, traceable 0, xtask docs-drift OK, real bin. KNOWN-HAZARDS 7.16 (+7.13 supersede) + CONTEXT note.

## Logged follow-up (doyle, non-blocking — NOT done, by design)
translate_key_event maps Ctrl+<letter>→C0 only; Ctrl+<non-letter> (Ctrl+] / \ / _ / @) falls to the literal char, not its C0 control byte. In-scope (design scoped Ctrl→C0 to letters). doyle logged it; mint a follow-up REQ next session ONLY IF a harness needs those. Did not gold-plate (no REQ, no request → no untracked work).

## NEXT (doyle/operator-driven — NOT my build)
doyle batched PATH deploy (operator-facing: stop daemon + close rc + Copy-Item opbuild→PATH + verify SHA) → operator HITL on the deployed bin (arrows/Home/End/F-keys + Backspace=char/Ctrl+Backspace=word + ctrl-b d detach in a real CC session; also the W4 picker, 3+4 attach, window) → PR (gravity-linux hard-legs, doyle tracks) → deployah cuts v0.13.0 MINOR. I'm idle on build — stand ready for any HITL-surfaced fix doyle dispatches. After v0.13.0: W6 (perri translation binary, release-gated) + deferred (Layer F gravity, A2 SEED REQ-HAZARD-DRIVEN-BY-IDLE-REMOTE-EVICT, W1b F2 forkpty park bound).

## Process held all session
repro-first RED→GREEN; ONE spt-test-engineer per item (background, ≤4-iter, test-only); I own src/REQ/docs + breaking-test fixes; gate-toggle for non-vacuity; registry-first; surface to doyle for independent gate. The false-red catch (output()/closed-stdin) + gate-toggle proofs earned doyle's praise.
</live-context>
<project-context>
v0.13.0 delivery-control: BUILD COMPLETE — every build wave doyle-GATE-PASSED (W1/W1b/W2/W3/W4/W5/W7/F1 + WMI-window + bugs 3+4 + bug 2). Architectural fact added this session: Windows `spt rc` keyboard input is now a crossterm key-event→standard-xterm-VT translator (agnostic, full key fidelity), Unix stays the byte-pump (already VT) — cfg-split; the W7 normalize_key_byte swap is superseded (folded into translate_key_event). Remaining to SHIP: doyle's batched PATH deploy → operator HITL on the deployed bin → PR (gravity-linux hard-legs confirm) → deployah cuts v0.13.0 (MINOR — new delivery-control behavior + the rc input-fidelity upgrade). Post-v0.13.0: W6 (perri translation binary, release-gated) is the next feature; deferred/doyle-tracked = Layer F gravity, REQ-HAZARD-DRIVEN-BY-IDLE-REMOTE-EVICT (A2), W1b F2 (forkpty park bound), and the logged Ctrl+<non-letter>→C0 follow-up (mint a REQ only if a harness needs it).
</project-context>


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

<live-context>
# v0.13.0 BUILD COMPLETE — all items gate-passed (supersedes the prior "resume bug 2" commune)

Bug 2 (RC VT translator) is DONE + doyle GATE-PASS @bf32b8c (REQ-RC-KEY-VT-TRANSLATE [doc,impl,unit]). That was the LAST v0.13.0 build item. ALL build items now gate-passed this session: W4 picker UX @ed1aa04, WMI daemon-window @082f5ed, bugs 3+4 attach-online race @5c0870c, bug 2 @bf32b8c. Plans/design @b26f2b3.

## Bug 2 as shipped
Windows `spt rc` reads crossterm key EVENTS → standard xterm VT (pure translate_key_event, verbatim ctlseqs table) so arrows/Home/End/PgUp/Dn/Ins/Del/F-keys + modifiers all reach the harness — AGNOSTIC, not win32-input-mode. spawn_stdin_reader cfg-split: Windows tty→events / Windows non-tty→byte fallback (e2e injection preserved) / Unix→byte-pump UNCHANGED. Detach = ctrl-b d PREFIX event-sourced (Option B: Ctrl+B arms; armed+plain-'d'⇒Detach; armed+Ctrl+B⇒literal 0x02; armed+other⇒0x02+translated; Ctrl+D does NOT detach). normalize_key_byte REMOVED; REQ-HAZARD-RC-INPUT-KEY-ENCODING evidence relocated into translate_key_event's Backspace(0x7f)/Ctrl+Backspace(0x08) arm + unit (still covered). NO int (live console = HITL); exhaustive non-vacuous mapping unit + event-detach SM unit. Gates: clippy 0, 8 rc units, traceable 0, xtask docs-drift OK, real bin. KNOWN-HAZARDS 7.16 (+7.13 supersede) + CONTEXT note.

## Logged follow-up (doyle, non-blocking — NOT done, by design)
translate_key_event maps Ctrl+<letter>→C0 only; Ctrl+<non-letter> (Ctrl+] / \ / _ / @) falls to the literal char, not its C0 control byte. In-scope (design scoped Ctrl→C0 to letters). doyle logged it; mint a follow-up REQ next session ONLY IF a harness needs those. Did not gold-plate (no REQ, no request → no untracked work).

## NEXT (doyle/operator-driven — NOT my build)
doyle batched PATH deploy (operator-facing: stop daemon + close rc + Copy-Item opbuild→PATH + verify SHA) → operator HITL on the deployed bin (arrows/Home/End/F-keys + Backspace=char/Ctrl+Backspace=word + ctrl-b d detach in a real CC session; also the W4 picker, 3+4 attach, window) → PR (gravity-linux hard-legs, doyle tracks) → deployah cuts v0.13.0 MINOR. I'm idle on build — stand ready for any HITL-surfaced fix doyle dispatches. After v0.13.0: W6 (perri translation binary, release-gated) + deferred (Layer F gravity, A2 SEED REQ-HAZARD-DRIVEN-BY-IDLE-REMOTE-EVICT, W1b F2 forkpty park bound).

## Process held all session
repro-first RED→GREEN; ONE spt-test-engineer per item (background, ≤4-iter, test-only); I own src/REQ/docs + breaking-test fixes; gate-toggle for non-vacuity; registry-first; surface to doyle for independent gate. The false-red catch (output()/closed-stdin) + gate-toggle proofs earned doyle's praise.
</live-context>
<project-context>
v0.13.0 delivery-control: BUILD COMPLETE — every build wave doyle-GATE-PASSED (W1/W1b/W2/W3/W4/W5/W7/F1 + WMI-window + bugs 3+4 + bug 2). Architectural fact added this session: Windows `spt rc` keyboard input is now a crossterm key-event→standard-xterm-VT translator (agnostic, full key fidelity), Unix stays the byte-pump (already VT) — cfg-split; the W7 normalize_key_byte swap is superseded (folded into translate_key_event). Remaining to SHIP: doyle's batched PATH deploy → operator HITL on the deployed bin → PR (gravity-linux hard-legs confirm) → deployah cuts v0.13.0 (MINOR — new delivery-control behavior + the rc input-fidelity upgrade). Post-v0.13.0: W6 (perri translation binary, release-gated) is the next feature; deferred/doyle-tracked = Layer F gravity, REQ-HAZARD-DRIVEN-BY-IDLE-REMOTE-EVICT (A2), W1b F2 (forkpty park bound), and the logged Ctrl+<non-letter>→C0 follow-up (mint a REQ only if a harness needs it).
</project-context>


Commune updated. **v0.13.0 build complete — all items gate-passed.** Nothing more to build on my side; standing ready for any HITL-surfaced fix doyle dispatches.

**Session close — 4 ship-blockers, all built + doyle-gated:**

| Item | Commit | REQ |
|---|---|---|
| W4 picker UX | @ed1aa04 | REQ-RUN-PICKER / REQ-PICKER-4 |
| WMI daemon-window | @082f5ed | REQ-HAZARD-WMI-DAEMON-WINDOW |
| Bugs 3+4 attach-online race | @5c0870c | REQ-HAZARD-RC-ATTACH-ONLINE-RACE |
| Bug 2 RC VT translator | @bf32b8c | REQ-RC-KEY-VT-TRANSLATE |

Every build wave (W1·W1b·W2·W3·W4·W5·W7·F1 + window + 3+4 + bug 2) is gate-passed. Ship path now doyle/operator-driven: **batched PATH deploy → operator HITL → PR (gravity-linux hard-legs) → deployah cuts v0.13.0 (MINOR).**

Process that held throughout: repro-first RED→GREEN, one test-engineer per item, gate-toggle non-vacuity, registry-first, independent doyle gate. Logged for next session (not gold-plated): Ctrl+`<non-letter>`→C0 — mint a REQ only if a harness needs it.