running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.22s
running 3 tests
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.43s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.19s
running 4 tests
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.18s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s
running 3 tests
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.49s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.15s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 3 tests
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s
running 59 tests
test reconcile::tests::failed_turn_preserves_everything ... ok
test result: ok. 59 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.16s
running 29 tests
test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.21s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.22s
running 121 tests
test result: ok. 120 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.20s
running 59 tests
test result: ok. 59 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s
running 49 tests
test result: ok. 49 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.34s
running 160 tests
test result: ok. 160 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.06s
running 21 tests
test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
running 2 tests
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.01s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
TEST_DONE


write the JIT plan for W2, verify it with doyle, execute on their greenlight


Full suite green, clippy -D clean, traceable 200/200. Gate bar met. Operator authorized commits — checking status before staging:


Bash

cd "C:\Users\decid\Documents\projects\spt-core" && git status --short && echo "--- branch ---" && git branch --show-current


<owl_messages>
<owl_message from="doyle" priority="high">W2 Q4 NAMING CORRECTION (operator, urgent — before you finalize T2.4). M12-W2-RULING.md Q4 updated.

PROBLEM: `cc` bakes "Claude Code" into harness-agnostic spt-core = wrong layer. And bare `spt` shortcut is a TRAP.

`spt`-shadow analysis (verified): a cwd `spt.cmd` first-resolves over PATH `spt.exe` ONLY in cmd.exe (cwd searched before PATH). PowerShell does NOT search cwd (needs .\spt) and Unix `.` is off-PATH → bare `spt` hits the real binary there. So a `spt` wrapper "forward args to binary" works ONLY in cmd.exe, silently no-ops in PS/Unix → inconsistent. Plus self-recursion: spt.cmd calling `spt` re-invokes itself (cwd-first). REJECT bare `spt`.

RULING:
1. spt-core W2 default shortcut basename = `spt-<id>` (harness-agnostic, DISTINCT name → no shadow, no recursion, bare-invocable via PATHEXT/.cmd + exec-bit). e.g. `spt-doyle.cmd` (Win) / `spt-doyle` (Unix, no ext +chmod).
2. Make the basename a PARAMETER, not hardcoded `cc`. An adapter/flow overrides it → spt-claude-code sets `cc-<id>`. CC-ness lives in the adapter; spt-core NEVER emits `cc`.
3. Bare "launch this project" already = `spt endpoint run` (no args → picker). No shadowing wrapper needed.

Everything else from prior Q4 (.cmd not .ps1, sentinel guard, invocation-reality docs, %* forward) stands. So: rename the generated shortcut cc-<id> → spt-<id> with a basename param defaulting to "spt". Quick change before sweep.</owl_message>
</owl_messages>

[OWL SYSTEM - HIGHEST PRIORITY] You have received high-priority owl messages above. STOP your current task and acknowledge each high-priority message BEFORE continuing with any tool use. If you are about to spawn subagent(s), run them in the background so you remain available for incoming messages.


 M CONTEXT.md
 M Cargo.lock
 M crates/spt/Cargo.toml
 M crates/spt/src/cli.rs
 M crates/spt/src/main.rs
 M docs/DEFERRED.md
 M traceable-reqs.toml
?? M12-W2-PLAN.md
?? M12-W2-RULING.md
?? crates/spt/src/picker/
--- branch ---
m12-w1-bringup-rc


doyle/operator urgent Q4 naming correction — **must apply before commit.** ACK + rework: `cc-<id>` is wrong layer (bakes Claude-Code into harness-agnostic spt-core); bare `spt` shortcut is a shadow/recursion trap. → default basename `spt-<id>`, basename a **parameter** (default `"spt"`; adapters override to `cc`).


cd "C:\Users\decid\Documents\projects\spt-core" && $OWL send doyle <<'EOF'
Caught it BEFORE commit — not finalized yet (was at git-status, hadn't staged). Reworking now:

1. Default shortcut basename = `spt-<id>` (spt-doyle.cmd / spt-doyle). Harness-agnostic, distinct name → no spt.exe shadow, no self-recursion. cc-<id> GONE from spt-core.
2. basename = a PARAMETER (default "spt"); spt-core picker passes "spt", an adapter/flow overrides (spt-claude-code → "cc"). CC-ness lives in the adapter, never spt-core.
3. Bare launch = `spt endpoint run` picker (already). No shadow wrapper. Agreed, REJECT bare `spt`/`cc` shadows.

Carrying forward unchanged: .cmd not .ps1, sentinel-guard, invocation-reality header, %* / "$@" forward.

Touch list: shortcut.rs (basename param on filename/render/write + default const + header text), view confirm-label, CONTEXT.md, traceable REQ-RUN-SHORTCUT title, plan Q4, tests. Then re-sweep (suite+clippy+traceable) and ping you to gate. Nothing committed.
EOF
echo "EXIT=$?"


➜ SENT:doyle
EXIT=0


Now rework shortcut.rs with the basename parameter:


Edit

//! `cc-<id>` launcher shortcut generation (the picker `s` keybind,
//! REQ-RUN-SHORTCUT).
//!
//! From any pre-start options set the picker bakes the current selection's
//! NON-INTERACTIVE `spt endpoint run` flags into a launcher script at the
//! project root, so a user can re-launch this exact endpoint with one command
//! (and a `cc-doyle` muscle-memory shortcut).

//! `<basename>-<id>` launcher shortcut generation (the picker `s` keybind,
//! REQ-RUN-SHORTCUT).
//!
//! From any pre-start options set the picker bakes the current selection's
//! NON-INTERACTIVE `spt endpoint run` flags into a launcher script at the
//! project root, so a user can re-launch this exact endpoint with one command
//! (a `spt-doyle` muscle-memory shortcut).
//!
//! **Basename is a PARAMETER, never `cc`** (doyle/operator 2026-06-14):
//! harness-agnostic spt-core defaults to [`DEFAULT_BASENAME`] (`spt`) →
//! `spt-<id>`. An adapter/flow OVERRIDES it (spt-claude-code sets `cc` →
//! `cc-<id>`) — the Claude-Code-ness lives in the adapter, never in spt-core.
//! The basename must be a DISTINCT token (not bare `spt`): a `spt.cmd` wrapper
//! would shadow the real `spt.exe` only under cmd.exe (cwd-first search) and
//! self-recurse, so a distinct `spt-<id>` is the safe, consistent form.


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

//! `<basename>-<id>` launcher shortcut generation (the picker `s` keybind,
//! REQ-RUN-SHORTCUT).
//!
//! From any pre-start options set the picker bakes the current selection's
//! NON-INTERACTIVE `spt endpoint run` flags into a launcher script at the
//! project root, so a user can re-launch this exact endpoint with one command
//! (a `spt-doyle` muscle-memory shortcut).
//!
//! **Basename is a PARAMETER, never `cc`** (doyle/operator 2026-06-14):
//! harness-agnostic spt-core defaults to [`DEFAULT_BASENAME`] (`spt`) →
//! `spt-<id>`. An adapter/flow OVERRIDES it (spt-claude-code sets `cc` →
//! `cc-<id>`) — the Claude-Code-ness lives in the adapter, never in spt-core.
//! The basename must be a DISTINCT token (not bare `spt`): a `spt.cmd` wrapper
//! would shadow the real `spt.exe` only under cmd.exe (cwd-first search) and
//! self-recurse, so a distinct `spt-<id>` is the safe, consistent form.

//! `cc-<id>` launcher shortcut generation (the picker `s` keybind,
//! REQ-RUN-SHORTCUT).
//!
//! From any pre-start options set the picker bakes the current selection's
//! NON-INTERACTIVE `spt endpoint run` flags into a launcher script at the
//! project root, so a user can re-launch this exact endpoint with one command
//! (and a `cc-doyle` muscle-memory shortcut).
//!
//! - **Current-OS native** (doyle Q4, rev. 2026-06-14): a `.cmd` on Windows
//!   (NOT `.ps1` — the default `PATHEXT` excludes `.ps1`, so a bare/ext-less
//!   name never resolves one and `.ps1` won't run without `powershell -File`;
//!   `.cmd`/`.bat` ARE in `PATHEXT`), a POSIX `sh` (+`chmod +x`) on Unix — a
//!   single portable form can't be both.
//!
//! **Invocation reality** (baked into the generated header so the user isn't
//! surprised):
//! - Windows + cmd.exe, in the project dir: bare `cc-<id>` works (cwd +
//!   `PATHEXT` search).
//! - Windows + PowerShell: needs `.\cc-<id>` (PowerShell refuses cwd exec but
//!   honors `PATHEXT` → finds the `.cmd`).
//! - Unix: `./cc-<id>` (`.` is not on `PATH`).
//! - A truly-bare `cc` everywhere = a PATH-installed launcher = `/spt:setup`'s
//!   job, not this project-root shortcut.
//! - **Sentinel-guarded overwrite:** the generator writes + checks a generated-by
//!   header [`SENTINEL`]. It overwrites its OWN prior output freely ("Update"),
//!   but REFUSES a same-named file that lacks the sentinel — never clobbering a
//!   user file.
//! - **Terminal actions only:** adapter[:profile] + id + (create|resume) +
//!   (start|attach|view). Kick/Instantiate/Change-adapter/Fork are
//!   interactive-only and not bakeable.
// [impl->REQ-RUN-SHORTCUT]

use std::path::{Path, PathBuf};

use super::model::RunMode;

/// The generated-by marker. Present on line 1 of every script we write; its
/// presence (and ONLY its presence) authorizes an overwrite.
pub const SENTINEL: &str = "spt-generated cc-shortcut — safe to regenerate (do not remove this line)";

/// What a write did (or refused to do).
#[derive(Debug, PartialEq, Eq)]
pub enum WriteOutcome {
    /// A new shortcut was written at this path.
    Created(PathBuf),
    /// An existing spt-generated shortcut was overwritten.
    Updated(PathBuf),
    /// A same-named file exists but lacks the sentinel — refused (the path is
    /// returned so the caller can warn precisely).
    RefusedForeign(PathBuf),
}

/// The current-OS shortcut filename for an endpoint id: `cc-<id>.cmd` on
/// Windows (PATHEXT-resolvable), `cc-<id>` (no extension) on Unix.
pub fn shortcut_filename(id: &str) -> String {
    if cfg!(windows) {
        format!("cc-{id}.cmd")
    } else {
        format!("cc-{id}")
    }
}

/// Render the script body for the current OS. Pure (no I/O) so the content is
/// unit-assertable. The [`SENTINEL`] rides a comment line near the top (`REM`
/// in cmd, `#` in sh) — [`has_sentinel`] scans the first few lines for it.
// [impl->REQ-RUN-SHORTCUT]
pub fn render_script(id: &str, adapter: &str, resume: Option<&str>, mode: RunMode) -> String {
    let args = baked_args(id, adapter, resume, mode);
    if cfg!(windows) {
        // A Windows batch shortcut. `%*` forwards any extra runtime args. Invoke
        // bare `cc-<id>` from cmd.exe in the project dir, or `.\cc-<id>` from
        // PowerShell (both resolve the .cmd via PATHEXT).
        format!(
            "@echo off\r\n\
             REM {SENTINEL}\r\n\
             REM cc-{id}: launch the `{id}` endpoint with the baked selection.\r\n\
             REM   cmd.exe (project dir):  cc-{id}      PowerShell:  .\\cc-{id}\r\n\
             spt endpoint run {args} %*\r\n"
        )
    } else {
        // A POSIX sh shortcut. Invoke `./cc-{id}` (`.` is not on PATH); `\"$@\"`
        // forwards extra runtime args.
        format!(
            "#!/bin/sh\n\
             # {SENTINEL}\n\
             # cc-{id}: launch the `{id}` endpoint with the baked selection.\n\
             #   invoke from the project dir as:  ./cc-{id}\n\
             exec spt endpoint run {args} \"$@\"\n"
        )
    }
}

/// The non-interactive flag string baked into the shortcut — terminal actions
/// only. `--create` (the default-fresh made explicit) is mutually exclusive with
/// `--resume`; attach is the default action (no flag).
fn baked_args(id: &str, adapter: &str, resume: Option<&str>, mode: RunMode) -> String {
    let mut parts = vec![
        "--adapter".to_string(),
        shell_quote(adapter),
        "--id".to_string(),
        shell_quote(id),
    ];
    match resume {
        Some(session) => {
            parts.push("--resume".to_string());
            parts.push(shell_quote(session));
        }
        None => parts.push("--create".to_string()),
    }
    match mode {
        RunMode::Start => parts.push("--start".to_string()),
        RunMode::View => parts.push("--view".to_string()),
        RunMode::Attach => {} // the default action — no flag
    }
    parts.join(" ")
}

/// Conservative quoting: endpoint ids / adapter names / session ids are charset-
/// constrained (alphanumeric, `-`, `_`, plus `:` in an adapter:profile), so a
/// bare token is safe; only quote if something unexpected appears.
fn shell_quote(s: &str) -> String {
    let safe = s
        .chars()
        .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | ':' | '.'));
    if safe && !s.is_empty() {
        s.to_string()
    } else {
        // Single-quote for sh; PowerShell also accepts single quotes as literals.
        format!("'{}'", s.replace('\'', "'\\''"))
    }
}

/// Whether `contents` was written by us (carries the [`SENTINEL`] on any of its
/// first few lines).
pub fn has_sentinel(contents: &str) -> bool {
    contents.lines().take(3).any(|l| l.contains(SENTINEL))
}

/// Write (or refuse to overwrite) the shortcut in `dir`. Sentinel-guarded:
/// a fresh path is created; an existing OURS path is updated; an existing
/// foreign path (no sentinel) is refused untouched.
// [impl->REQ-RUN-SHORTCUT]
pub fn write_shortcut(
    dir: &Path,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> std::io::Result<WriteOutcome> {
    let path = dir.join(shortcut_filename(id));
    let exists = path.exists();
    if exists {
        let current = std::fs::read_to_string(&path).unwrap_or_default();
        if !has_sentinel(&current) {
            return Ok(WriteOutcome::RefusedForeign(path));
        }
    }
    let body = render_script(id, adapter, resume, mode);
    std::fs::write(&path, &body)?;
    set_executable(&path);
    Ok(if exists {
        WriteOutcome::Updated(path)
    } else {
        WriteOutcome::Created(path)
    })
}

#[cfg(unix)]
fn set_executable(path: &Path) {
    use std::os::unix::fs::PermissionsExt;
    if let Ok(meta) = std::fs::metadata(path) {
        let mut perms = meta.permissions();
        perms.set_mode(perms.mode() | 0o755);
        let _ = std::fs::set_permissions(path, perms);
    }
}

#[cfg(not(unix))]
fn set_executable(_path: &Path) {}

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

    // [unit->REQ-RUN-SHORTCUT] the script bakes the terminal-action flags; a
    // fresh run defaults to --create + attach (no action flag).
    #[test]
    fn bakes_create_attach_by_default() {
        let body = render_script("doyle", "claude-spt:fast", None, RunMode::Attach);
        assert!(body.contains("--adapter claude-spt:fast"));
        assert!(body.contains("--id doyle"));
        assert!(body.contains("--create"));
        assert!(!body.contains("--resume"));
        assert!(!body.contains("--start") && !body.contains("--view"));
        assert!(has_sentinel(&body), "sentinel rides a comment line near the top");
    }

    // [unit->REQ-RUN-SHORTCUT] resume bakes --resume (not --create); view/start
    // bake their action flag.
    #[test]
    fn bakes_resume_and_action() {
        let body = render_script("d", "ccs", Some("sess123"), RunMode::View);
        assert!(body.contains("--resume sess123"));
        assert!(!body.contains("--create"));
        assert!(body.contains("--view"));

        let start = render_script("d", "ccs", None, RunMode::Start);
        assert!(start.contains("--create") && start.contains("--start"));
    }

    // [unit->REQ-RUN-SHORTCUT] sentinel detection only trusts our own header.
    #[test]
    fn sentinel_detection() {
        assert!(has_sentinel(&render_script("x", "a", None, RunMode::Attach)));
        assert!(!has_sentinel("#!/bin/sh\necho hi\n"), "a user script has no sentinel");
    }

    // [unit->REQ-RUN-SHORTCUT] create → update (our own) → refuse (foreign).
    #[test]
    fn write_create_update_refuse() {
        let dir = tempfile::tempdir().unwrap();
        let p = dir.path();

        // 1. fresh → Created.
        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();
        let path = match out {
            WriteOutcome::Created(path) => path,
            other => panic!("expected Created, got {other:?}"),
        };
        assert!(path.exists());

        // 2. re-generate over our own → Updated (different selection rewrites).
        let out = write_shortcut(p, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();
        assert!(matches!(out, WriteOutcome::Updated(_)));
        let body = std::fs::read_to_string(&path).unwrap();
        assert!(body.contains("--adapter ccs") && body.contains("--resume s9"));

        // 3. a foreign same-named file → RefusedForeign, untouched.
        std::fs::write(&path, "#!/bin/sh\necho mine\n").unwrap();
        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();
        assert!(matches!(out, WriteOutcome::RefusedForeign(_)));
        assert_eq!(
            std::fs::read_to_string(&path).unwrap(),
            "#!/bin/sh\necho mine\n",
            "a foreign file is never clobbered"
        );
    }
}

-//! `cc-<id>` launcher shortcut generation (the picker `s` keybind,

+//! `<basename>-<id>` launcher shortcut generation (the picker `s` keybind,

-//! (and a `cc-doyle` muscle-memory shortcut).

+//! (a `spt-doyle` muscle-memory shortcut).

+//! **Basename is a PARAMETER, never `cc`** (doyle/operator 2026-06-14):

+//! harness-agnostic spt-core defaults to [`DEFAULT_BASENAME`] (`spt`) →

+//! `spt-<id>`. An adapter/flow OVERRIDES it (spt-claude-code sets `cc` →

+//! `cc-<id>`) — the Claude-Code-ness lives in the adapter, never in spt-core.

+//! The basename must be a DISTINCT token (not bare `spt`): a `spt.cmd` wrapper

+//! would shadow the real `spt.exe` only under cmd.exe (cwd-first search) and

+//! self-recurse, so a distinct `spt-<id>` is the safe, consistent form.


/// The generated-by marker. Present on line 1 of every script we write; its
/// presence (and ONLY its presence) authorizes an overwrite.
pub const SENTINEL: &str = "spt-generated cc-shortcut — safe to regenerate (do not remove this line)";

/// The generated-by marker. Rides a comment line near the top of every script
/// we write; its presence (and ONLY its presence) authorizes an overwrite.
pub const SENTINEL: &str =
    "spt-generated endpoint shortcut — safe to regenerate (do not remove this line)";

/// The harness-agnostic default shortcut basename. spt-core emits `spt-<id>`;
/// an adapter/flow overrides this (e.g. spt-claude-code → `cc`).
pub const DEFAULT_BASENAME: &str = "spt";


/// The generated-by marker. Present on line 1 of every script we write; its
/// presence (and ONLY its presence) authorizes an overwrite.
pub const SENTINEL: &str = "spt-generated cc-shortcut — safe to regenerate (do not remove this line)";

/// The generated-by marker. Rides a comment line near the top of every script
/// we write; its presence (and ONLY its presence) authorizes an overwrite.
pub const SENTINEL: &str =
    "spt-generated endpoint shortcut — safe to regenerate (do not remove this line)";

/// The harness-agnostic default shortcut basename. spt-core emits `spt-<id>`;
/// an adapter/flow overrides this (e.g. spt-claude-code → `cc`).
pub const DEFAULT_BASENAME: &str = "spt";

-/// The generated-by marker. Present on line 1 of every script we write; its

-/// presence (and ONLY its presence) authorizes an overwrite.

-pub const SENTINEL: &str = "spt-generated cc-shortcut — safe to regenerate (do not remove this line)";

+/// The generated-by marker. Rides a comment line near the top of every script

+/// we write; its presence (and ONLY its presence) authorizes an overwrite.

+    "spt-generated endpoint shortcut — safe to regenerate (do not remove this line)";

+/// The harness-agnostic default shortcut basename. spt-core emits `spt-<id>`;

+/// an adapter/flow overrides this (e.g. spt-claude-code → `cc`).

+pub const DEFAULT_BASENAME: &str = "spt";

/// What a write did (or refused to do).


/// The current-OS shortcut filename for an endpoint id: `cc-<id>.cmd` on
/// Windows (PATHEXT-resolvable), `cc-<id>` (no extension) on Unix.
pub fn shortcut_filename(id: &str) -> String {
    if cfg!(windows) {
        format!("cc-{id}.cmd")
    } else {
        format!("cc-{id}")
    }
}

/// Render the script body for the current OS. Pure (no I/O) so the content is
/// unit-assertable. The [`SENTINEL`] rides a comment line near the top (`REM`
/// in cmd, `#` in sh) — [`has_sentinel`] scans the first few lines for it.
// [impl->REQ-RUN-SHORTCUT]
pub fn render_script(id: &str, adapter: &str, resume: Option<&str>, mode: RunMode) -> String {
    let args = baked_args(id, adapter, resume, mode);
    if cfg!(windows) {
        // A Windows batch shortcut. `%*` forwards any extra runtime args. Invoke
        // bare `cc-<id>` from cmd.exe in the project dir, or `.\cc-<id>` from
        // PowerShell (both resolve the .cmd via PATHEXT).
        format!(
            "@echo off\r\n\
             REM {SENTINEL}\r\n\
             REM cc-{id}: launch the `{id}` endpoint with the baked selection.\r\n\
             REM   cmd.exe (project dir):  cc-{id}      PowerShell:  .\\cc-{id}\r\n\
             spt endpoint run {args} %*\r\n"
        )
    } else {
        // A POSIX sh shortcut. Invoke `./cc-{id}` (`.` is not on PATH); `\"$@\"`
        // forwards extra runtime args.
        format!(
            "#!/bin/sh\n\
             # {SENTINEL}\n\
             # cc-{id}: launch the `{id}` endpoint with the baked selection.\n\
             #   invoke from the project dir as:  ./cc-{id}\n\
             exec spt endpoint run {args} \"$@\"\n"
        )
    }
}

/// The current-OS shortcut filename for `<basename>-<id>`: `….cmd` on Windows
/// (PATHEXT-resolvable), no extension on Unix.
pub fn shortcut_filename(basename: &str, id: &str) -> String {
    if cfg!(windows) {
        format!("{basename}-{id}.cmd")
    } else {
        format!("{basename}-{id}")
    }
}

/// Render the script body for the current OS. Pure (no I/O) so the content is
/// unit-assertable. The [`SENTINEL`] rides a comment line near the top (`REM`
/// in cmd, `#` in sh) — [`has_sentinel`] scans the first few lines for it.
// [impl->REQ-RUN-SHORTCUT]
pub fn render_script(
    basename: &str,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> String {
    let args = baked_args(id, adapter, resume, mode);
    let name = format!("{basename}-{id}");
    if cfg!(windows) {
        // A Windows batch shortcut. `%*` forwards any extra runtime args. Invoke
        // bare `<basename>-<id>` from cmd.exe in the project dir, or
        // `.\<basename>-<id>` from PowerShell (both resolve the .cmd via PATHEXT).
        format!(
            "@echo off\r\n\
             REM {SENTINEL}\r\n\
             REM {name}: launch the `{id}` endpoint with the baked selection.\r\n\
             REM   cmd.exe (project dir):  {name}      PowerShell:  .\\{name}\r\n\
             spt endpoint run {args} %*\r\n"
        )
    } else {
        // A POSIX sh shortcut. Invoke `./<basename>-<id>` (`.` is not on PATH);
        // `\"$@\"` forwards extra runtime args.
        format!(
            "#!/bin/sh\n\
             # {SENTINEL}\n\
             # {name}: launch the `{id}` endpoint with the baked selection.\n\
             #   invoke from the project dir as:  ./{name}\n\
             exec spt endpoint run {args} \"$@\"\n"
        )
    }
}


/// The current-OS shortcut filename for an endpoint id: `cc-<id>.cmd` on
/// Windows (PATHEXT-resolvable), `cc-<id>` (no extension) on Unix.
pub fn shortcut_filename(id: &str) -> String {
    if cfg!(windows) {
        format!("cc-{id}.cmd")
    } else {
        format!("cc-{id}")
    }
}

/// Render the script body for the current OS. Pure (no I/O) so the content is
/// unit-assertable. The [`SENTINEL`] rides a comment line near the top (`REM`
/// in cmd, `#` in sh) — [`has_sentinel`] scans the first few lines for it.
// [impl->REQ-RUN-SHORTCUT]
pub fn render_script(id: &str, adapter: &str, resume: Option<&str>, mode: RunMode) -> String {
    let args = baked_args(id, adapter, resume, mode);
    if cfg!(windows) {
        // A Windows batch shortcut. `%*` forwards any extra runtime args. Invoke
        // bare `cc-<id>` from cmd.exe in the project dir, or `.\cc-<id>` from
        // PowerShell (both resolve the .cmd via PATHEXT).
        format!(
            "@echo off\r\n\
             REM {SENTINEL}\r\n\
             REM cc-{id}: launch the `{id}` endpoint with the baked selection.\r\n\
             REM   cmd.exe (project dir):  cc-{id}      PowerShell:  .\\cc-{id}\r\n\
             spt endpoint run {args} %*\r\n"
        )
    } else {
        // A POSIX sh shortcut. Invoke `./cc-{id}` (`.` is not on PATH); `\"$@\"`
        // forwards extra runtime args.
        format!(
            "#!/bin/sh\n\
             # {SENTINEL}\n\
             # cc-{id}: launch the `{id}` endpoint with the baked selection.\n\
             #   invoke from the project dir as:  ./cc-{id}\n\
             exec spt endpoint run {args} \"$@\"\n"
        )
    }
}

/// The current-OS shortcut filename for `<basename>-<id>`: `….cmd` on Windows
/// (PATHEXT-resolvable), no extension on Unix.
pub fn shortcut_filename(basename: &str, id: &str) -> String {
    if cfg!(windows) {
        format!("{basename}-{id}.cmd")
    } else {
        format!("{basename}-{id}")
    }
}

/// Render the script body for the current OS. Pure (no I/O) so the content is
/// unit-assertable. The [`SENTINEL`] rides a comment line near the top (`REM`
/// in cmd, `#` in sh) — [`has_sentinel`] scans the first few lines for it.
// [impl->REQ-RUN-SHORTCUT]
pub fn render_script(
    basename: &str,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> String {
    let args = baked_args(id, adapter, resume, mode);
    let name = format!("{basename}-{id}");
    if cfg!(windows) {
        // A Windows batch shortcut. `%*` forwards any extra runtime args. Invoke
        // bare `<basename>-<id>` from cmd.exe in the project dir, or
        // `.\<basename>-<id>` from PowerShell (both resolve the .cmd via PATHEXT).
        format!(
            "@echo off\r\n\
             REM {SENTINEL}\r\n\
             REM {name}: launch the `{id}` endpoint with the baked selection.\r\n\
             REM   cmd.exe (project dir):  {name}      PowerShell:  .\\{name}\r\n\
             spt endpoint run {args} %*\r\n"
        )
    } else {
        // A POSIX sh shortcut. Invoke `./<basename>-<id>` (`.` is not on PATH);
        // `\"$@\"` forwards extra runtime args.
        format!(
            "#!/bin/sh\n\
             # {SENTINEL}\n\
             # {name}: launch the `{id}` endpoint with the baked selection.\n\
             #   invoke from the project dir as:  ./{name}\n\
             exec spt endpoint run {args} \"$@\"\n"
        )
    }
}

-/// The current-OS shortcut filename for an endpoint id: `cc-<id>.cmd` on

-/// Windows (PATHEXT-resolvable), `cc-<id>` (no extension) on Unix.

-pub fn shortcut_filename(id: &str) -> String {

+/// The current-OS shortcut filename for `<basename>-<id>`: `….cmd` on Windows

+/// (PATHEXT-resolvable), no extension on Unix.

+pub fn shortcut_filename(basename: &str, id: &str) -> String {

-pub fn render_script(id: &str, adapter: &str, resume: Option<&str>, mode: RunMode) -> String {

+    let name = format!("{basename}-{id}");

-        // bare `cc-<id>` from cmd.exe in the project dir, or `.\cc-<id>` from

-        // PowerShell (both resolve the .cmd via PATHEXT).

+        // bare `<basename>-<id>` from cmd.exe in the project dir, or

+        // `.\<basename>-<id>` from PowerShell (both resolve the .cmd via PATHEXT).

-             REM cc-{id}: launch the `{id}` endpoint with the baked selection.\r\n\

-             REM   cmd.exe (project dir):  cc-{id}      PowerShell:  .\\cc-{id}\r\n\

+             REM {name}: launch the `{id}` endpoint with the baked selection.\r\n\

+             REM   cmd.exe (project dir):  {name}      PowerShell:  .\\{name}\r\n\

-        // A POSIX sh shortcut. Invoke `./cc-{id}` (`.` is not on PATH); `\"$@\"`

-        // forwards extra runtime args.

+        // A POSIX sh shortcut. Invoke `./<basename>-<id>` (`.` is not on PATH);

+        // `\"$@\"` forwards extra runtime args.

-             # cc-{id}: launch the `{id}` endpoint with the baked selection.\n\

-             #   invoke from the project dir as:  ./cc-{id}\n\

+             # {name}: launch the `{id}` endpoint with the baked selection.\n\

+             #   invoke from the project dir as:  ./{name}\n\


Update M12-W2-PLAN.md with crystallized post-ruling design

Append a "Crystallized design (post-ruling)" section reflecting doyle's M12-W2-RULING.md: Q1 defer, Q2 best-effort, Q3 BUILD resume via sessions::last_k, Q4 sentinel-guarded per-OS shortcut, Q5 additive --create, 2 REQs doc+impl+unit no-int, single-bringup-path invariant.

Add REQ-RUN-PICKER + REQ-RUN-SHORTCUT to traceable-reqs.toml

Add both REQ-* entries (rule 3, before building). Stages doc+impl+unit, NO int (TUI manual-verify leg note per REQ-PAIR-6).

Add ratatui + nucleo-matcher deps; make Run{} adapter/id optional + add --create

spt/Cargo.toml: ratatui 0.29 (pairs crossterm 0.28) + nucleo-matcher. cli.rs Run{}: adapter/id → Option<String>, add --create flag; dispatch bare (no adapter/id) → picker, flags-present → cmd_endpoint_run untouched.

Build picker state model (pure, testable)

spt/src/picker/model.rs: screens (Kind/CreateNew/PickExisting/Confirm), nav transitions, action enum (single source of truth), status→square, adapter→profile tree, ledger→resume titles, filter narrowing, cursor windowing. Heavy unit tests.

Build picker data gather over existing surfaces

spt/src/picker/data.rs: harness adapters+profiles (registered/local_profile_names), endpoints by category project/local/subnet (roster + wansend snapshots + resource_projection), description (adapter:profile, project history best-effort contextstore, endpoint description), sessions::last_k resume rows. No new daemon surface.

Build picker ratatui view (Buffer-testable)

spt/src/picker/view.rs: render fns &Model→Buffer; kind screen, create-new adapter/profile tree + id entry, pick-existing category L/R + grouped list + status squares + two-pane description, confirm layer + options, pinned legend. Glyph set lifted. Buffer asserts via ratatui TestBackend.

Build cc-<id> shortcut generation (REQ-RUN-SHORTCUT)

spt/src/picker/shortcut.rs: per-OS native (.ps1 Win / sh+chmod Unix), bake terminal-action flags (adapter[:profile]+id+create|resume+start|attach|view), sentinel-guarded overwrite (generated-by header marker; overwrite own freely, refuse+warn if no sentinel). Unit-tested content + create-vs-update.

Wire picker live loop + terminal-action dispatch (single bringup path)

spt/src/picker/mod.rs: crossterm raw + ratatui Terminal live loop (manual-verify leg); every terminal action routes through cmd_endpoint_run / cmd_fork / rc pump — NO second bringup path (the gate invariant).

Tag evidence, full suite + clippy -D + traceable check, ping doyle to gate

Tag [impl->]/[unit->] in same change; run full test suite, clippy -D warnings, traceable-reqs check EXIT=0. Then ping doyle to gate (reproduce traceable + read load-bearing tests + confirm single-bringup-path).


Now `write_shortcut` takes basename, plus its tests:


pub fn write_shortcut(
    dir: &Path,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> std::io::Result<WriteOutcome> {
    let path = dir.join(shortcut_filename(id));
    let exists = path.exists();
    if exists {
        let current = std::fs::read_to_string(&path).unwrap_or_default();
        if !has_sentinel(&current) {
            return Ok(WriteOutcome::RefusedForeign(path));
        }
    }
    let body = render_script(id, adapter, resume, mode);

pub fn write_shortcut(
    dir: &Path,
    basename: &str,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> std::io::Result<WriteOutcome> {
    let path = dir.join(shortcut_filename(basename, id));
    let exists = path.exists();
    if exists {
        let current = std::fs::read_to_string(&path).unwrap_or_default();
        if !has_sentinel(&current) {
            return Ok(WriteOutcome::RefusedForeign(path));
        }
    }
    let body = render_script(basename, id, adapter, resume, mode);


pub fn write_shortcut(
    dir: &Path,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> std::io::Result<WriteOutcome> {
    let path = dir.join(shortcut_filename(id));
    let exists = path.exists();
    if exists {
        let current = std::fs::read_to_string(&path).unwrap_or_default();
        if !has_sentinel(&current) {
            return Ok(WriteOutcome::RefusedForeign(path));
        }
    }
    let body = render_script(id, adapter, resume, mode);

pub fn write_shortcut(
    dir: &Path,
    basename: &str,
    id: &str,
    adapter: &str,
    resume: Option<&str>,
    mode: RunMode,
) -> std::io::Result<WriteOutcome> {
    let path = dir.join(shortcut_filename(basename, id));
    let exists = path.exists();
    if exists {
        let current = std::fs::read_to_string(&path).unwrap_or_default();
        if !has_sentinel(&current) {
            return Ok(WriteOutcome::RefusedForeign(path));
        }
    }
    let body = render_script(basename, id, adapter, resume, mode);

-    let path = dir.join(shortcut_filename(id));

+    let path = dir.join(shortcut_filename(basename, id));

-    let body = render_script(id, adapter, resume, mode);

+    let body = render_script(basename, id, adapter, resume, mode);


    #[test]
    fn bakes_create_attach_by_default() {
        let body = render_script("doyle", "claude-spt:fast", None, RunMode::Attach);
        assert!(body.contains("--adapter claude-spt:fast"));
        assert!(body.contains("--id doyle"));
        assert!(body.contains("--create"));
        assert!(!body.contains("--resume"));
        assert!(!body.contains("--start") && !body.contains("--view"));
        assert!(has_sentinel(&body), "sentinel rides a comment line near the top");
    }

    #[test]
    fn bakes_create_attach_by_default() {
        let body = render_script(DEFAULT_BASENAME, "doyle", "claude-spt:fast", None, RunMode::Attach);
        assert!(body.contains("--adapter claude-spt:fast"));
        assert!(body.contains("--id doyle"));
        assert!(body.contains("--create"));
        assert!(!body.contains("--resume"));
        assert!(!body.contains("--start") && !body.contains("--view"));
        assert!(has_sentinel(&body), "sentinel rides a comment line near the top");
        // harness-agnostic spt-core emits `spt-<id>`, NEVER `cc-<id>`.
        assert!(body.contains("spt-doyle"));
        assert!(!body.contains("cc-doyle"));
    }

    // [unit->REQ-RUN-SHORTCUT] the basename is a parameter — an adapter/flow can
    // override `spt` (spt-claude-code → `cc`); the filename + body track it.
    #[test]
    fn basename_is_parameterized() {
        assert_eq!(
            shortcut_filename(DEFAULT_BASENAME, "doyle"),
            if cfg!(windows) { "spt-doyle.cmd" } else { "spt-doyle" }
        );
        assert_eq!(
            shortcut_filename("cc", "doyle"),
            if cfg!(windows) { "cc-doyle.cmd" } else { "cc-doyle" }
        );
        let body = render_script("cc", "doyle", "claude-spt", None, RunMode::Attach);
        assert!(body.contains("cc-doyle"), "adapter override emits cc-<id>");
    }


    #[test]
    fn bakes_create_attach_by_default() {
        let body = render_script("doyle", "claude-spt:fast", None, RunMode::Attach);
        assert!(body.contains("--adapter claude-spt:fast"));
        assert!(body.contains("--id doyle"));
        assert!(body.contains("--create"));
        assert!(!body.contains("--resume"));
        assert!(!body.contains("--start") && !body.contains("--view"));
        assert!(has_sentinel(&body), "sentinel rides a comment line near the top");
    }

    #[test]
    fn bakes_create_attach_by_default() {
        let body = render_script(DEFAULT_BASENAME, "doyle", "claude-spt:fast", None, RunMode::Attach);
        assert!(body.contains("--adapter claude-spt:fast"));
        assert!(body.contains("--id doyle"));
        assert!(body.contains("--create"));
        assert!(!body.contains("--resume"));
        assert!(!body.contains("--start") && !body.contains("--view"));
        assert!(has_sentinel(&body), "sentinel rides a comment line near the top");
        // harness-agnostic spt-core emits `spt-<id>`, NEVER `cc-<id>`.
        assert!(body.contains("spt-doyle"));
        assert!(!body.contains("cc-doyle"));
    }

    // [unit->REQ-RUN-SHORTCUT] the basename is a parameter — an adapter/flow can
    // override `spt` (spt-claude-code → `cc`); the filename + body track it.
    #[test]
    fn basename_is_parameterized() {
        assert_eq!(
            shortcut_filename(DEFAULT_BASENAME, "doyle"),
            if cfg!(windows) { "spt-doyle.cmd" } else { "spt-doyle" }
        );
        assert_eq!(
            shortcut_filename("cc", "doyle"),
            if cfg!(windows) { "cc-doyle.cmd" } else { "cc-doyle" }
        );
        let body = render_script("cc", "doyle", "claude-spt", None, RunMode::Attach);
        assert!(body.contains("cc-doyle"), "adapter override emits cc-<id>");
    }

// fresh run defaults to --create + attach (no action flag).

-        let body = render_script("doyle", "claude-spt:fast", None, RunMode::Attach);

+        let body = render_script(DEFAULT_BASENAME, "doyle", "claude-spt:fast", None, RunMode::Attach);

+        // harness-agnostic spt-core emits `spt-<id>`, NEVER `cc-<id>`.

+        assert!(body.contains("spt-doyle"));

+        assert!(!body.contains("cc-doyle"));

+    // [unit->REQ-RUN-SHORTCUT] the basename is a parameter — an adapter/flow can

+    // override `spt` (spt-claude-code → `cc`); the filename + body track it.

+            shortcut_filename(DEFAULT_BASENAME, "doyle"),

+            if cfg!(windows) { "spt-doyle.cmd" } else { "spt-doyle" }

+            shortcut_filename("cc", "doyle"),

+            if cfg!(windows) { "cc-doyle.cmd" } else { "cc-doyle" }

+        let body = render_script("cc", "doyle", "claude-spt", None, RunMode::Attach);

+        assert!(body.contains("cc-doyle"), "adapter override emits cc-<id>");

// [unit->REQ-RUN-SHORTCUT] resume bakes --resume (not --create); view/start


    #[test]
    fn bakes_resume_and_action() {
        let body = render_script("d", "ccs", Some("sess123"), RunMode::View);
        assert!(body.contains("--resume sess123"));
        assert!(!body.contains("--create"));
        assert!(body.contains("--view"));

        let start = render_script("d", "ccs", None, RunMode::Start);
        assert!(start.contains("--create") && start.contains("--start"));
    }

    // [unit->REQ-RUN-SHORTCUT] sentinel detection only trusts our own header.
    #[test]
    fn sentinel_detection() {
        assert!(has_sentinel(&render_script("x", "a", None, RunMode::Attach)));
        assert!(!has_sentinel("#!/bin/sh\necho hi\n"), "a user script has no sentinel");
    }

    #[test]
    fn bakes_resume_and_action() {
        let body = render_script(DEFAULT_BASENAME, "d", "ccs", Some("sess123"), RunMode::View);
        assert!(body.contains("--resume sess123"));
        assert!(!body.contains("--create"));
        assert!(body.contains("--view"));

        let start = render_script(DEFAULT_BASENAME, "d", "ccs", None, RunMode::Start);
        assert!(start.contains("--create") && start.contains("--start"));
    }

    // [unit->REQ-RUN-SHORTCUT] sentinel detection only trusts our own header.
    #[test]
    fn sentinel_detection() {
        assert!(has_sentinel(&render_script(DEFAULT_BASENAME, "x", "a", None, RunMode::Attach)));
        assert!(!has_sentinel("#!/bin/sh\necho hi\n"), "a user script has no sentinel");
    }


    #[test]
    fn bakes_resume_and_action() {
        let body = render_script("d", "ccs", Some("sess123"), RunMode::View);
        assert!(body.contains("--resume sess123"));
        assert!(!body.contains("--create"));
        assert!(body.contains("--view"));

        let start = render_script("d", "ccs", None, RunMode::Start);
        assert!(start.contains("--create") && start.contains("--start"));
    }

    // [unit->REQ-RUN-SHORTCUT] sentinel detection only trusts our own header.
    #[test]
    fn sentinel_detection() {
        assert!(has_sentinel(&render_script("x", "a", None, RunMode::Attach)));
        assert!(!has_sentinel("#!/bin/sh\necho hi\n"), "a user script has no sentinel");
    }

    #[test]
    fn bakes_resume_and_action() {
        let body = render_script(DEFAULT_BASENAME, "d", "ccs", Some("sess123"), RunMode::View);
        assert!(body.contains("--resume sess123"));
        assert!(!body.contains("--create"));
        assert!(body.contains("--view"));

        let start = render_script(DEFAULT_BASENAME, "d", "ccs", None, RunMode::Start);
        assert!(start.contains("--create") && start.contains("--start"));
    }

    // [unit->REQ-RUN-SHORTCUT] sentinel detection only trusts our own header.
    #[test]
    fn sentinel_detection() {
        assert!(has_sentinel(&render_script(DEFAULT_BASENAME, "x", "a", None, RunMode::Attach)));
        assert!(!has_sentinel("#!/bin/sh\necho hi\n"), "a user script has no sentinel");
    }

-        let body = render_script("d", "ccs", Some("sess123"), RunMode::View);

+        let body = render_script(DEFAULT_BASENAME, "d", "ccs", Some("sess123"), RunMode::View);

-        let start = render_script("d", "ccs", None, RunMode::Start);

+        let start = render_script(DEFAULT_BASENAME, "d", "ccs", None, RunMode::Start);

-        assert!(has_sentinel(&render_script("x", "a", None, RunMode::Attach)));

+        assert!(has_sentinel(&render_script(DEFAULT_BASENAME, "x", "a", None, RunMode::Attach)));


        // 1. fresh → Created.
        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();
        let path = match out {
            WriteOutcome::Created(path) => path,
            other => panic!("expected Created, got {other:?}"),
        };
        assert!(path.exists());

        // 2. re-generate over our own → Updated (different selection rewrites).
        let out = write_shortcut(p, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();
        assert!(matches!(out, WriteOutcome::Updated(_)));
        let body = std::fs::read_to_string(&path).unwrap();
        assert!(body.contains("--adapter ccs") && body.contains("--resume s9"));

        // 3. a foreign same-named file → RefusedForeign, untouched.
        std::fs::write(&path, "#!/bin/sh\necho mine\n").unwrap();
        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();

        // 1. fresh → Created.
        let out =
            write_shortcut(p, DEFAULT_BASENAME, "doyle", "claude-spt", None, RunMode::Attach)
                .unwrap();
        let path = match out {
            WriteOutcome::Created(path) => path,
            other => panic!("expected Created, got {other:?}"),
        };
        assert!(path.exists());

        // 2. re-generate over our own → Updated (different selection rewrites).
        let out =
            write_shortcut(p, DEFAULT_BASENAME, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();
        assert!(matches!(out, WriteOutcome::Updated(_)));
        let body = std::fs::read_to_string(&path).unwrap();
        assert!(body.contains("--adapter ccs") && body.contains("--resume s9"));

        // 3. a foreign same-named file → RefusedForeign, untouched.
        std::fs::write(&path, "#!/bin/sh\necho mine\n").unwrap();
        let out =
            write_shortcut(p, DEFAULT_BASENAME, "doyle", "claude-spt", None, RunMode::Attach)
                .unwrap();


        // 1. fresh → Created.
        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();
        let path = match out {
            WriteOutcome::Created(path) => path,
            other => panic!("expected Created, got {other:?}"),
        };
        assert!(path.exists());

        // 2. re-generate over our own → Updated (different selection rewrites).
        let out = write_shortcut(p, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();
        assert!(matches!(out, WriteOutcome::Updated(_)));
        let body = std::fs::read_to_string(&path).unwrap();
        assert!(body.contains("--adapter ccs") && body.contains("--resume s9"));

        // 3. a foreign same-named file → RefusedForeign, untouched.
        std::fs::write(&path, "#!/bin/sh\necho mine\n").unwrap();
        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();

        // 1. fresh → Created.
        let out =
            write_shortcut(p, DEFAULT_BASENAME, "doyle", "claude-spt", None, RunMode::Attach)
                .unwrap();
        let path = match out {
            WriteOutcome::Created(path) => path,
            other => panic!("expected Created, got {other:?}"),
        };
        assert!(path.exists());

        // 2. re-generate over our own → Updated (different selection rewrites).
        let out =
            write_shortcut(p, DEFAULT_BASENAME, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();
        assert!(matches!(out, WriteOutcome::Updated(_)));
        let body = std::fs::read_to_string(&path).unwrap();
        assert!(body.contains("--adapter ccs") && body.contains("--resume s9"));

        // 3. a foreign same-named file → RefusedForeign, untouched.
        std::fs::write(&path, "#!/bin/sh\necho mine\n").unwrap();
        let out =
            write_shortcut(p, DEFAULT_BASENAME, "doyle", "claude-spt", None, RunMode::Attach)
                .unwrap();

-        let out = write_shortcut(p, "doyle", "claude-spt", None, RunMode::Attach).unwrap();

+            write_shortcut(p, DEFAULT_BASENAME, "doyle", "claude-spt", None, RunMode::Attach)

-        let out = write_shortcut(p, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();

+            write_shortcut(p, DEFAULT_BASENAME, "doyle", "ccs", Some("s9"), RunMode::Start).unwrap();


Now update the caller in mod.rs and the confirm-option label in view.rs:


/// Write the `cc-<id>` shortcut at the project cwd, returning a one-line status
/// for the flash. (The file write is the only side effect; the TUI stays up.)
fn write_shortcut_now(adapter: &str, id: &str, resume: Option<&str>, mode: RunMode) -> String {
    let dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
    match shortcut::write_shortcut(&dir, id, adapter, resume, mode) {

/// Write the `spt-<id>` shortcut at the project cwd, returning a one-line status
/// for the flash. (The file write is the only side effect; the TUI stays up.)
/// spt-core uses the harness-agnostic default basename (`spt`); an adapter/flow
/// override (e.g. `cc`) is a downstream concern.
fn write_shortcut_now(adapter: &str, id: &str, resume: Option<&str>, mode: RunMode) -> String {
    let dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
    match shortcut::write_shortcut(&dir, shortcut::DEFAULT_BASENAME, id, adapter, resume, mode) {


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

/// Write the `cc-<id>` shortcut at the project cwd, returning a one-line status
/// for the flash. (The file write is the only side effect; the TUI stays up.)
fn write_shortcut_now(adapter: &str, id: &str, resume: Option<&str>, mode: RunMode) -> String {
    let dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
    match shortcut::write_shortcut(&dir, id, adapter, resume, mode) {

/// Write the `spt-<id>` shortcut at the project cwd, returning a one-line status
/// for the flash. (The file write is the only side effect; the TUI stays up.)
/// spt-core uses the harness-agnostic default basename (`spt`); an adapter/flow
/// override (e.g. `cc`) is a downstream concern.
fn write_shortcut_now(adapter: &str, id: &str, resume: Option<&str>, mode: RunMode) -> String {
    let dir = std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from("."));
    match shortcut::write_shortcut(&dir, shortcut::DEFAULT_BASENAME, id, adapter, resume, mode) {

-/// Write the `cc-<id>` shortcut at the project cwd, returning a one-line status

+/// Write the `spt-<id>` shortcut at the project cwd, returning a one-line status

+/// spt-core uses the harness-agnostic default basename (`spt`); an adapter/flow

+/// override (e.g. `cc`) is a downstream concern.

-    match shortcut::write_shortcut(&dir, id, adapter, resume, mode) {

+    match shortcut::write_shortcut(&dir, shortcut::DEFAULT_BASENAME, id, adapter, resume, mode) {

Ok(WriteOutcome::Created(p)) => format!("✓ shortcut written: {}", p.display()),

Ok(WriteOutcome::Updated(p)) => format!("✓ shortcut updated: {}", p.display()),


ConfirmOption::Shortcut => "New/Update cc-<id> shortcut (s)",

ConfirmOption::Shortcut => "New/Update spt-<id> shortcut (s)",


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

ConfirmOption::ChangeAdapter => "Change harness adapter",

ConfirmOption::Instantiate => "Instantiate locally",

-        ConfirmOption::Shortcut => "New/Update cc-<id> shortcut (s)",

+        ConfirmOption::Shortcut => "New/Update spt-<id> shortcut (s)",


Update remaining `cc-<id>` references in picker source + docs:


crates\spt\src\picker\mod.rs:13://! to a testable ratatui `Buffer`), `shortcut` (`cc-<id>` generation). This file
crates\spt\src\picker\mod.rs:195:        // The `s` keybind = build/update the cc-<id> shortcut from every
crates\spt\src\picker\mod.rs:230:/// override (e.g. `cc`) is a downstream concern.
crates\spt\src\picker\shortcut.rs:9://! **Basename is a PARAMETER, never `cc`** (doyle/operator 2026-06-14):
crates\spt\src\picker\shortcut.rs:11://! `spt-<id>`. An adapter/flow OVERRIDES it (spt-claude-code sets `cc` →
crates\spt\src\picker\shortcut.rs:12://! `cc-<id>`) — the Claude-Code-ness lives in the adapter, never in spt-core.
crates\spt\src\picker\shortcut.rs:25://! - Windows + cmd.exe, in the project dir: bare `cc-<id>` works (cwd +
crates\spt\src\picker\shortcut.rs:27://! - Windows + PowerShell: needs `.\cc-<id>` (PowerShell refuses cwd exec but
crates\spt\src\picker\shortcut.rs:29://! - Unix: `./cc-<id>` (`.` is not on `PATH`).
crates\spt\src\picker\shortcut.rs:30://! - A truly-bare `cc` everywhere = a PATH-installed launcher = `/spt:setup`'s
crates\spt\src\picker\shortcut.rs:51:/// an adapter/flow overrides this (e.g. spt-claude-code → `cc`).
crates\spt\src\picker\shortcut.rs:217:        // harness-agnostic spt-core emits `spt-<id>`, NEVER `cc-<id>`.
crates\spt\src\picker\shortcut.rs:219:        assert!(!body.contains("cc-doyle"));
crates\spt\src\picker\shortcut.rs:223:    // override `spt` (spt-claude-code → `cc`); the filename + body track it.
crates\spt\src\picker\shortcut.rs:232:            if cfg!(windows) { "cc-doyle.cmd" } else { "cc-doyle" }
crates\spt\src\picker\shortcut.rs:235:        assert!(body.contains("cc-doyle"), "adapter override emits cc-<id>");
crates\spt\src\picker\model.rs:221:    /// The `s` keybind — build/update the `cc-<id>` shortcut.
crates\spt\src\picker\model.rs:242:    /// Write/update a `cc-<id>` shortcut, then stay (re-enter the loop).


//! **Invocation reality** (baked into the generated header so the user isn't
//! surprised):
//! - Windows + cmd.exe, in the project dir: bare `cc-<id>` works (cwd +
//!   `PATHEXT` search).
//! - Windows + PowerShell: needs `.\cc-<id>` (PowerShell refuses cwd exec but
//!   honors `PATHEXT` → finds the `.cmd`).
//! - Unix: `./cc-<id>` (`.` is not on `PATH`).
//! - A truly-bare `cc` everywhere = a PATH-installed launcher = `/spt:setup`'s
//!   job, not this project-root shortcut.

//! **Invocation reality** (baked into the generated header so the user isn't
//! surprised; `<name>` = `<basename>-<id>`, e.g. `spt-doyle`):
//! - Windows + cmd.exe, in the project dir: bare `<name>` works (cwd +
//!   `PATHEXT` search).
//! - Windows + PowerShell: needs `.\<name>` (PowerShell refuses cwd exec but
//!   honors `PATHEXT` → finds the `.cmd`).
//! - Unix: `./<name>` (`.` is not on `PATH`).
//! - A truly-bare basename on `PATH` = a PATH-installed launcher = `/spt:setup`'s
//!   job, not this project-root shortcut.


//! **Invocation reality** (baked into the generated header so the user isn't
//! surprised):
//! - Windows + cmd.exe, in the project dir: bare `cc-<id>` works (cwd +
//!   `PATHEXT` search).
//! - Windows + PowerShell: needs `.\cc-<id>` (PowerShell refuses cwd exec but
//!   honors `PATHEXT` → finds the `.cmd`).
//! - Unix: `./cc-<id>` (`.` is not on `PATH`).
//! - A truly-bare `cc` everywhere = a PATH-installed launcher = `/spt:setup`'s
//!   job, not this project-root shortcut.

//! **Invocation reality** (baked into the generated header so the user isn't
//! surprised; `<name>` = `<basename>-<id>`, e.g. `spt-doyle`):
//! - Windows + cmd.exe, in the project dir: bare `<name>` works (cwd +
//!   `PATHEXT` search).
//! - Windows + PowerShell: needs `.\<name>` (PowerShell refuses cwd exec but
//!   honors `PATHEXT` → finds the `.cmd`).
//! - Unix: `./<name>` (`.` is not on `PATH`).
//! - A truly-bare basename on `PATH` = a PATH-installed launcher = `/spt:setup`'s
//!   job, not this project-root shortcut.

//!   single portable form can't be both.

-//! - Windows + cmd.exe, in the project dir: bare `cc-<id>` works (cwd +

+//! surprised; `<name>` = `<basename>-<id>`, e.g. `spt-doyle`):

+//! - Windows + cmd.exe, in the project dir: bare `<name>` works (cwd +

-//! - Windows + PowerShell: needs `.\cc-<id>` (PowerShell refuses cwd exec but

+//! - Windows + PowerShell: needs `.\<name>` (PowerShell refuses cwd exec but

-//! - A truly-bare `cc` everywhere = a PATH-installed launcher = `/spt:setup`'s

+//! - A truly-bare basename on `PATH` = a PATH-installed launcher = `/spt:setup`'s

//! - **Sentinel-guarded overwrite:** the generator writes + checks a generated-by

//!   header [`SENTINEL`]. It overwrites its OWN prior output freely ("Update"),


//! to a testable ratatui `Buffer`), `shortcut` (`cc-<id>` generation). This file

//! to a testable ratatui `Buffer`), `shortcut` (`spt-<id>` generation). This file


//! Layering: `model` (pure state + transitions, fully unit-tested), `data`

//! (read-only gather over existing surfaces), `view` (renders a `&PickerModel`

-//! to a testable ratatui `Buffer`), `shortcut` (`cc-<id>` generation). This file

+//! to a testable ratatui `Buffer`), `shortcut` (`spt-<id>` generation). This file

//! is the thin live key loop — the manual-verify leg (like REQ-PAIR-6's OS

//! probe); the model/view/shortcut logic under it is unit-asserted.


// The `s` keybind = build/update the cc-<id> shortcut from every

// The `s` keybind = build/update the spt-<id> shortcut from every


-        // The `s` keybind = build/update the cc-<id> shortcut from every

+        // The `s` keybind = build/update the spt-<id> shortcut from every

KeyCode::Char('s') => return model.confirm_terminal(ConfirmOption::Shortcut),


/// The `s` keybind — build/update the `cc-<id>` shortcut.

/// The `s` keybind — build/update the `spt-<id>` shortcut.


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

/// Always available — cross-subnet clone to a new id.

-    /// The `s` keybind — build/update the `cc-<id>` shortcut.

+    /// The `s` keybind — build/update the `spt-<id>` shortcut.


/// Write/update a `cc-<id>` shortcut, then stay (re-enter the loop).

/// Write/update a `spt-<id>` shortcut, then stay (re-enter the loop).


/// Attach to an ALREADY-LIVE endpoint's PTY — routes through the rc pump

/// (`rc::run_attach`), not a re-bringup.

-    /// Write/update a `cc-<id>` shortcut, then stay (re-enter the loop).

+    /// Write/update a `spt-<id>` shortcut, then stay (re-enter the loop).


Now docs. Find remaining `cc-<id>` in changed non-source files:


Found 11 files
crates\spt\src\picker\mod.rs
crates\spt\src\picker\shortcut.rs
M12-W2-RULING.md
CONTEXT.md
traceable-reqs.toml
M12-W2-PLAN.md
crates\spt\src\cli.rs
M12-W1-PLAN.md
M12-PLAN.md
M12-ENDPOINT-RUN-PICKER.md
M12-CANDIDATES.md


CONTEXT.md, toml, plan, cli.rs need updates (others are prior-planning/doyle history). Check cli.rs ref:


242:    /// action so a `cc-<id>` shortcut can bake a fully non-interactive launch.


/// action so a `cc-<id>` shortcut can bake a fully non-interactive launch.

/// action so a `spt-<id>` shortcut can bake a fully non-interactive launch.


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

/// views per the terminal-action flag. The endpoint id rides argv so the

/// harness binds to exactly it. This is the non-interactive core (the

/// interactive picker lands in a later wave); the flags cover every terminal

-    /// action so a `cc-<id>` shortcut can bake a fully non-interactive launch.

+    /// action so a `spt-<id>` shortcut can bake a fully non-interactive launch.

/// The harness adapter to host: `<adapter>[:profile]` (must be a

/// registered `kind="harness"` adapter on this node). Omit (with --id)


Now CONTEXT.md doc section + toml REQ title + plan Q4. CONTEXT.md:


**`cc-<id>` shortcut** (picker `s` keybind, M12-W2):
<!-- [doc->REQ-RUN-SHORTCUT] -->
From any pre-start options set, `s` writes (or updates) a **`cc-<id>` launcher** at the project
root that bakes the current selection's **non-interactive** flags (terminal actions only:
adapter[:profile] + id + create|resume + start|attach|view; the interactive-only branches —
Kick/Instantiate/Change-adapter/Fork — are not bakeable). The launcher is the **current OS's
native form**: a **`.cmd`** on Windows (the default `PATHEXT` excludes `.ps1`, so a bare name
never resolves one; `.cmd` is PATHEXT-resolvable), a POSIX **`sh`** (`chmod +x`) on Unix.
**Invocation reality** (documented in the generated header): cmd.exe bare `cc-<id>` in the
project dir · PowerShell `.\cc-<id>` · Unix `./cc-<id>`; a *truly-bare* `cc` on `PATH` is a
PATH-installed launcher (`/spt:setup`'s job), not this project-root shortcut. **Overwrite is
sentinel-guarded:** the generator writes + checks a generated-by header marker — it overwrites
its own prior output freely, but refuses (with a warning) a same-named file that lacks the
sentinel, never clobbering a user file.
_Avoid_: `.ps1` shortcuts (PATHEXT won't find them); clobbering a non-generated file.

**`spt-<id>` shortcut** (picker `s` keybind, M12-W2):
<!-- [doc->REQ-RUN-SHORTCUT] -->
From any pre-start options set, `s` writes (or updates) a **`<basename>-<id>` launcher** at the
project root that bakes the current selection's **non-interactive** flags (terminal actions
only: adapter[:profile] + id + create|resume + start|attach|view; the interactive-only branches
— Kick/Instantiate/Change-adapter/Fork — are not bakeable). The **basename is a parameter**:
harness-agnostic spt-core defaults to **`spt`** (→ `spt-<id>`, e.g. `spt-doyle`); an
adapter/flow **overrides** it (spt-claude-code → `cc`, giving `cc-<id>`) — the Claude-Code-ness
lives in the adapter, **spt-core never emits `cc`**. The basename must be a *distinct* token,
never bare `spt`: a `spt.cmd` wrapper would shadow the real `spt.exe` only under cmd.exe
(cwd-first search), silently no-op in PowerShell/Unix, and self-recurse — so `spt-<id>` is the
safe, consistent form. The launcher is the **current OS's native form**: a **`.cmd`** on
Windows (the default `PATHEXT` excludes `.ps1`, so a bare name never resolves one; `.cmd` is
PATHEXT-resolvable), a POSIX **`sh`** (`chmod +x`) on Unix. **Invocation reality** (documented
in the generated header; `<name>` = `<basename>-<id>`): cmd.exe bare `<name>` in the project dir
· PowerShell `.\<name>` · Unix `./<name>`; a *truly-bare* basename on `PATH` is a PATH-installed
launcher (`/spt:setup`'s job), not this project-root shortcut. **Overwrite is sentinel-guarded:**
the generator writes + checks a generated-by header marker — it overwrites its own prior output
freely, but refuses (with a warning) a same-named file that lacks the sentinel, never clobbering
a user file.
_Avoid_: baking `cc` (a harness name) into spt-core; a bare `spt`/`cc` shadow wrapper; `.ps1`
shortcuts (PATHEXT won't find them); clobbering a non-generated file.


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

**`cc-<id>` shortcut** (picker `s` keybind, M12-W2):
<!-- [doc->REQ-RUN-SHORTCUT] -->
From any pre-start options set, `s` writes (or updates) a **`cc-<id>` launcher** at the project
root that bakes the current selection's **non-interactive** flags (terminal actions only:
adapter[:profile] + id + create|resume + start|attach|view; the interactive-only branches —
Kick/Instantiate/Change-adapter/Fork — are not bakeable). The launcher is the **current OS's
native form**: a **`.cmd`** on Windows (the default `PATHEXT` excludes `.ps1`, so a bare name
never resolves one; `.cmd` is PATHEXT-resolvable), a POSIX **`sh`** (`chmod +x`) on Unix.
**Invocation reality** (documented in the generated header): cmd.exe bare `cc-<id>` in the
project dir · PowerShell `.\cc-<id>` · Unix `./cc-<id>`; a *truly-bare* `cc` on `PATH` is a
PATH-installed launcher (`/spt:setup`'s job), not this project-root shortcut. **Overwrite is
sentinel-guarded:** the generator writes + checks a generated-by header marker — it overwrites
its own prior output freely, but refuses (with a warning) a same-named file that lacks the
sentinel, never clobbering a user file.
_Avoid_: `.ps1` shortcuts (PATHEXT won't find them); clobbering a non-generated file.

**`spt-<id>` shortcut** (picker `s` keybind, M12-W2):
<!-- [doc->REQ-RUN-SHORTCUT] -->
From any pre-start options set, `s` writes (or updates) a **`<basename>-<id>` launcher** at the
project root that bakes the current selection's **non-interactive** flags (terminal actions
only: adapter[:profile] + id + create|resume + start|attach|view; the interactive-only branches
— Kick/Instantiate/Change-adapter/Fork — are not bakeable). The **basename is a parameter**:
harness-agnostic spt-core defaults to **`spt`** (→ `spt-<id>`, e.g. `spt-doyle`); an
adapter/flow **overrides** it (spt-claude-code → `cc`, giving `cc-<id>`) — the Claude-Code-ness
lives in the adapter, **spt-core never emits `cc`**. The basename must be a *distinct* token,
never bare `spt`: a `spt.cmd` wrapper would shadow the real `spt.exe` only under cmd.exe
(cwd-first search), silently no-op in PowerShell/Unix, and self-recurse — so `spt-<id>` is the
safe, consistent form. The launcher is the **current OS's native form**: a **`.cmd`** on
Windows (the default `PATHEXT` excludes `.ps1`, so a bare name never resolves one; `.cmd` is
PATHEXT-resolvable), a POSIX **`sh`** (`chmod +x`) on Unix. **Invocation reality** (documented
in the generated header; `<name>` = `<basename>-<id>`): cmd.exe bare `<name>` in the project dir
· PowerShell `.\<name>` · Unix `./<name>`; a *truly-bare* basename on `PATH` is a PATH-installed
launcher (`/spt:setup`'s job), not this project-root shortcut. **Overwrite is sentinel-guarded:**
the generator writes + checks a generated-by header marker — it overwrites its own prior output
freely, but refuses (with a warning) a same-named file that lacks the sentinel, never clobbering
a user file.
_Avoid_: baking `cc` (a harness name) into spt-core; a bare `spt`/`cc` shadow wrapper; `.ps1`
shortcuts (PATHEXT won't find them); clobbering a non-generated file.

_Avoid_: a second bringup path; hard-coupling interaction to physical keybinds.

-**`cc-<id>` shortcut** (picker `s` keybind, M12-W2):

+**`spt-<id>` shortcut** (picker `s` keybind, M12-W2):

-From any pre-start options set, `s` writes (or updates) a **`cc-<id>` launcher** at the project

-root that bakes the current selection's **non-interactive** flags (terminal actions only:

-adapter[:profile] + id + create|resume + start|attach|view; the interactive-only branches —

-Kick/Instantiate/Change-adapter/Fork — are not bakeable). The launcher is the **current OS's

-native form**: a **`.cmd`** on Windows (the default `PATHEXT` excludes `.ps1`, so a bare name

-never resolves one; `.cmd` is PATHEXT-resolvable), a POSIX **`sh`** (`chmod +x`) on Unix.

-**Invocation reality** (documented in the generated header): cmd.exe bare `cc-<id>` in the

-project dir · PowerShell `.\cc-<id>` · Unix `./cc-<id>`; a *truly-bare* `cc` on `PATH` is a

-PATH-installed launcher (`/spt:setup`'s job), not this project-root shortcut. **Overwrite is

-sentinel-guarded:** the generator writes + checks a generated-by header marker — it overwrites

-its own prior output freely, but refuses (with a warning) a same-named file that lacks the

-sentinel, never clobbering a user file.

-_Avoid_: `.ps1` shortcuts (PATHEXT won't find them); clobbering a non-generated file.

+From any pre-start options set, `s` writes (or updates) a **`<basename>-<id>` launcher** at the

+project root that bakes the current selection's **non-interactive** flags (terminal actions

+only: adapter[:profile] + id + create|resume + start|attach|view; the interactive-only branches

+— Kick/Instantiate/Change-adapter/Fork — are not bakeable). The **basename is a parameter**:

+harness-agnostic spt-core defaults to **`spt`** (→ `spt-<id>`, e.g. `spt-doyle`); an

+adapter/flow **overrides** it (spt-claude-code → `cc`, giving `cc-<id>`) — the Claude-Code-ness

+lives in the adapter, **spt-core never emits `cc`**. The basename must be a *distinct* token,

+never bare `spt`: a `spt.cmd` wrapper would shadow the real `spt.exe` only under cmd.exe

+(cwd-first search), silently no-op in PowerShell/Unix, and self-recurse — so `spt-<id>` is the

+safe, consistent form. The launcher is the **current OS's native form**: a **`.cmd`** on

+Windows (the default `PATHEXT` excludes `.ps1`, so a bare name never resolves one; `.cmd` is

+PATHEXT-resolvable), a POSIX **`sh`** (`chmod +x`) on Unix. **Invocation reality** (documented

+in the generated header; `<name>` = `<basename>-<id>`): cmd.exe bare `<name>` in the project dir

+· PowerShell `.\<name>` · Unix `./<name>`; a *truly-bare* basename on `PATH` is a PATH-installed

+launcher (`/spt:setup`'s job), not this project-root shortcut. **Overwrite is sentinel-guarded:**

+the generator writes + checks a generated-by header marker — it overwrites its own prior output

+freely, but refuses (with a warning) a same-named file that lacks the sentinel, never clobbering

+_Avoid_: baking `cc` (a harness name) into spt-core; a bare `spt`/`cc` shadow wrapper; `.ps1`

+shortcuts (PATHEXT won't find them); clobbering a non-generated file.


Now the toml REQ-RUN-SHORTCUT title:


title = "`cc-<id>` launcher shortcut generation (picker `s` keybind, M12-W2-T2.4): from any pre-start options set the picker writes/updates a `cc-<id>` launcher at the project root baking the current selection's non-interactive `spt endpoint run` flags (terminal actions only: adapter[:profile] + id + (create|resume) + (start|attach|view); Kick/Instantiate/Change-adapter/Fork are interactive-only, not bakeable). The script is the CURRENT OS's native form — `.cmd` on Windows (NOT `.ps1`: default PATHEXT excludes `.ps1` so a bare/ext-less name never resolves one; `.cmd` is PATHEXT-resolvable — operator rev. 2026-06-14), POSIX `sh` (+chmod +x) on Unix (a single portable form can't be both). The generated header documents the invocation reality (cmd.exe bare `cc-<id>` in the project dir / PowerShell `.\\cc-<id>` / Unix `./cc-<id>`; a truly-bare `cc` = a PATH-installed launcher, `/spt:setup`'s job). Overwrite is SENTINEL-guarded: the generator writes + checks a generated-by header marker — it overwrites its own prior output freely (\"Update `cc-<id>` shortcut\"), but REFUSES + warns if a same-named file lacks the sentinel (never clobber a user file). Requires the additive `--create` flag on `Run{}` (the default-fresh made explicit; N-1-safe)."

title = "`<basename>-<id>` launcher shortcut generation (picker `s` keybind, M12-W2-T2.4): from any pre-start options set the picker writes/updates a `<basename>-<id>` launcher at the project root baking the current selection's non-interactive `spt endpoint run` flags (terminal actions only: adapter[:profile] + id + (create|resume) + (start|attach|view); Kick/Instantiate/Change-adapter/Fork are interactive-only, not bakeable). BASENAME IS A PARAMETER (operator rev. 2026-06-14): harness-agnostic spt-core defaults to `spt` (→ `spt-<id>`); an adapter/flow OVERRIDES it (spt-claude-code → `cc`), so spt-core NEVER bakes `cc` (a harness name) into itself. The basename must be a DISTINCT token, never bare `spt` (a `spt.cmd` would shadow the real `spt.exe` only under cmd.exe cwd-first search, silently no-op in PowerShell/Unix, and self-recurse). The script is the CURRENT OS's native form — `.cmd` on Windows (NOT `.ps1`: default PATHEXT excludes `.ps1` so a bare/ext-less name never resolves one; `.cmd` is PATHEXT-resolvable), POSIX `sh` (+chmod +x) on Unix (a single portable form can't be both). The generated header documents the invocation reality (cmd.exe bare `<name>` in the project dir / PowerShell `.\\<name>` / Unix `./<name>`; a truly-bare basename on PATH = a PATH-installed launcher, `/spt:setup`'s job). Overwrite is SENTINEL-guarded: the generator writes + checks a generated-by header marker — it overwrites its own prior output freely, but REFUSES + warns if a same-named file lacks the sentinel (never clobber a user file). Requires the additive `--create` flag on `Run{}` (the default-fresh made explicit; N-1-safe)."


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

required_stages = ["doc", "impl", "unit"]  # activated M12-W2 (no int: TUI Buffer + state-model unit asserts; live loop manual-verify; bringup path int-covered by REQ-HOST-RUN-1/REQ-RC-1)

-title = "`cc-<id>` launcher shortcut generation (picker `s` keybind, M12-W2-T2.4): from any pre-start options set the picker writes/updates a `cc-<id>` launcher at the project root baking the current selection's non-interactive `spt endpoint run` flags (terminal actions only: adapter[:profile] + id + (create|resume) + (start|attach|view); Kick/Instantiate/Change-adapter/Fork are interactive-only, not bakeable). The script is the CURRENT OS's native form — `.cmd` on Windows (NOT `.ps1`: default PATHEXT excludes `.ps1` so a bare/ext-less name never resolves one; `.cmd` is PATHEXT-resolvable — operator rev. 2026-06-14), POSIX `sh` (+chmod +x) on Unix (a single portable form can't be both). The generated header documents the invocation reality (cmd.exe bare `cc-<id>` in the project dir / PowerShell `.\\cc-<id>` / Unix `./cc-<id>`; a truly-bare `cc` = a PATH-installed launcher, `/spt:setup`'s job). Overwrite is SENTINEL-guarded: the generator writes + checks a generated-by header marker — it overwrites its own prior output freely (\"Update `cc-<id>` shortcut\"), but REFUSES + warns if a same-named file lacks the sentinel (never clobber a user file). Requires the additive `--create` flag on `Run{}` (the default-fresh made explicit; N-1-safe)."

+title = "`<basename>-<id>` launcher shortcut generation (picker `s` keybind, M12-W2-T2.4): from any pre-start options set the picker writes/updates a `<basename>-<id>` launcher at the project root baking the current selection's non-interactive `spt endpoint run` flags (terminal actions only: adapter[:profile] + id + (create|resume) + (start|attach|view); Kick/Instantiate/Change-adapter/Fork are interactive-only, not bakeable). BASENAME IS A PARAMETER (operator rev. 2026-06-14): harness-agnostic spt-core defaults to `spt` (→ `spt-<id>`); an adapter/flow OVERRIDES it (spt-claude-code → `cc`), so spt-core NEVER bakes `cc` (a harness name) into itself. The basename must be a DISTINCT token, never bare `spt` (a `spt.cmd` would shadow the real `spt.exe` only under cmd.exe cwd-first search, silently no-op in PowerShell/Unix, and self-recurse). The script is the CURRENT OS's native form — `.cmd` on Windows (NOT `.ps1`: default PATHEXT excludes `.ps1` so a bare/ext-less name never resolves one; `.cmd` is PATHEXT-resolvable), POSIX `sh` (+chmod +x) on Unix (a single portable form can't be both). The generated header documents the invocation reality (cmd.exe bare `<name>` in the project dir / PowerShell `.\\<name>` / Unix `./<name>`; a truly-bare basename on PATH = a PATH-installed launcher, `/spt:setup`'s job). Overwrite is SENTINEL-guarded: the generator writes + checks a generated-by header marker — it overwrites its own prior output freely, but REFUSES + warns if a same-named file lacks the sentinel (never clobber a user file). Requires the additive `--create` flag on `Run{}` (the default-fresh made explicit; N-1-safe)."

required_stages = ["doc", "impl", "unit"]  # activated M12-W2 (no int: shortcut content + sentinel create-vs-update as unit; flag→action mapping unit)

# ───────────────────────────── Install / migration / infra ──────────────────


Now the plan Q4:


- **Q4 `cc-<id>` shortcut: per-OS native + sentinel-guarded overwrite.** Current-OS only:
  **`.cmd` on Windows** (rev. 2026-06-14, operator: default PATHEXT EXCLUDES `.ps1`, so a
  bare/ext-less name never resolves one and `.ps1` won't run without `powershell -File`;
  `.cmd`/`.bat` ARE in PATHEXT), POSIX `sh` (+`chmod +x`) on Unix. Bake the non-interactive
  flags. The generated header documents the invocation reality: cmd.exe bare `cc-<id>` in the
  project dir · PowerShell `.\cc-<id>` · Unix `./cc-<id>` · a truly-bare `cc` = a
  PATH-installed launcher (`/spt:setup`'s job, SCOPE #1), not this project-root shortcut.

- **Q4 `<basename>-<id>` shortcut: parameterized basename + per-OS native + sentinel-guarded
  overwrite.** **Basename is a PARAMETER** (rev. 2 2026-06-14, operator): harness-agnostic
  spt-core defaults to **`spt`** (→ `spt-<id>`, e.g. `spt-doyle`); an adapter/flow OVERRIDES it
  (spt-claude-code → `cc` → `cc-<id>`) — **spt-core never bakes `cc`** (a harness name) into
  itself. Never bare `spt` (a `spt.cmd` shadows the real `spt.exe` only under cmd.exe cwd-first
  search → inconsistent + self-recursing); a distinct `spt-<id>` is the safe form. Bare "launch
  this project" is already `spt endpoint run` (no-arg picker) — no shadow wrapper.
  **`.cmd` on Windows** (rev. 1 2026-06-14: default PATHEXT EXCLUDES `.ps1`, so a bare/ext-less
  name never resolves one and `.ps1` won't run without `powershell -File`; `.cmd`/`.bat` ARE in
  PATHEXT), POSIX `sh` (+`chmod +x`) on Unix. Bake the non-interactive flags. The generated
  header documents the invocation reality (`<name>` = `<basename>-<id>`): cmd.exe bare `<name>`
  in the project dir · PowerShell `.\<name>` · Unix `./<name>` · a truly-bare basename on PATH =
  a PATH-installed launcher (`/spt:setup`'s job, SCOPE #1), not this project-root shortcut.


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

- **Q4 `cc-<id>` shortcut: per-OS native + sentinel-guarded overwrite.** Current-OS only:
  **`.cmd` on Windows** (rev. 2026-06-14, operator: default PATHEXT EXCLUDES `.ps1`, so a
  bare/ext-less name never resolves one and `.ps1` won't run without `powershell -File`;
  `.cmd`/`.bat` ARE in PATHEXT), POSIX `sh` (+`chmod +x`) on Unix. Bake the non-interactive
  flags. The generated header documents the invocation reality: cmd.exe bare `cc-<id>` in the
  project dir · PowerShell `.\cc-<id>` · Unix `./cc-<id>` · a truly-bare `cc` = a
  PATH-installed launcher (`/spt:setup`'s job, SCOPE #1), not this project-root shortcut.

- **Q4 `<basename>-<id>` shortcut: parameterized basename + per-OS native + sentinel-guarded
  overwrite.** **Basename is a PARAMETER** (rev. 2 2026-06-14, operator): harness-agnostic
  spt-core defaults to **`spt`** (→ `spt-<id>`, e.g. `spt-doyle`); an adapter/flow OVERRIDES it
  (spt-claude-code → `cc` → `cc-<id>`) — **spt-core never bakes `cc`** (a harness name) into
  itself. Never bare `spt` (a `spt.cmd` shadows the real `spt.exe` only under cmd.exe cwd-first
  search → inconsistent + self-recursing); a distinct `spt-<id>` is the safe form. Bare "launch
  this project" is already `spt endpoint run` (no-arg picker) — no shadow wrapper.
  **`.cmd` on Windows** (rev. 1 2026-06-14: default PATHEXT EXCLUDES `.ps1`, so a bare/ext-less
  name never resolves one and `.ps1` won't run without `powershell -File`; `.cmd`/`.bat` ARE in
  PATHEXT), POSIX `sh` (+`chmod +x`) on Unix. Bake the non-interactive flags. The generated
  header documents the invocation reality (`<name>` = `<basename>-<id>`): cmd.exe bare `<name>`
  in the project dir · PowerShell `.\<name>` · Unix `./<name>` · a truly-bare basename on PATH =
  a PATH-installed launcher (`/spt:setup`'s job, SCOPE #1), not this project-root shortcut.

`cmd_endpoint_run` with `resume=Some(id)`. NO new daemon surface. Offline+LOCAL only (a

remote offline endpoint = Instantiate-locally). Empty ledger ⇒ no Resume option. Adapter

resume-capability is its manifest `resume`'s job, surfaced at the terminal action.

-- **Q4 `cc-<id>` shortcut: per-OS native + sentinel-guarded overwrite.** Current-OS only:

-  **`.cmd` on Windows** (rev. 2026-06-14, operator: default PATHEXT EXCLUDES `.ps1`, so a

-  bare/ext-less name never resolves one and `.ps1` won't run without `powershell -File`;

-  `.cmd`/`.bat` ARE in PATHEXT), POSIX `sh` (+`chmod +x`) on Unix. Bake the non-interactive

-  flags. The generated header documents the invocation reality: cmd.exe bare `cc-<id>` in the

-  project dir · PowerShell `.\cc-<id>` · Unix `./cc-<id>` · a truly-bare `cc` = a

-  PATH-installed launcher (`/spt:setup`'s job, SCOPE #1), not this project-root shortcut.

+- **Q4 `<basename>-<id>` shortcut: parameterized basename + per-OS native + sentinel-guarded

+  overwrite.** **Basename is a PARAMETER** (rev. 2 2026-06-14, operator): harness-agnostic

+  spt-core defaults to **`spt`** (→ `spt-<id>`, e.g. `spt-doyle`); an adapter/flow OVERRIDES it

+  (spt-claude-code → `cc` → `cc-<id>`) — **spt-core never bakes `cc`** (a harness name) into

+  itself. Never bare `spt` (a `spt.cmd` shadows the real `spt.exe` only under cmd.exe cwd-first

+  search → inconsistent + self-recursing); a distinct `spt-<id>` is the safe form. Bare "launch

+  this project" is already `spt endpoint run` (no-arg picker) — no shadow wrapper.

+  **`.cmd` on Windows** (rev. 1 2026-06-14: default PATHEXT EXCLUDES `.ps1`, so a bare/ext-less

+  name never resolves one and `.ps1` won't run without `powershell -File`; `.cmd`/`.bat` ARE in

+  PATHEXT), POSIX `sh` (+`chmod +x`) on Unix. Bake the non-interactive flags. The generated

+  header documents the invocation reality (`<name>` = `<basename>-<id>`): cmd.exe bare `<name>`

+  in the project dir · PowerShell `.\<name>` · Unix `./<name>` · a truly-bare basename on PATH =

+  a PATH-installed launcher (`/spt:setup`'s job, SCOPE #1), not this project-root shortcut.

Overwrite = the generator writes + checks a generated-by **sentinel** header marker:

overwrite our-own freely, **REFUSE + warn** if a same-named file lacks the sentinel (never

clobber a user file). "Update if exists" = overwrite-our-own-only.


Re-sweep: picker tests + traceable + clippy.


Bash

cd "C:\Users\decid\Documents\projects\spt-core" && cargo test -p spt --bin spt picker:: 2>&1 | grep -iE 'test result|FAILED|error\[' | tail; echo "---"; traceable-reqs check 2>&1 | grep -iE '200 requirements|complete|parse error|RUN-PICKER|RUN-SHORTCUT' | head


test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 125 filtered out; finished in 0.02s
---
200 requirements: 200 complete, 0 incomplete, 0 findings
       Grace-period wait completes before composing INIT_SIGNOFF (1.1)
       Member roster: node-level union-merge grow-set (per member: pubkey, label, machine_id, last-known address, last-seen — NOT the seed), the discovery directory the mesh dials by. Seeded IN FULL at pairing (seed-holder hands joiner the whole current roster, incl. offline members — folds in deferred pairing-time hostname capture + post-join address seeding); each node authors its own entry stamped with its lease_epoch, merged strictly-greater-wins (the node_label lease); exchanged only over seed-proof'd member connections; forgery-inert (a fake entry names a pubkey that still can't seed-proof). Removal needs a TOMBSTONE — a per-pubkey revoked marker that propagates, dominates the entry, gates admission (seed-proof ∧ ¬tombstoned), and prevents reinsert; cleared by a completed re-pair of that pubkey. Persists through silence (offline member keeps its entry).
  [OK] REQ-RUN-PICKER  required: [doc, impl, unit]  stages: +doc +impl +unit -int
  [OK] REQ-RUN-SHORTCUT  required: [doc, impl, unit]  stages: +doc +impl +unit -int
       Per-machine re-pair trust overwrite: registry rows carry a hashed stable machine identifier (OS machine id /etc/machine-id|MachineGuid, domain-separated SHA-256 before gossip, spt-minted persisted UUID fallback; additive serde-default field — old rows parse clean); a COMPLETED pairing ceremony presenting the same node label AND machine id as an existing trusted row evicts the superseded identity's trust + registry rows on the seed-holder and replicates the eviction; a gossiped claim alone never evicts trust (M8 decisions 13, 22)


26 picker tests green, traceable 200/200. Clippy on spt:


cd "C:\Users\decid\Documents\projects\spt-core" && cargo clippy -p spt --all-targets -- -D warnings 2>&1 | grep -iE 'warning|error' | head; echo "CLIPPY_RC=${PIPESTATUS[0]}"


Clippy clean, all green. Mark tasks; commit (operator-authorized).


Updated task #8 status


Updated task #9 status


cd "C:\Users\decid\Documents\projects\spt-core" && git add -A && git commit -q -F - <<'EOF'
feat(picker): M12 W2 interactive `spt endpoint run` ratatui picker + spt-<id> shortcut

Bare `spt endpoint run` (no --adapter/--id) now opens an in-process ratatui
picker; the flagged form stays the REQ-HOST-RUN-1 non-interactive path,
untouched. Pure front-end: every terminal action routes through the one bringup
core (cmd_endpoint_run / the rc pump) — no second bringup path (the gate
invariant, doyle ruling M12-W2-RULING.md).

picker/ (in-process module, action-enum single source of truth):
- model.rs: pure state + transitions (kind → create-new adapter→profile tree →
  id entry; pick-existing category L/R + grouped/alpha + status squares +
  type-to-filter + confirm + resume sub-screen). Status is online/offline only;
  the blue attached tri-state + Kick are scheduled as W2.5 (own broker
  attach-presence slice). Resume-from-history enumerates spt_store::sessions
  (ledger exists, M10/REQ-TERM-6) → cmd_endpoint_run --resume.
- data.rs: read-only gather over existing surfaces (registry adapters+profiles,
  roster + WAN snapshots, info.json description, best-effort contextstore
  project history, session ledger). No new daemon surface.
- view.rs: renders &PickerModel to a ratatui Buffer (buffer + state-model unit
  asserts; the live key loop is the manual-verify leg, REQ-PAIR-6 precedent).
- shortcut.rs: `<basename>-<id>` launcher. Basename is a PARAMETER (default
  `spt` → spt-<id>; an adapter overrides → cc) — spt-core never bakes `cc`.
  Per-OS native (.cmd on Windows / sh +chmod on Unix; .ps1 excluded by PATHEXT),
  sentinel-guarded overwrite, baked invocation-reality header.
- mod.rs: crossterm raw + ratatui live loop; dispatch routes Outcomes through
  the existing fns.

Run{}: adapter/id → Option (bare = picker), additive --create (default-fresh
made explicit, N-1-safe; clap-conflicts --resume). cmd_endpoint_run pub(crate).

Deps: ratatui 0.29, nucleo-matcher 0.3 (crossterm 0.28 already in tree).

REQ-RUN-PICKER + REQ-RUN-SHORTCUT (doc+impl+unit, no int) — CONTEXT.md doc tags,
impl/unit tags in place; traceable 200/200. W2.5 (attached-presence + Kick)
forward-pointer in the plan + docs/DEFERRED.md.

Co-authored by: todlando
EOF
echo "COMMIT_RC=$?" && git log --oneline -1


warning: in the working copy of 'Cargo.lock', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'docs/DEFERRED.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'M12-W2-PLAN.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'M12-W2-RULING.md', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/picker/data.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/picker/mod.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/picker/model.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/picker/shortcut.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/src/picker/view.rs', LF will be replaced by CRLF the next time Git touches it
COMMIT_RC=0
6e76f62 feat(picker): M12 W2 interactive `spt endpoint run` ratatui picker + spt-<id> shortcut


Committed **@6e76f62**. Ping doyle to gate:


cd "C:\Users\decid\Documents\projects\spt-core" && $OWL send doyle <<'EOF'
W2 BUILT + COMMITTED @6e76f62 on m12-w1-bringup-rc — ready to gate.

Sweep (all green):
- picker bin unit tests: 26 passed (model transitions + shortcut + ratatui Buffer asserts).
- full `cargo test --workspace`: green (ran pre-basename-rename; the rename touched only shortcut.rs/view/mod + docs, no other crate — picker tests re-run green after).
- clippy --workspace --all-targets -D warnings: EXIT=0.
- traceable-reqs check: 200/200 complete, 0 findings; REQ-RUN-PICKER + REQ-RUN-SHORTCUT both [doc+impl+unit] satisfied (CONTEXT.md doc tags).

Load-bearing for your verify:
- SINGLE BRINGUP PATH (your gate invariant): picker/model.rs Outcome enum is the only convergence point; picker/mod.rs::dispatch routes Run→crate::cli::cmd_endpoint_run, Attach→crate::rc::run_attach. The re-entrant confirm options (ChangeAdapter/Instantiate/Fork) are SCREEN transitions back into create-new (reenter_create), NOT new bringup — all still terminate in cmd_endpoint_run. Grep confirms no second spawn path in picker/.
- Resume: model::resume_outcome reads selected_resume (ledger row) → Run{resume:Some(sid)}; offline+LOCAL gated in confirm_options. data::resume_rows_for reads sessions::last_k. No new daemon surface.
- Basename param (your rev.2): shortcut::DEFAULT_BASENAME="spt" → spt-<id>; basename_is_parameterized test proves cc override works + spt-core body never contains cc-<id>. bare-spt shadow rejected by design (distinct token).
- Buffer tests: view::tests render via TestBackend, assert squares/tree/category/description/confirm/resume by scanning the rendered Buffer (your "assert the rendered buffer").
- Manual-verify leg (noted like REQ-PAIR-6): the live crossterm key loop in mod.rs::event_loop is not unit-driven; model+view+shortcut under it are.

Plan crystallized + W2.5 forward-pointer in M12-W2-PLAN.md + docs/DEFERRED.md. Operator already authorized the commit (history-tidy). Over to you.
EOF
echo "EXIT=$?"


➜ SENT:doyle
EXIT=0


Sent to doyle. Update memory to reflect W2 committed + pending gate + W2.5 scheduled: