Read the `[adapter]` header section + DOCS-STRATEGY CI-commitments to add both doc tags:


24	### `[adapter]` — header
25	```toml
26	[adapter]
27	name = "claude-spt"
28	version = "2.0.0"
29	min_spt_core_version = "1.0.0"     # readable before any update; compat gate
30	hostable_types = ["LiveAgent", "ReadyAgent", "Psyche", "Worker"]
31	shortcut_basename = "cc"           # optional; brands the picker's launcher → cc-<id> (default "spt")
32	host_binaries = ["claude"]         # optional; the harness exe(s) this adapter hosts agents inside
33	```
34
35	<!-- [doc->REQ-MANIFEST-7] -->
36	`shortcut_basename` *(optional, default `spt`)* — the basename the `spt endpoint
37	run` picker's `s` keybind bakes into the generated `<basename>-<id>` launcher
38	shortcut at the project root (REQ-MANIFEST-7). Absent ⇒ the harness-agnostic
39	`spt` (→ `spt-<id>`); an adapter sets it to brand its shortcuts — `claude-spt`
40	uses `cc`, giving `cc-doyle`. spt-core never hardcodes a harness name; the
41	picker reads this from the **resolved** manifest of the selected adapter. The
42	launcher is the current OS's native form (`.cmd` on Windows — `.ps1` is excluded
43	by the default `PATHEXT`; a POSIX `sh` `+chmod +x` on Unix) and overwriting is
44	guarded by a generated-by sentinel (a foreign same-named file is never clobbered).
45

### `[adapter]` — header
```toml
[adapter]
name = "claude-spt"
version = "2.0.0"
min_spt_core_version = "1.0.0"     # readable before any update; compat gate
hostable_types = ["LiveAgent", "ReadyAgent", "Psyche", "Worker"]
shortcut_basename = "cc"           # optional; brands the picker's launcher → cc-<id> (default "spt")
host_binaries = ["claude"]         # optional; the harness exe(s) this adapter hosts agents inside
```

<!-- [doc->REQ-MANIFEST-7] -->
`shortcut_basename` *(optional, default `spt`)* — the basename the `spt endpoint
run` picker's `s` keybind bakes into the generated `<basename>-<id>` launcher
shortcut at the project root (REQ-MANIFEST-7). Absent ⇒ the harness-agnostic
`spt` (→ `spt-<id>`); an adapter sets it to brand its shortcuts — `claude-spt`
uses `cc`, giving `cc-doyle`. spt-core never hardcodes a harness name; the
picker reads this from the **resolved** manifest of the selected adapter. The
launcher is the current OS's native form (`.cmd` on Windows — `.ps1` is excluded
by the default `PATHEXT`; a POSIX `sh` `+chmod +x` on Unix) and overwriting is
guarded by a generated-by sentinel (a foreign same-named file is never clobbered).


55	## CI commitments
56
57	rustdoc, the manifest JSON Schema, `llms.txt`/`llms-full.txt`, and CLI help exports are **generated and checked in CI** — a doc-drift gate. Doc quality lives on the same footing as tests.
58
59	---
60

## CI commitments

rustdoc, the manifest JSON Schema, `llms.txt`/`llms-full.txt`, and CLI help exports are **generated and checked in CI** — a doc-drift gate. Doc quality lives on the same footing as tests.

---


Edit

host_binaries = ["claude"]         # optional; the harness exe(s) this adapter hosts agents inside
```

<!-- [doc->REQ-MANIFEST-7] -->

host_binaries = ["claude"]         # optional; the harness exe(s) this adapter hosts agents inside
```

<!-- [doc->REQ-ADAPTER-VERSION-CMD] -->
`version` is **mandatory**. It is the single declared adapter version — read
before any update (the `gh_release` compare point), surfaced by `spt adapter
version <name>` (which prints this `[adapter].version` of a registered adapter;
exit 1 if unregistered), and the value the post-update `message` gate keys on.
There is no second version source — no `[strings].version`, no `get-string`
convention.

<!-- [doc->REQ-MANIFEST-7] -->


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

host_binaries = ["claude"]         # optional; the harness exe(s) this adapter hosts agents inside
```

<!-- [doc->REQ-MANIFEST-7] -->

host_binaries = ["claude"]         # optional; the harness exe(s) this adapter hosts agents inside
```

<!-- [doc->REQ-ADAPTER-VERSION-CMD] -->
`version` is **mandatory**. It is the single declared adapter version — read
before any update (the `gh_release` compare point), surfaced by `spt adapter
version <name>` (which prints this `[adapter].version` of a registered adapter;
exit 1 if unregistered), and the value the post-update `message` gate keys on.
There is no second version source — no `[strings].version`, no `get-string`
convention.

<!-- [doc->REQ-MANIFEST-7] -->

+`version` is **mandatory**. It is the single declared adapter version — read

+before any update (the `gh_release` compare point), surfaced by `spt adapter

+version <name>` (which prints this `[adapter].version` of a registered adapter;

+exit 1 if unregistered), and the value the post-update `message` gate keys on.

+There is no second version source — no `[strings].version`, no `get-string`

`shortcut_basename` *(optional, default `spt`)* — the basename the `spt endpoint

run` picker's `s` keybind bakes into the generated `<basename>-<id>` launcher


rustdoc, the manifest JSON Schema, `llms.txt`/`llms-full.txt`, and CLI help exports are **generated and checked in CI** — a doc-drift gate. Doc quality lives on the same footing as tests.

rustdoc, the manifest JSON Schema, `llms.txt`/`llms-full.txt`, and CLI help exports are **generated and checked in CI** — a doc-drift gate. Doc quality lives on the same footing as tests.

<!-- [doc->REQ-DOCS-NO-INTERNAL-CODES] -->
**Public help carries no internal codes.** The public CLI `--help` (the clap `///` doc-comments) and the generated `docs-site/src/cli/reference.md` MUST NOT contain internal tracker/decision codes — `REQ-*`, `F-###`, `M#-W#`, `ADR-####`. They are meaningless to an end user reading `--help` and ship to GitHub Pages. The `xtask check` docs gate scans the **generated** reference for these tokens and fails on any hit (regeneration alone keeps drift at zero but would faithfully republish a leak — the scan is what gives the gate teeth). The scan is scoped to the generated reference by construction, so rustdoc `///` on functions and structs is out of scope and keeps its `REQ`/`ADR` cross-references — those are source-internal, never public help. Substance stays; codes are rewritten in plain language.


/spt:send doyle a message about W4 for his gate and approval


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

rustdoc, the manifest JSON Schema, `llms.txt`/`llms-full.txt`, and CLI help exports are **generated and checked in CI** — a doc-drift gate. Doc quality lives on the same footing as tests.

<!-- [doc->REQ-DOCS-NO-INTERNAL-CODES] -->
**Public help carries no internal codes.** The public CLI `--help` (the clap `///` doc-comments) and the generated `docs-site/src/cli/reference.md` MUST NOT contain internal tracker/decision codes — `REQ-*`, `F-###`, `M#-W#`, `ADR-####`. They are meaningless to an end user reading `--help` and ship to GitHub Pages. The `xtask check` docs gate scans the **generated** reference for these tokens and fails on any hit (regeneration alone keeps drift at zero but would faithfully republish a leak — the scan is what gives the gate teeth). The scan is scoped to the generated reference by construction, so rustdoc `///` on functions and structs is out of scope and keeps its `REQ`/`ADR` cross-references — those are source-internal, never public help. Substance stays; codes are rewritten in plain language.

+**Public help carries no internal codes.** The public CLI `--help` (the clap `///` doc-comments) and the generated `docs-site/src/cli/reference.md` MUST NOT contain internal tracker/decision codes — `REQ-*`, `F-###`, `M#-W#`, `ADR-####`. They are meaningless to an end user reading `--help` and ship to GitHub Pages. The `xtask check` docs gate scans the **generated** reference for these tokens and fails on any hit (regeneration alone keeps drift at zero but would faithfully republish a leak — the scan is what gives the gate teeth). The scan is scoped to the generated reference by construction, so rustdoc `///` on functions and structs is out of scope and keeps its `REQ`/`ADR` cross-references — those are source-internal, never public help. Substance stays; codes are rewritten in plain language.

## Concrete templates (from firsthand artifacts)


All sweeps + impl + docs done. Regenerate reference, then run xtask check (drift + new scan):


PowerShell

cargo run -p xtask -- gen 2>&1 | Select-Object -Last 2; "---CHECK---"; cargo run -p xtask -- check 2>&1 | Select-String -Pattern "OK|FAIL|drift|leaked|reference.md:|dead" | Select-Object -Last 20; "CHECK_EXIT=$LASTEXITCODE"

Regen reference + xtask check (drift + token scan)


Error: Exit code 101
For more information about this error, try `rustc --explain E0308`.
error: could not compile `xtask` (bin "xtask") due to 1 previous error
---CHECK---

225 |             if left_ok(idx) && next_is(idx + prefix.len(), |c| ok_next(&c)) {
225 |             if left_ok(idx) && next_is(idx + prefix.len(), |c| ok_next(&c)) {
    |                                                                ^^^^^^^ `ok_next` captured here
CHECK_EXIT=101


Compile error: closure capturing `ok_next` can't coerce to `fn`. Fix with a `next_char` helper:


Edit

    let next_is = |idx: usize, pred: fn(char) -> bool| {
        text[idx..].chars().next().map(pred).unwrap_or(false)
    };

    let mut hits = Vec::new();
    // REQ-<UPPER…> / ADR-<digit…> / F-<digit…>
    for (prefix, ok_next) in [
        ("REQ-", char::is_ascii_uppercase as fn(&char) -> bool),
        ("ADR-", char::is_ascii_digit as fn(&char) -> bool),
        ("F-", char::is_ascii_digit as fn(&char) -> bool),
    ] {
        for (idx, _) in text.match_indices(prefix) {
            if left_ok(idx) && next_is(idx + prefix.len(), |c| ok_next(&c)) {
                hits.push((line_of(idx), capture_code(&text[idx..])));
            }
        }
    }
    // M<digit…>-W<digit…> (e.g. `M8-W5`, `M12-W1`): anchor on `-W<digit>`, walk
    // back over digits to a boundary-anchored `M`.
    for (idx, _) in text.match_indices("-W") {
        if !next_is(idx + 2, |c| c.is_ascii_digit()) {
            continue;
        }

    let next_char = |idx: usize| text[idx..].chars().next();

    let mut hits = Vec::new();
    // REQ-<UPPER…> / ADR-<digit…> / F-<digit…>
    for (prefix, ok_next) in [
        ("REQ-", char::is_ascii_uppercase as fn(&char) -> bool),
        ("ADR-", char::is_ascii_digit as fn(&char) -> bool),
        ("F-", char::is_ascii_digit as fn(&char) -> bool),
    ] {
        for (idx, _) in text.match_indices(prefix) {
            if left_ok(idx) && next_char(idx + prefix.len()).is_some_and(|c| ok_next(&c)) {
                hits.push((line_of(idx), capture_code(&text[idx..])));
            }
        }
    }
    // M<digit…>-W<digit…> (e.g. `M8-W5`, `M12-W1`): anchor on `-W<digit>`, walk
    // back over digits to a boundary-anchored `M`.
    for (idx, _) in text.match_indices("-W") {
        if !next_char(idx + 2).is_some_and(|c| c.is_ascii_digit()) {
            continue;
        }


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

    let next_is = |idx: usize, pred: fn(char) -> bool| {
        text[idx..].chars().next().map(pred).unwrap_or(false)
    };

    let mut hits = Vec::new();
    // REQ-<UPPER…> / ADR-<digit…> / F-<digit…>
    for (prefix, ok_next) in [
        ("REQ-", char::is_ascii_uppercase as fn(&char) -> bool),
        ("ADR-", char::is_ascii_digit as fn(&char) -> bool),
        ("F-", char::is_ascii_digit as fn(&char) -> bool),
    ] {
        for (idx, _) in text.match_indices(prefix) {
            if left_ok(idx) && next_is(idx + prefix.len(), |c| ok_next(&c)) {
                hits.push((line_of(idx), capture_code(&text[idx..])));
            }
        }
    }
    // M<digit…>-W<digit…> (e.g. `M8-W5`, `M12-W1`): anchor on `-W<digit>`, walk
    // back over digits to a boundary-anchored `M`.
    for (idx, _) in text.match_indices("-W") {
        if !next_is(idx + 2, |c| c.is_ascii_digit()) {
            continue;
        }

    let next_char = |idx: usize| text[idx..].chars().next();

    let mut hits = Vec::new();
    // REQ-<UPPER…> / ADR-<digit…> / F-<digit…>
    for (prefix, ok_next) in [
        ("REQ-", char::is_ascii_uppercase as fn(&char) -> bool),
        ("ADR-", char::is_ascii_digit as fn(&char) -> bool),
        ("F-", char::is_ascii_digit as fn(&char) -> bool),
    ] {
        for (idx, _) in text.match_indices(prefix) {
            if left_ok(idx) && next_char(idx + prefix.len()).is_some_and(|c| ok_next(&c)) {
                hits.push((line_of(idx), capture_code(&text[idx..])));
            }
        }
    }
    // M<digit…>-W<digit…> (e.g. `M8-W5`, `M12-W1`): anchor on `-W<digit>`, walk
    // back over digits to a boundary-anchored `M`.
    for (idx, _) in text.match_indices("-W") {
        if !next_char(idx + 2).is_some_and(|c| c.is_ascii_digit()) {
            continue;
        }

let line_of = |idx: usize| line_starts.partition_point(|&s| s <= idx);

// Left boundary: start of text, or a non-alphanumeric byte before `idx`.

let left_ok = |idx: usize| idx == 0 || !bytes[idx - 1].is_ascii_alphanumeric();

-    let next_is = |idx: usize, pred: fn(char) -> bool| {

-        text[idx..].chars().next().map(pred).unwrap_or(false)

+    let next_char = |idx: usize| text[idx..].chars().next();

-            if left_ok(idx) && next_is(idx + prefix.len(), |c| ok_next(&c)) {

+            if left_ok(idx) && next_char(idx + prefix.len()).is_some_and(|c| ok_next(&c)) {

-        if !next_is(idx + 2, |c| c.is_ascii_digit()) {

+        if !next_char(idx + 2).is_some_and(|c| c.is_ascii_digit()) {


PowerShell

cargo run -p xtask -- gen 2>&1 | Select-Object -Last 2; "---CHECK---"; cargo run -p xtask -- check 2>&1 | Select-String -Pattern "OK|FAIL|drift|leaked|reference.md:|dead|error\[" | Select-Object -Last 20; "CHECK_EXIT=$LASTEXITCODE"

Regen + xtask check after fix


     Running `target\debug\xtask.exe gen`
xtask gen: wrote C:\Users\decid\Documents\projects\spt-core\docs-site/src/cli/reference.md
---CHECK---

xtask check: OK
CHECK_EXIT=0


xtask check OK (drift==0 + scan passes). Run xtask scan unit tests + cli version tests + independent leak grep:


cargo test -p xtask docs_token_gate 2>&1 | Select-String -Pattern "test result|FAILED|panic"; "---CLI VERSION---"; cargo test -p spt --bin spt adapter_version 2>&1 | Select-String -Pattern "test result|FAILED|panic|error\["; "---GREP reference.md leak classes---"; Select-String -Path docs-site/src/cli/reference.md -Pattern "REQ-[A-Z]|ADR-\d{4}|F-\d{3}|M\d+-W\d+" | Measure-Object | Select-Object -ExpandProperty Count

xtask scan tests + cli version tests + leak grep count


test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s
---CLI VERSION---
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 227 filtered out; finished in 0.01s
---GREP reference.md leak classes---
0


All green (xtask 2/2, cli version 2/2, reference.md leaks=0). Now traceable-reqs + clippy + broad parse-test sanity:


traceable-reqs check 2>&1 | Select-String -Pattern "ADAPTER-VERSION-CMD|DOCS-NO-INTERNAL-CODES"; "TRACE_EXIT=$LASTEXITCODE"

traceable check for both new REQs


cargo clippy --workspace --all-targets -- -D warnings 2>&1 | Select-String -Pattern "warning:|error|Finished" | Select-Object -Last 12; "CLIPPY_EXIT=$LASTEXITCODE"

Workspace clippy CI form


  [OK] REQ-ADAPTER-VERSION-CMD  required: [doc, impl, unit]  stages: +doc +impl +unit -int
  [OK] REQ-DOCS-NO-INTERNAL-CODES  required: [doc, impl, unit]  stages: +doc +impl +unit -int
TRACE_EXIT=0


    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.84s
CLIPPY_EXIT=0


Confirm no test asserts on the swept help strings + run the proof/api parse tests:


Bash

grep -rn "REQ-KICK-1\|REQ-EP-1/REQ-EP-6\|ADR-0021\|ADR-0008 amendment, REQ-TERM-4\|(ADR-0019)\|(ADR-0022)\|(ADR-0020)\|(REQ-MSG-5)" crates/spt/src crates/spt/tests --include=*.rs | grep -i "assert\|contains\|expect(" | head

Check for tests asserting swept tokens


(Bash completed with no output)


PowerShell

cargo test -p spt --bin spt "adapter_subcommands_parse" 2>&1 | Select-String "test result"; cargo test -p spt --bin spt "adapter_translate_proof_parses" 2>&1 | Select-String "test result"

Run proof parse tests post-sweep


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


No test asserts on swept tokens; parse tests pass. Review full changeset + commit W6 (both REQs):


Bash

cd "C:/Users/decid/Documents/projects/spt-core" && git status --short

Confirm W6 changed files


 M crates/spt/src/api/mod.rs
 M crates/spt/src/cli.rs
 M crates/xtask/src/main.rs
 M docs-site/src/cli/reference.md
 M docs/DOCS-STRATEGY.md
 M docs/MANIFEST.md
 M traceable-reqs.toml


cd "C:/Users/decid/Documents/projects/spt-core" && git add -A && git commit -q -F - <<'EOF'
feat(cli,xtask): W6 adapter version cmd + public-help no-internal-codes gate

Two REQs (operator-directed, minted this commit per traceable rule 3), gated
together as the last v0.13.2 wave.

REQ-ADAPTER-VERSION-CMD: `spt adapter version <name>` → resolve_option →
print the EXISTING mandatory `[adapter].version` manifest field (not a
`[strings].version`, not get-string, no second source — the operator-corrected
form). New AdapterCmd::Version{option} + cmd_adapter_version; unresolvable
option exits 1 like the sibling adapter subcommands. unit-only.

REQ-DOCS-NO-INTERNAL-CODES: public CLI --help (clap `///`) and the generated
docs-site/src/cli/reference.md must not carry internal codes (REQ-*, F-###,
M#-W#, ADR-####) — meaningless to an end user, ships to GH-Pages.
- impl(a): forbidden_codes_in() scanner + scan_cli_reference_for_internal_codes()
  wired into `xtask check`, over the GENERATED reference.md. Regen alone keeps
  drift==0 but republishes a leak (how W5's slipped) — the scan gives the gate
  teeth. Left-word-boundary rule so UTF-8 etc. never false-positive.
- impl(b): swept all 14 leak sites / 8 clap `///` sources (cli.rs: REQ-MSG-5,
  REQ-KICK-1, ADR-0019, ADR-0022, ADR-0020; api/mod.rs: ADR-0021, REQ-EP-1/6,
  ADR-0008+REQ-TERM-4) to plain language, substance kept. The `// [impl->...]`
  line comments + fn/struct rustdoc `///` (not public help) keep their refs.
- unit: xtask docs_token_gate_tests — a planted token of each class FAILS
  (non-vacuous, with line numbers), a clean reference PASSES (UTF-8 safe).
- doc: DOCS-STRATEGY public-help rule + MANIFEST.md [adapter].version note.

Gates: cli 2 version + 2 proof-parse unit pass; xtask scan 2/2; reference.md
grep for all four code classes = 0; traceable-reqs check exit 0 (both REQs
+doc +impl +unit); xtask check OK (drift==0 + scan clean); clippy
--workspace --all-targets -D warnings clean.

Co-authored by: todlando
EOF
git log --oneline -1

Commit W6 (both REQs)


warning: in the working copy of 'docs-site/src/cli/reference.md', LF will be replaced by CRLF the next time Git touches it
7c377f0 feat(cli,xtask): W6 adapter version cmd + public-help no-internal-codes gate


W6 committed @7c377f0 (both REQs). Ping doyle to gate:


$OWL send doyle <<'EOF'
W6 ready for your gate — BOTH REQs @7c377f0 (branch v0.13.2-adapter-packaging). Last v0.13.2 wave.

MINTED (rule 3, this commit): REQ-ADAPTER-VERSION-CMD + REQ-DOCS-NO-INTERNAL-CODES.

1. REQ-ADAPTER-VERSION-CMD (base, corrected form):
   - AdapterCmd::Version{option} → cmd_adapter_version → resolve_option → println manifest.adapter.version (the EXISTING mandatory [adapter] field; NOT [strings].version, NOT get-string). Unresolvable → exit 1 (ADAPTER_VERSION_FAIL), like siblings.
   - unit: adapter_version_parses (parses to Version{option}); adapter_version_surfaces_declared_adapter_version (registered "cc" v3.1.4 → resolve_option exposes exactly [adapter].version, cmd exit 0; ghost → exit 1). unit-only, no int.

2. REQ-DOCS-NO-INTERNAL-CODES (the gate w/ teeth):
   - impl(a): forbidden_codes_in() pure scanner + scan_cli_reference_for_internal_codes() wired into `xtask check`, scanning the GENERATED reference.md for REQ-*/ADR-####/F-###/M#-W#. Left-word-boundary so UTF-8 / hyphenated prose never false-positive. This is the teeth: regen keeps drift==0 but republishes a leak (exactly how W5 slipped) — the scan catches it.
   - impl(b): SWEPT all 14 occ / 8 clap-/// sources. cli.rs: REQ-MSG-5, REQ-KICK-1, ADR-0019, ADR-0022, ADR-0020. api/mod.rs: ADR-0021 (--adapter), REQ-EP-1/6 (--type), ADR-0008+REQ-TERM-4 (digest-entry). Plain language, substance kept. The `// [impl->...]` line comments + fn/struct rustdoc /// (not public help) UNTOUCHED — keep their refs, as you specified.
   - unit: xtask docs_token_gate_tests — planted token of EACH class FAILS (non-vacuous, asserts line numbers); clean reference PASSES (UTF-8 boundary case).
   - doc: DOCS-STRATEGY public-help no-internal-codes rule + MANIFEST.md [adapter].version note.

VERIFIED (ran all):
- cli 2 version + 2 proof-parse unit pass; xtask scan 2/2.
- FULL reference.md grep for all 4 code classes = ZERO (down from 14).
- traceable-reqs check EXIT=0, both REQs +doc +impl +unit.
- xtask check OK (drift==0 AND scan clean — the new gate runs green on the swept tree).
- clippy --workspace --all-targets -D warnings EXIT=0.

NON-VACUITY for your re-run: the scan unit plants REQ-KICK-1/ADR-0019/F-011/M8-W5 and asserts each flagged + correct line; the clean-text test includes "UTF-8" and hyphenated words to prove no false-positive. To prove the gate has teeth end-to-end you can temporarily re-add a code to any clap /// + `xtask check` → it exits 1 naming reference.md:<line>.

Both halves green. This is the last scope — gate both, then deployah cuts v0.13.2 (counter 29; F-011 closed at W5, perri drops F-014 stopgap on W1 publish). Ping when verdict's in.
EOF

Send W6 gate request to doyle


➜ SENT:doyle


W6 SENT to doyle — both REQs @7c377f0.

**v0.13.2 build complete (pending W6 gate):**

| Wave | REQ | Commit | doyle |
|------|-----|--------|-------|
| W4 | ADAPTER-UPDATE-MESSAGE | 311b2dc | ✅ PASS |
| W5 | ADAPTER-PROOF-DIR-OVERRIDE | acf2387 + ce179a1 | ✅ PASS |
| W6a | ADAPTER-VERSION-CMD | 7c377f0 | ⏳ gating |
| W6b | DOCS-NO-INTERNAL-CODES | 7c377f0 | ⏳ gating |

W6 delivered: `spt adapter version <name>` (prints existing `[adapter].version`, the operator-corrected form — not `[strings].version`); + the docs-token gate with teeth (swept all 14 leak sites → 0, added `xtask check` scan over generated `reference.md`, non-vacuous unit). All gates green: traceable EXIT=0 (both +doc +impl +unit), xtask check OK, clippy clean, reference.md leak count 0.

Holding for doyle's W6 verdict. On PASS → deployah cuts **v0.13.2** (counter 29; F-011 closed at W5, perri drops F-014 stopgap on W1 publish).


<task-notification>
<task-id>bsp4y8a8u</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/6" id="7caa0078" type="msg" from="doyle">W6 GATE PASS — BOTH REQs @7c377f0. v0.13.2 build COMPLETE.

Re-ran every gate myself:
- xtask docs_token_gate unit 2/2 (planted REQ/ADR/F/M each flagged + line#; clean UTF-8/hyphen text passes — non-vacuous both ways)
- version cmd unit 2/2 (parses; &quot;cc&quot; v3.1.4 surfaces exactly [adapter].versio</EVENT-PART>
<EVENT-PART seq="2/6" id="7caa0078">n exit 0; ghost exit 1)
- reference.md grep ALL 4 classes (REQ-*/ADR-####/F-###/M#-W#) = ZERO (down from 14)
- traceable EXIT=0, both REQs +doc+impl+unit
- xtask check OK (drift==0 AND scan clean)
- clippy --workspace --all-targets -D warnings EXIT=0

TEETH PROVEN end-to-end (your suggested probe): planted &quot;ADR-9999&quot</EVENT-PART>
<EVENT-PART seq="3/6" id="7caa0078">; in the version clap ///, `xtask gen` (drift stays 0 — the exact W5-slip condition), then `xtask check` → EXIT 1, naming `reference.md:61` and `:172`. Then `git checkout` reverted, re-confirmed tree == 7c377f0, ADR-9999 gone, xtask check back to OK. The scan is the real teeth, not just a regen.

SPOT-CHECKED the sweep: api/mod.rs (A</EVENT-PART>
<EVENT-PART seq="4/6" id="7caa0078">DR-0021→&quot;Optional&quot;; REQ-EP-1/6 removed, open-type-tag explanation kept; ADR-0008+REQ-TERM-4→plain) — substance intact, codes gone. cmd_adapter_version is the correct thin form (resolve_option→println adapter.version→0; err→ADAPTER_VERSION_FAIL exit 1).

ALL v0.13.2 WAVES GATED: W1-W3 (you'd closed) + W4 + W5 + W6. G</EVENT-PART>
<EVENT-PART seq="5/6" id="7caa0078">O for deployah to cut v0.13.2.

Tell deployah the release-author checklist (from prior cuts): a build-only PR does NOT self-bump — deployah AUTHORS the bump commit: workspace.package.version → 0.13.2, CHANGELOG section (= the release-body), Cargo.lock first-party crate lines ONLY (targeted, not blanket — third-party collisions bit </EVENT-PART>
<EVENT-PART seq="6/6" id="7caa0078">us before). And the ci.yml ordering: push bump → CI green BOTH runners → THEN tag (never tag-early). I'll vet the CHANGELOG before publish (catch surface-coverage/overstatement like v0.8.0/v0.12.0). Ping me when the bump's drafted.</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>


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


doyle: **W6 GATE PASS — v0.13.2 build COMPLETE.** All waves W1–W6 gated. Teeth proven end-to-end (planted ADR-9999 → drift stayed 0 but `xtask check` EXIT 1 naming reference.md:61/:172 → reverted). GO for deployah.

Hand off to deployah with the GO + release-author checklist:


Check deployah reachability


SUBNET SPT_DEV
  (no endpoints)
SUBNET BIGNET
  (no endpoints)
ENDPOINTS:0
LOCAL (this node)
  (no local perches)


deployah offline — send will QUEUE (delivered on its next listen). Send the cut handoff:


$OWL send deployah <<'EOF'
GO — cut v0.13.2. doyle gated ALL waves (W1-W6); build COMPLETE. You author the bump.

BRANCH: v0.13.2-adapter-packaging  HEAD: 7c377f0  (counter 29 — VERIFY against spt-releases metadata at cut; the v0.13.1 stale-counter lesson)

WHAT SHIPPED (v0.13.2 = adapter packaging + live update):
- W1 REQ-ADAPTER-MULTIPLATFORM-SPT (ADR-0024): multi-platform .spt (shared manifest+strings root, per-triple binary subdirs; extract shared + current triple; legacy-flat back-compat).
- W2 REQ-ADAPTER-GH-TRANSPORT: gh_release transport https|gh|auto (private-repo path via gh CLI, no token custody) + add --release --gh/--https.
- W3 REQ-ADAPTER-LIVE-UPDATE (ADR-0025, keystone): daemon-coordinated live adapter update — stop resident binary (frees Windows lock) → CRC-only swap → in-memory manifest refresh → restart; endpoint never restarts. + the stop-path psyche reap hazards.
- W4 REQ-ADAPTER-UPDATE-MESSAGE @311b2dc: [update].message — markdown notice on APPLIED update only.
- W5 REQ-ADAPTER-PROOF-DIR-OVERRIDE @acf2387/ce179a1: digest-proof/translate-proof --dir/--manifest (proof a DEV/bare-file adapter unstaged; closes perri F-011).
- W6 @7c377f0: REQ-ADAPTER-VERSION-CMD (`spt adapter version <name>` → prints [adapter].version) + REQ-DOCS-NO-INTERNAL-CODES (swept 14 public-help leaks; new xtask check scan bans REQ-*/F-###/M#-W#/ADR-#### from generated reference.md).

RELEASE-AUTHOR CHECKLIST (doyle, from prior cuts — a build-only PR does NOT self-bump; YOU author the bump commit):
1. workspace.package.version → 0.13.2.
2. CHANGELOG section (= the release body). doyle VETS it before publish (he flags surface-coverage/overstatement like v0.8.0/v0.12.0) — keep it accurate to the 6 waves above, no overstatement.
3. Cargo.lock: first-party crate lines ONLY (targeted, NOT blanket — third-party version collisions bit us before).
4. ci.yml ORDERING: push bump → CI GREEN on BOTH runners → THEN tag. Never tag-early.

DOWNSTREAM on publish: ping perri (drops the claude-spt F-014 per-OS stopgap now W1 multi-platform .spt lands; F-011 already closed at W5).

Ping doyle when the bump commit is drafted (he vets CHANGELOG pre-publish). Ping me if any wave needs a fix during the cut.
EOF

Send v0.13.2 cut GO + checklist to deployah


➜ SENT:deployah


QUEUED to deployah (offline — delivers on next listen).

Recording the new docs gate — a gotcha that will bite future clap edits:


Write

---
name: public-help-no-internal-codes-gate
description: xtask check now bans internal codes (REQ-*/F-###/M#-W#/ADR-####) from clap /// public help; future CLI doc-comments must stay plain.
metadata:
  type: project
---

v0.13.2 W6 added **REQ-DOCS-NO-INTERNAL-CODES** (commit 7c377f0): a forbidden-token scan in `cargo run -p xtask -- check` (`forbidden_codes_in` + `scan_cli_reference_for_internal_codes` in crates/xtask/src/main.rs) over the GENERATED `docs-site/src/cli/reference.md`. It fails CI on any `REQ-*`, `F-###`, `M#-W#`, or `ADR-####` token.

**Why:** clap `///` doc-comments ARE public `--help` → regenerated into reference.md → ship to GH-Pages. Internal tracker/decision codes are meaningless to end users (operator ruling: ban even ADR). Regen alone keeps drift==0 but republishes a leak — the scan is the teeth.

**How to apply:** when adding/editing a clap `///` (enum variant or `#[arg]` field doc) in `cli.rs` or `api/mod.rs`, keep it plain — NO REQ/ADR/F/M codes (substance yes, codes no). After clap doc edits run `xtask gen` then `xtask check`. The scan is scoped to the generated reference, so `// [impl->REQ-*]` line comments and fn/struct rustdoc `///` (not public help) KEEP their cross-refs — only clap `///` is in scope. Left-word-boundary rule means `UTF-8`/hyphenated prose won't false-positive. Related: [[redirect-folded-req-seeds]].


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

---
name: public-help-no-internal-codes-gate
description: "xtask check now bans internal codes (REQ-*/F-###/M#-W#/ADR-####) from clap /// public help; future CLI doc-comments must stay plain."
metadata:
  node_type: memory
  type: project
  originSessionId: 1ced1cef-197e-4383-a870-ed2d15fe12eb
---

v0.13.2 W6 added **REQ-DOCS-NO-INTERNAL-CODES** (commit 7c377f0): a forbidden-token scan in `cargo run -p xtask -- check` (`forbidden_codes_in` + `scan_cli_reference_for_internal_codes` in crates/xtask/src/main.rs) over the GENERATED `docs-site/src/cli/reference.md`. It fails CI on any `REQ-*`, `F-###`, `M#-W#`, or `ADR-####` token.

**Why:** clap `///` doc-comments ARE public `--help` → regenerated into reference.md → ship to GH-Pages. Internal tracker/decision codes are meaningless to end users (operator ruling: ban even ADR). Regen alone keeps drift==0 but republishes a leak — the scan is the teeth.

**How to apply:** when adding/editing a clap `///` (enum variant or `#[arg]` field doc) in `cli.rs` or `api/mod.rs`, keep it plain — NO REQ/ADR/F/M codes (substance yes, codes no). After clap doc edits run `xtask gen` then `xtask check`. The scan is scoped to the generated reference, so `// [impl->REQ-*]` line comments and fn/struct rustdoc `///` (not public help) KEEP their cross-refs — only clap `///` is in scope. Left-word-boundary rule means `UTF-8`/hyphenated prose won't false-positive. Related: [[redirect-folded-req-seeds]].


1	# Memory index
2
3	- [Cross-machine test rig](cross-machine-test-rig.md) — enlyzeam (Windows, ssh key) for two-host network spikes + Tailscale-down gotcha; gravity-linux (Ubuntu, david/bigscreen pw-auth + askpass shim) as the Linux/forkpty build host.
4	- [CI traceability gate](ci-traceability-gate.md) — how CI installs traceable-reqs (TRACEABLE_REQS_TOKEN PAT + latest BigscreenVR release); the v0.1.0-stale-binary gotcha + the v0.1.1 fix; I have admin to cut releases.

# Memory index

- [Cross-machine test rig](cross-machine-test-rig.md) — enlyzeam (Windows, ssh key) for two-host network spikes + Tailscale-down gotcha; gravity-linux (Ubuntu, david/bigscreen pw-auth + askpass shim) as the Linux/forkpty build host.
- [CI traceability gate](ci-traceability-gate.md) — how CI installs traceable-reqs (TRACEABLE_REQS_TOKEN PAT + latest BigscreenVR release); the v0.1.0-stale-binary gotcha + the v0.1.1 fix; I have admin to cut releases.


Edit

- [CI traceability gate](ci-traceability-gate.md) — how CI installs traceable-reqs (TRACEABLE_REQS_TOKEN PAT + latest BigscreenVR release); the v0.1.0-stale-binary gotcha + the v0.1.1 fix; I have admin to cut releases.

- [CI traceability gate](ci-traceability-gate.md) — how CI installs traceable-reqs (TRACEABLE_REQS_TOKEN PAT + latest BigscreenVR release); the v0.1.0-stale-binary gotcha + the v0.1.1 fix; I have admin to cut releases.
- [Public-help no-internal-codes gate](public-help-no-internal-codes-gate.md) — xtask check bans REQ-*/F-###/M#-W#/ADR-#### from clap /// public help (scans generated reference.md); keep CLI doc-comments plain.


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

- [CI traceability gate](ci-traceability-gate.md) — how CI installs traceable-reqs (TRACEABLE_REQS_TOKEN PAT + latest BigscreenVR release); the v0.1.0-stale-binary gotcha + the v0.1.1 fix; I have admin to cut releases.
- [Public-help no-internal-codes gate](public-help-no-internal-codes-gate.md) — xtask check bans REQ-*/F-###/M#-W#/ADR-#### from clap /// public help (scans generated reference.md); keep CLI doc-comments plain.

# Memory index

- [Cross-machine test rig](cross-machine-test-rig.md) — enlyzeam (Windows, ssh key) for two-host network spikes + Tailscale-down gotcha; gravity-linux (Ubuntu, david/bigscreen pw-auth + askpass shim) as the Linux/forkpty build host.
- [CI traceability gate](ci-traceability-gate.md) — how CI installs traceable-reqs (TRACEABLE_REQS_TOKEN PAT + latest BigscreenVR release); the v0.1.0-stale-binary gotcha + the v0.1.1 fix; I have admin to cut releases.
- [Attractor build harness](attractor-build-harness.md) — attractor+pi/codex setup at ../attractor; codex model = openai-codex/gpt-5.5 (NOT the SPEC's gpt-5.3-codex); viable for bounded single-machine spt-core tasks (SPIKE-07b gix pilot).
- [Windows UAC binary-name 740](windows-uac-binary-name-740.md) — exe names containing update/setup/install/patch trigger UAC elevation (os error 740); name self-update artifacts + test bins to dodge it.
- [M4 resume state](m4-resume-state.md) — M4 (spt-net) in progress 2026-06-03; D0+D1 done (iroh =0.98.2 endpoint, identity-bound, relay policy, mDNS); spt-net = first async crate; next = D2 pairing.
- [Linux runner migration](linux-runner-migration.md) — replace gravity CI Linux runner with kitsubito (LAN Linux), not WSL (disk cost); deferred until after v0.1.1; retarget `gravity` host-label in ci/release/docs-publish workflows to a role label.
- [Delegate tests to spt-test-engineer](delegate-tests-to-spt-test-engineer.md) — write spt-core tests via the `spt-test-engineer` subagent (Agent tool subagent_type), not inline.
- [spt verification gates](spt-verification-gates.md) — before "done": workspace clippy (CI form), rebuild the real bin (not cargo test), verify terminal fixes live, keep the shared tree compilable.
- [Redirect folded REQ seeds](redirect-folded-req-seeds.md) — when folding a wave into existing reqs, retire/redirect the wave's minted seed in the SAME commit (doyle caught a dangling REQ-PICKER-UX-V013 @ W4).
- [Test subagent stalls on hanging test](test-subagent-stalls-on-hanging-test.md) — a test subagent's blocking until-loops stall forever on a hung test; take over (kill orphans, bisect timeout-wrapped) instead of waiting; Windows e2e suites also just run slow under load.
- [Owl send binary](owl-send-binary.md) — reach live agents via `$OWL send <target>` (stdin body), NOT `spt send` (returns NO_PERCH for live perches).
- [v0.13.0 rc-attach flood wedge](v013-rc-attach-flood-wedge.md) — the 3 inject_control_wedge gates fail on a REAL throughput bug (concurrent rc-view attach starves under sustained PTY output flood, serde-saturation / control-vs-data-plane); root-caused 2026-06-20 via gdb+SPT_WEDGE_TRACE on kitsubito, every lock hypothesis refuted; pending operator scope decision; two-phase CI split shipped.
- [Workspace bin-name collision](workspace-bin-name-collision.md) — Cargo [[bin]] names must be unique across ALL workspace crates (shared target/ → clobber + wrong CARGO_BIN_EXE); PR#28 gate-escape; verify cross-crate fixtures with the FULL matrix not -p onecrate; also `git add` fatals+stages-nothing on a stale pathspec.
- [cold_start_pump arg is io_timeout not connect](cold-start-pump-iotimeout-not-connect.md) — cold_start_pump's 3rd Duration = per-IPC-call read deadline (call_deadline), connect is unbounded; inject-wedge `(false,false)@2s` flake = request_attach net_open_stream ack starved past io_timeout; misread 3× (connect/watchdog/connect); fixed @45cc479 with SPT_ATTACH_IPC_DEADLINE_MS knob.
- [Daemon lib tests deadlock on live host](daemon-lib-tests-deadlock-on-live-host.md) — `spt-daemon --lib` lifecycle tests (seedmap/serveprobe/shellwake) deadlock when live spt-core daemons share the Windows host; auto-backgrounded cargo orphans `spt_daemon-*` test bins that wedge the target lock across away-gaps; unwedge by killing stale cargo+test bins; CI is the authority for that suite.

+- [Public-help no-internal-codes gate](public-help-no-internal-codes-gate.md) — xtask check bans REQ-*/F-###/M#-W#/ADR-#### from clap /// public help (scans generated reference.md); keep CLI doc-comments plain.


All W4–W6 work done, gated, handed off.

## v0.13.2 — build COMPLETE, all waves gated ✅

| Wave | REQ | Commit | doyle |
|------|-----|--------|-------|
| W4 | ADAPTER-UPDATE-MESSAGE | 311b2dc | ✅ |
| W5 | ADAPTER-PROOF-DIR-OVERRIDE | acf2387 + ce179a1 | ✅ |
| W6a | ADAPTER-VERSION-CMD | 7c377f0 | ✅ |
| W6b | DOCS-NO-INTERNAL-CODES | 7c377f0 | ✅ |

**This session (resumed mid-W4):** built W4 (post-update `[update].message`), W5 (`*-proof --dir/--manifest`, closes F-011) incl. doyle's help-leak scrub, W6 (`spt adapter version` + the public-help token gate — swept 14 leaks, added `xtask check` scan with teeth). doyle gated each, re-running every gate himself; W6 teeth proven end-to-end (planted ADR-9999 → drift 0 but check EXIT 1).

**Handoff:** GO + release-author checklist QUEUED to deployah (offline) — authors the bump (version→0.13.2, CHANGELOG=release body, Cargo.lock first-party lines only, push→both-runners-green→tag, never tag-early). doyle vets CHANGELOG pre-publish; perri drops F-014 stopgap on W1 publish.

**Recorded:** memory for the new docs-token gate so future clap-`///` edits stay plain.

Nothing left on my plate until deployah pings (a wave fix) or doyle/operator routes next work. Holding.


<task-notification>
<task-id>bsp4y8a8u</task-id>
<summary>Monitor event: "« spt event »"</summary>
<event><EVENT-PART seq="1/2" id="dddeffc4" type="msg" from="deployah">GO received — cutting v0.13.2 (adapter packaging + live update, W1-W6). Authoring bump + CHANGELOG from the 6 waves (user-facing, no internal codes, no overstatement). Will draft the bump commit then PING DOYLE to vet the CHANGELOG before publish, per your flow. Counter verified from metadata (expect 29). Throwaway</EVENT-PART>
<EVENT-PART seq="2/2" id="dddeffc4"> worktree off origin/main. Will ping perri + you + doyle on publish.</EVENT-PART></event>
</task-notification>


deployah acked — but flagged a risk: "throwaway worktree off **origin/main**." All of v0.13.2 (W1–W6) lives on branch `v0.13.2-adapter-packaging`, NOT main. Verify push/merge state before deployah cuts an empty release:


Bash

cd "C:/Users/decid/Documents/projects/spt-core" && echo "===branch + upstream===" && git status -sb | head -3 && echo "===is HEAD on origin?===" && git branch -r --contains 7c377f0 2>/dev/null | head && echo "(empty above = NOT pushed)" && echo "===does origin/main have the W-work? (W6 commit)===" && git branch -r --contains 7c377f0 --list 'origin/main' 2>/dev/null && echo "===main vs branch divergence===" && git rev-list --left-right --count origin/main...HEAD 2>/dev/null || echo "no origin/main ref locally"

Check push + merge state of v0.13.2 work


===branch + upstream===
## v0.13.2-adapter-packaging...origin/v0.13.2-adapter-packaging [ahead 4]
===is HEAD on origin?===
(empty above = NOT pushed)
===does origin/main have the W-work? (W6 commit)===
===main vs branch divergence===
0	19


Confirmed problem: branch is **ahead 4 unpushed** (W4–W6: 311b2dc, acf2387, ce179a1, 7c377f0) and **origin/main has ZERO of the 19 v0.13.2 commits**. deployah cutting "off origin/main" = empty release. Correct deployah + get the base decision:


$OWL send deployah <<'EOF'
HOLD THE BASE — do NOT cut off origin/main. It has ZERO of v0.13.2.

State (just checked):
- All v0.13.2 W1-W6 = 19 commits on branch v0.13.2-adapter-packaging, HEAD 7c377f0. origin/main is 19 BEHIND (0 left / 19 right). A worktree off origin/main would author a bump over an EMPTY release.
- My last 4 commits (W4 311b2dc, W5 acf2387 + ce179a1, W6 7c377f0) are NOT pushed yet — branch remote (origin/v0.13.2-adapter-packaging) is 4 behind HEAD.

Need before you base the bump:
1. I push the 4 commits to origin/v0.13.2-adapter-packaging (pending operator nod — asking now).
2. Base decision (operator's call): EITHER (a) you author the bump on the BRANCH HEAD 7c377f0 and cut off the branch, OR (b) merge branch -> main first, then cut off main. The bump MUST sit atop 7c377f0 either way.

Don't draft the bump against origin/main. Confirm you'll base on 7c377f0; I'll ping when pushed + relay the (a)/(b) decision. Counter 29 still correct.
EOF

Correct deployah's release base


AskUserQuestion

Question: v0.13.2 release base: origin/main has NONE of the W1–W6 work (19 commits on branch v0.13.2-adapter-packaging, HEAD 7c377f0; my last 4 unpushed). deployah was about to cut off origin/main = empty release. How should deployah base the cut?

Choices:
Push my 4 commits to origin/v0.13.2-adapter-packaging; deployah authors the bump on HEAD 7c377f0 and cuts off the branch. Matches the release-branch flow (push bump→CI both runners→tag). No main merge now.
Push, then merge v0.13.2-adapter-packaging→main (PR), deployah cuts off main. main becomes the release truth before tagging.
I tell deployah to wait; I push nothing. Use if you want to review the branch or sequence the merge yourself first.


Your questions have been answered: "v0.13.2 release base: origin/main has NONE of the W1–W6 work (19 commits on branch v0.13.2-adapter-packaging, HEAD 7c377f0; my last 4 unpushed). deployah was about to cut off origin/main = empty release. How should deployah base the cut?"="Push branch, merge to main first". You can now continue with these answers in mind.

Question: v0.13.2 release base: origin/main has NONE of the W1–W6 work (19 commits on branch v0.13.2-adapter-packaging, HEAD 7c377f0; my last 4 unpushed). deployah was about to cut off origin/main = empty release. How should deployah base the cut?

Choices:
Push my 4 commits to origin/v0.13.2-adapter-packaging; deployah authors the bump on HEAD 7c377f0 and cuts off the branch. Matches the release-branch flow (push bump→CI both runners→tag). No main merge now.
Push, then merge v0.13.2-adapter-packaging→main (PR), deployah cuts off main. main becomes the release truth before tagging.
I tell deployah to wait; I push nothing. Use if you want to review the branch or sequence the merge yourself first.


Operator: **push branch, merge to main first.** Pushing my 4 commits to the branch's upstream (fast-forward, ahead 4 / not behind):


Bash

cd "C:/Users/decid/Documents/projects/spt-core" && git push origin v0.13.2-adapter-packaging 2>&1 | tail -8 && echo "===verify HEAD on remote===" && git branch -r --contains 7c377f0

Push 4 commits to branch upstream


<owl_messages>
<owl_message from="deployah" priority="high">HOLD ACK — standing down, NOT basing off origin/main (confirmed: it has 0 of v0.13.2). Nothing pushed/tagged; tore down the premature trial worktree.

SHA reconcile on my side: 7c377f0 (your HEAD, all 19 W1-W6) IS reachable in my LOCAL object store (shared worktree repo on this box) but NOT on origin. origin/v0.13.2-adapter-packaging tip = 92ee788 (your 4 commits W4 311b2dc / W5 acf2387 / W5 ce179a1 / W6 7c377f0 unpushed). PR#29 head shows 92ee788, base origin/main. origin/main HEAD 7de5cfb now carries ADR-0023 (2f52457, operator reconciled it on).

USEFUL: I trial-merged 7c377f0 onto a fresh worktree off main(+ADR-0023) -> CLEAN, ZERO conflicts. So option (b) (merge branch -> main, then cut off main) is conflict-free; ADR-0023 + v0.13.2 don't collide. Either (a) or (b) works for me.

CONFIRMED: bump WILL sit atop 7c377f0 (all 19 commits), never origin/main. Standing by for (1) your push of the 4 commits to origin, (2) the operator's (a)/(b) base decision. Counter 29 holds (v0.13.1=28, verified). Ready on your ping.</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.


To https://github.com/SaberMage/spt-core.git
   92ee788..7c377f0  v0.13.2-adapter-packaging -> v0.13.2-adapter-packaging
===verify HEAD on remote===
  origin/v0.13.2-adapter-packaging


deployah high-priority msg acknowledged: stood down off main, trial-merge of 7c377f0 onto main(+ADR-0023) was CLEAN, counter 29 holds. I just pushed — 7c377f0 is now on origin. Operator chose **(b) merge→main, then cut off main**.

Ack deployah + check PR#29 + CI state before any merge:


$OWL send deployah <<'EOF'
PUSHED + DECISION. 7c377f0 (all 19, incl my 4: 311b2dc/acf2387/ce179a1/7c377f0) now on origin/v0.13.2-adapter-packaging — PR#29 head should reflect it. Operator chose (b): merge branch -> main, THEN you cut off main. Your clean trial-merge onto main(+ADR-0023 7de5cfb) confirms no collision — good.

Sequence: I'll land PR#29 -> main once CI is green on both runners (checking now; won't merge red/pending). When main carries 7c377f0, I ping you — you author the bump ON main (version->0.13.2, CHANGELOG=6 waves, Cargo.lock first-party lines only), push, CI green both runners, THEN tag. doyle vets CHANGELOG pre-publish. Counter 29 confirmed. Standby for my merge-done ping.
EOF

Ack deployah + relay (b) decision


cd "C:/Users/decid/Documents/projects/spt-core" && echo "===PR#29===" && gh pr view 29 --json number,headRefName,baseRefName,headRefOid,state,mergeable,mergeStateStatus 2>&1 | head -20 && echo "===CHECKS===" && gh pr checks 29 2>&1 | head -30

Inspect PR#29 + CI checks


===PR#29===
{"baseRefName":"main","headRefName":"v0.13.2-adapter-packaging","headRefOid":"7c377f0d18d39b2912d7722aec382221983b41b0","mergeStateStatus":"UNSTABLE","mergeable":"MERGEABLE","number":29,"state":"OPEN"}
===CHECKS===
n1-gate (self-hosted, Linux, kitsubito)	pending	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861323990
n1-gate (self-hosted, Windows, hfenduleam)	pending	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861323983
test (self-hosted, Linux, kitsubito)	pending	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861324020
test (self-hosted, Windows, hfenduleam)	pending	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861324002
traceability	pending	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861323982


PR#29 head = 7c377f0 (push landed), MERGEABLE but CI **pending** — 5 checks across both runners (n1-gate, test, traceability ×Linux/Windows). Won't merge until green. Watching CI in the background:


cd "C:/Users/decid/Documents/projects/spt-core" && gh pr checks 29 --watch --fail-fast 2>&1 | tail -30; echo "WATCH_EXIT=$?"

Watch PR#29 CI to completion


Command running in background with ID: b9mzn2n27. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\2730b458-50d2-48aa-b752-3ad22fefaa0b\tasks\b9mzn2n27.output. You will be notified when it completes. To check interim output, use Read on that file path.


Status — v0.13.2 cut in motion, paused on CI:

- **Pushed:** 7c377f0 (all 19 commits incl my W4–W6) → origin; PR#29 head updated, base main, **MERGEABLE** (deployah's trial-merge onto main+ADR-0023 was clean).
- **Operator decision:** (b) merge→main first, then deployah cuts off main. Relayed to deployah (acked, stood down off main).
- **CI running** on PR#29 — 5 checks both runners (n1-gate, test, traceability). Watching in background (`b9mzn2n27`); won't merge until green (doyle's rule).

**Next, automatic on CI-green:** merge PR#29→main → ping deployah → deployah authors bump on main (version→0.13.2, CHANGELOG=6 waves, Cargo.lock first-party only) → push → CI both runners → tag. doyle vets CHANGELOG pre-publish; perri pinged on publish (drops F-014 stopgap).

Holding for the CI watch to complete. If it goes red, I'll triage before any merge.


<task-notification>
<task-id>bsp4y8a8u</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/2" id="591ce26c" type="msg" from="deployah">Standby confirmed — (b) locked. Awaiting your merge-done ping (PR#29 -&gt; main, green both runners). On it I will: worktree off origin/main -&gt; bump 0.13.1-&gt;0.13.2 + Cargo.lock first-party-only + author CHANGELOG (6 waves, user-facing, no internal codes/overstatement) + gen -&gt; commit on main -&gt; PING DOY</EVENT-PART>
<EVENT-PART seq="2/2" id="591ce26c">LE to vet CHANGELOG -&gt; on his OK: push -&gt; CI green both -&gt; tag v0.13.2 -&gt; sign -&gt; publish --version 29 -&gt; ping perri+you+doyle.

Pre-drafting the CHANGELOG now from your W1-W6 brief so doyle's vet is fast. Idle until your ping.</EVENT-PART></event>
</task-notification>


deployah locked on (b), pre-drafting CHANGELOG, idle until my merge-done ping. Full publish chain confirmed (bump→commit on main→doyle vets CHANGELOG→push→CI green→tag→sign→publish v29→ping perri+me+doyle).

No action needed — holding for the CI watch (`b9mzn2n27`) to finish. On green I merge PR#29→main and ping deployah.


<task-notification>
<task-id>b9mzn2n27</task-id>
<tool-use-id>toolu_01Dyj5YnJigteQ5WE5j3gBkQ</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\2730b458-50d2-48aa-b752-3ad22fefaa0b\tasks\b9mzn2n27.output</output-file>
<status>completed</status>
<summary>Background command "Watch PR#29 CI to completion" completed (exit code 0)</summary>
</task-notification>


CI watch exited 0 — all green. Verify, then merge PR#29→main:


cd "C:/Users/decid/Documents/projects/spt-core" && gh pr checks 29 2>&1 | head -20 && echo "===mergestate===" && gh pr view 29 --json mergeable,mergeStateStatus,headRefOid -q '{mergeable,mergeStateStatus,headRefOid}'

Confirm all checks green + mergeable


twohost-a	skipping	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82862757851
twohost-b	skipping	0	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82862757893
n1-gate (self-hosted, Linux, kitsubito)	pass	1m14s	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861323990
n1-gate (self-hosted, Windows, hfenduleam)	pass	1m44s	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861323983
test (self-hosted, Linux, kitsubito)	pass	11m47s	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861324020
test (self-hosted, Windows, hfenduleam)	pass	10m52s	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861324002
traceability	pass	7s	https://github.com/SaberMage/spt-core/actions/runs/27997044794/job/82861323982
===mergestate===
{"headRefOid":"7c377f0d18d39b2912d7722aec382221983b41b0","mergeStateStatus":"CLEAN","mergeable":"MERGEABLE"}


All green (test both runners ~11m, n1-gate, traceability; twohost skipped/not-required), mergeStateStatus **CLEAN**. Merging PR#29→main (merge commit to preserve the W1–W6 wave history; keep branch):


cd "C:/Users/decid/Documents/projects/spt-core" && gh pr merge 29 --merge 2>&1 | tail -10 && echo "===main HEAD now===" && gh api repos/SaberMage/spt-core/commits/main -q '.sha + "  " + .commit.message' 2>&1 | head -3

Merge PR#29 to main (merge commit)


GraphQL: Pull Request is still a draft (mergePullRequest)
===main HEAD now===
7de5cfbfa185a83e1dff420716d1db0acbdbff8c  Merge branch 'main' of https://github.com/SaberMage/spt-core


PR#29 is a draft — mark ready, then merge:


cd "C:/Users/decid/Documents/projects/spt-core" && gh pr ready 29 2>&1 | tail -3 && sleep 2 && gh pr merge 29 --merge 2>&1 | tail -10 && echo "===main HEAD now===" && gh api repos/SaberMage/spt-core/commits/main -q '.sha + "  " + (.commit.message|split("\n")[0])' 2>&1 | head -1

Mark PR#29 ready + merge to main


✓ Pull request SaberMage/spt-core#29 is marked as "ready for review"
===main HEAD now===
a2667de56e41928a27e512290fb3faae1a2063d8  Merge pull request #29 from SaberMage/v0.13.2-adapter-packaging


Merged — main HEAD = a2667de (merge of PR#29). Verify the work landed + ping deployah:


cd "C:/Users/decid/Documents/projects/spt-core" && echo "===7c377f0 on main?===" && git fetch origin main -q 2>&1 && git branch -r --contains 7c377f0 --list 'origin/main' && echo "===main has W6 version cmd?===" && git show origin/main:traceable-reqs.toml 2>/dev/null | grep -c "REQ-ADAPTER-VERSION-CMD\|REQ-DOCS-NO-INTERNAL-CODES"

Confirm W1-W6 on origin/main


===7c377f0 on main?===
  origin/main
===main has W6 version cmd?===
2


Confirmed: 7c377f0 reachable from origin/main; both W6 REQs present. Ping deployah to author the bump:


$OWL send deployah <<'EOF'
MERGE DONE — GO author the bump on main.

PR#29 landed: marked ready (was draft — that's why initial merge bounced), merged with a MERGE COMMIT (preserves the W1-W6 wave history + co-author trailers). origin/main HEAD = a2667de (Merge pull request #29). 7c377f0 reachable from main; verified main carries both W6 REQs (REQ-ADAPTER-VERSION-CMD + REQ-DOCS-NO-INTERNAL-CODES) + all of W1-W5. PR#29 CI was GREEN both runners (test Linux 11m47s / Windows 10m52s, n1-gate both, traceability) before merge.

Your turn (off origin/main @a2667de):
- worktree off origin/main -> bump 0.13.1 -> 0.13.2 (workspace.package.version) + Cargo.lock first-party crate lines ONLY (targeted) + author CHANGELOG (6 waves W1-W6, user-facing, NO internal codes — the new xtask scan will FAIL the build if any REQ-*/ADR-####/F-###/M#-W# leaks into reference.md, but your CHANGELOG is separate; still keep it clean) + xtask gen -> commit on main -> PING DOYLE to vet CHANGELOG.
- On doyle OK: push -> CI green BOTH runners -> tag v0.13.2 -> sign -> publish --version 29 -> ping perri + me + doyle.

Counter 29 confirmed (v0.13.1=28). One heads-up: your bump commit adds the new xtask token-scan to `xtask check` in CI — your bump must keep reference.md clean (it already is on main; the bump shouldn't touch clap ///). Go.
EOF

Ping deployah: merge done, author bump


➜ SENT:deployah


Merge to main complete — handed off to deployah for the bump.

## Done on my side

- **W4–W6 built + gated** (doyle PASS each): 311b2dc, acf2387, ce179a1, 7c377f0
- **Pushed** all 4 to origin
- **PR#29 → main:** CI green both runners (test Linux 11m47s / Windows 10m52s, n1-gate, traceability), marked ready (was draft), **merged** with a merge commit — origin/main HEAD = **a2667de**, carries all W1–W6 (verified both W6 REQs present)
- **deployah pinged** to author the bump

## Now in deployah's hands

bump 0.13.1→0.13.2 + Cargo.lock first-party only + CHANGELOG (6 waves) → commit on main → **doyle vets CHANGELOG** → push → CI green both runners → tag v0.13.2 → sign → publish v29 → ping perri (drops F-014 stopgap) + me + doyle.

Holding for deployah's publish ping. Nothing actionable for me unless a wave fix surfaces.


<task-notification>
<task-id>bsp4y8a8u</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/9" id="c125316c" type="msg" from="doyle">NEW MILESTONE — v0.14.0 endpoint-creation-flow. Start now (v0.13.2 build is done + on main; deployah finishing the tag/publish in parallel — doesn't block you). Operator wants you moving.

BRANCH + PLAN already exist: `design/endpoint-creation-flow` has the full JIT (`V0.14.0-ENDPOINT-CREATION-FLOW-JIT.md`) + </EVENT-PART>
<EVENT-PART seq="2/9" id="c125316c">ADR-0026/0027 + the two REQs (REQ-RUN-MULTISUBNET-HOME, REQ-ENDPOINT-UNBOUND-ATTACH, currently doc-only). READ THE JIT — it's the authority; I'm relaying W1 + the prerequisite, but the file has every wave's files/gate.

STEP 0 — BINDING PREREQUISITE (do FIRST): the design branch is 21 behind main. Rebase/merge `design/endpoint-creati</EVENT-PART>
<EVENT-PART seq="3/9" id="c125316c">on-flow` onto current `origin/main` (@2bb9c8f = v0.13.2). This milestone BUILDS ON v0.13.2's broker `sessions` map (ADR-0025 W3a, per-endpoint endpoint/adapter/install_dir) — W2/W4/W5 read it as the &quot;is there a live session&quot; source of truth. The 2 design commits (JIT + ADR/REQ docs) rebase clean onto main. Push the rebased branch. </EVENT-PART>
<EVENT-PART seq="4/9" id="c125316c">Confirm traceable EXIT=0 after.

W1 (start here — foundational; W2 skeleton / W4 attach / W5 display all key on it):
REQ-ENDPOINT-UNBOUND-ATTACH, ADR-0027. Add `STATUS_UNBOUND` (liveness.rs:37, beside STATUS_ONLINE/OFFLINE).
- Lifecycle: spawn/skeleton-create → unbound; bind (cmd_bind establish-online) → online; broker sessio</EVENT-PART>
<EVENT-PART seq="5/9" id="c125316c">n death → offline via the EXISTING exit-waiter/reconcile (the B2/B5 dead-but-latched path — REUSE, no new teardown).
- Predicates: an `unbound` perch is ATTACHABLE (live broker session exists) but NOT message-addressable (no bound session_id). is_perch_alive / deliver-resolution STAY gated on online/bound. Add a NEW &quot;has a live ses</EVENT-PART>
<EVENT-PART seq="6/9" id="c125316c">sion&quot; predicate reading the broker sessions map — backs attach (W4) + display (W5).
- Files: spt-store/src/liveness.rs (constant + predicates); the reconcile/exit-waiter that stamps offline (livehost.rs / broker session-exit path); the info.json status writer.
- Gate: unit (transitions; unbound = attachable-not-addressable; reconc</EVENT-PART>
<EVENT-PART seq="7/9" id="c125316c">ile resolves a dead-session unbound → offline). doc = ADR-0027 + CONTEXT (already active). NO int yet (composed in W6). Activate REQ-ENDPOINT-UNBOUND-ATTACH impl+unit stages at W1 (rule 5; doc already active).

CADENCE (every wave): clippy --workspace --all-targets -D warnings; traceable standalone EXIT=0; the contended Windows host CA</EVENT-PART>
<EVENT-PART seq="8/9" id="c125316c">N'T run the lifecycle/daemon suite — CI is the authority, so push + get CI green BOTH runners per wave; I gate each before the next. Order: W1→W2(the multi-subnet UNBLOCK)→W3(MRU)→W4(attach-on-session)→W5(Unbound display)→W
...(truncated)</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>


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


New milestone **v0.14.0 endpoint-creation-flow**. doyle relayed W1 + binding STEP-0 prerequisite; the JIT on `design/endpoint-creation-flow` is authority. v0.13.2 build is done + on main (deployah finishing tag/publish in parallel — non-blocking).

Ack doyle + fetch/inspect state for STEP 0:


$OWL send doyle <<'EOF'
ACK v0.14.0 endpoint-creation-flow. Starting STEP 0 now (rebase design/endpoint-creation-flow onto origin/main @2bb9c8f = v0.13.2), then reading the JIT as authority before W1 (REQ-ENDPOINT-UNBOUND-ATTACH / STATUS_UNBOUND, ADR-0027). Note: v0.13.2 PR#29 merged to main @a2667de earlier; if 2bb9c8f is deployah's bump on top, good — I'll rebase onto whatever origin/main HEAD actually is and confirm. Context is high from the W4-W6 + release run — after STEP 0 lands clean I'll likely /commune + /self-clear to start W1 fresh on the rebased branch. Will ping per-wave for your gate.
EOF

Ack v0.14.0 milestone to doyle


➜ SENT:doyle


cd "C:/Users/decid/Documents/projects/spt-core" && git fetch origin -q 2>&1 && echo "===origin/main HEAD===" && git log origin/main --oneline -3 && echo "===design branch===" && git log origin/design/endpoint-creation-flow --oneline -4 2>&1 && echo "===behind count design vs main===" && git rev-list --left-right --count origin/main...origin/design/endpoint-creation-flow 2>&1

Inspect origin/main + design branch state


===origin/main HEAD===
2bb9c8f release: v0.13.2 — bump 0.13.1->0.13.2 + changelog + regen CLI reference
a2667de Merge pull request #29 from SaberMage/v0.13.2-adapter-packaging
7c377f0 feat(cli,xtask): W6 adapter version cmd + public-help no-internal-codes gate
===design branch===
7aab0fb docs: v0.14.0 endpoint-creation-flow JIT build plan
5fe1f0e docs: ADR-0026/0027 endpoint-creation-flow milestone (operator grill)
7de5cfb Merge branch 'main' of https://github.com/SaberMage/spt-core
bf1c724 Adjust instructions
===behind count design vs main===
21	2


State: origin/main @2bb9c8f = v0.13.2 release bump (deployah's bump landed on my merge — v0.13.2 is on main). Design branch = 2 doc commits (JIT + ADR-0026/0027), 21 behind. Execute STEP 0 rebase:


cd "C:/Users/decid/Documents/projects/spt-core" && git status --porcelain && echo "===checkout design===" && git checkout design/endpoint-creation-flow 2>&1 | tail -3 && echo "===rebase onto origin/main===" && git rebase origin/main 2>&1 | tail -15

Checkout design branch + rebase onto origin/main


<owl_messages>
<owl_message from="deployah" priority="high">v0.13.2 PUBLISHED ✓ counter 29. doyle CHANGELOG vet PASS (no amendments). Chain clean: merge a2667de -> bump 2bb9c8f -> CI green both runners (+ W6 token-scan) -> tag v0.13.2 -> signed -> public. linux e270734f... / windows 44c90902... ; update-set v29. Pinged perri (F-014 stopgap can drop). https://github.com/SaberMage/spt-releases/releases/tag/v0.13.2 . Clean cut — thanks for the merge.</owl_message>
<owl_message from="doyle" priority="high">ACK — your read of main is right: a2667de = PR#29 merge, 2bb9c8f = deployah's v0.13.2 bump on top (origin/main HEAD). Rebase onto origin/main HEAD as you said; the ADR-0025 W3a sessions map you need is in there.

GREEN on the /commune + /self-clear after STEP 0 lands clean — smart given your context load from the W4-W6 + release run. Land+push the rebase first (confirm traceable EXIT=0 on the rebased branch), THEN clear and start W1 fresh. W1 is self-contained (STATUS_UNBOUND primitive in liveness.rs + lifecycle/predicates; the JIT has the full files/gate) so a fresh context picks it up clean.

One guard for the rebase: your 2 design commits (JIT + ADR-0026/0027/REQ docs) touch traceable-reqs.toml — v0.13.2's W4/W5/W6 ALSO added REQs there (UPDATE-MESSAGE, PROOF-DIR-OVERRIDE, VERSION-CMD, DOCS-NO-INTERNAL-CODES). Expect a traceable-reqs.toml conflict on rebase; resolve = keep BOTH (union — append your 2 v0.14 REQs after the v0.13.2 ones, don't drop either block). Re-run traceable check after to confirm EXIT=0. Ping if anything else surfaces. Go.</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.


===checkout design===
Your branch is up to date with 'origin/design/endpoint-creation-flow'.
Switched to branch 'design/endpoint-creation-flow'
===rebase onto origin/main===
Auto-merging CONTEXT.md
Auto-merging traceable-reqs.toml
CONFLICT (content): Merge conflict in traceable-reqs.toml
Rebasing (1/2)
error: could not apply 5fe1f0e... docs: ADR-0026/0027 endpoint-creation-flow milestone (operator grill)
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 5fe1f0e... docs: ADR-0026/0027 endpoint-creation-flow milestone (operator grill)


Both acknowledged: **v0.13.2 PUBLISHED ✓** (counter 29, doyle CHANGELOG vet PASS, perri pinged — clean cut). And doyle's rebase guard: the predicted traceable-reqs.toml conflict — resolve = **union, keep both blocks**. Read the conflict:


cd "C:/Users/decid/Documents/projects/spt-core" && grep -n "^<<<<<<<\|^=======\|^>>>>>>>" traceable-reqs.toml

Locate conflict markers in traceable-reqs.toml


1334:<<<<<<< HEAD
1372:=======
1383:>>>>>>> 5fe1f0e (docs: ADR-0026/0027 endpoint-creation-flow milestone (operator grill))


1326	required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff KEEPS its eager subscribe(prior.session_id, prior.next_seq) [fix #1 REVERTED — load-bearing resume] AND seeds session_cursors.insert(prior.session_id, prior.next_seq); (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, whose INITIAL-BATCH loop returns when controller_epoch != its snapshot (read UNDER send.lock(), atomically with write_frame) — the live recv loop is NOT gated (delivers a superseded controller's terminal Displaced, ends on tx-drop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::subscribe_with resets session_cursors.insert(session_id, from_seq) when in resume mode (non-empty map), shared by attach/attach_as — the attach_as(0) re-subscribe re-delivers seq K to the operator viewport (the kitsubito operator-stream boundary fix; reset moved out of attach() into subscribe_with). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic stream reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + resubscribes for resume. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."
1327
1328	# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
1329	[[requirements]]
1330	id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"
1331	title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"
1332	required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.
1333
1334	<<<<<<< HEAD
1335	# ── v0.13.2 adapter packaging + live-update grill (operator-driven, 2026-06-22; doyle captured the design) ──
1336	# doc stage ACTIVE for the two ADR-backed REQs (the ADR IS the doc evidence); impl/unit/int deferred to the
1337	# v0.13.2 build milestone (rule 5). The three additive REQs stay fully inactive until built.
1338	[[requirements]]
1339	id = "REQ-ADAPTER-MULTIPLATFORM-SPT"
1340	title = "A `.spt` adapter archive may pack multiple platforms in one signed asset: shared `manifest.toml` + `strings/` at the root, role binaries under per-Rust-target-triple subdirectories (ADR-0016 triple vocabulary, e.g. `x86_64-pc-windows-msvc/`); install/update extracts the shared root plus ONLY `current_platform()`'s triple subdir, flattened into `install_dir` so flat `<install_dir>/<program>` resolution (REQ-INSTALL-11) is unchanged. Name stays `adapter.spt` (plain-tar or gzip, `--asset` optional default); one whole-archive Ed25519 signature over the fat archive (REQ-UPD-9 single-artifact verify). A legacy flat archive (no triple subdirs) extracts as today (free back-compat); a multi-platform archive sets `min_spt_core_version >= 0.13.2` (forward-compat gate, readable before extract); a multi-platform archive missing the recipient's triple -> typed `NoArtifactForPlatform`, never a silent no-op. Large adapters may still split per-platform (single-triple archives via `--asset`, or ADR-0016 update-set machinery). (ADR-0024, v0.13.2)"
1341	required_stages = ["doc", "impl", "unit", "int"]  # doc = ADR-0024 + CONTEXT "adapter packaging & live update". impl/unit/int activated at the v0.13.2 W1 build.
1342	[[requirements]]
1343	id = "REQ-ADAPTER-LIVE-UPDATE"
1344	title = "An adapter update is live and daemon-coordinated (the adapter analog of brain self-update, ADR-0004): for an endpoint with a running RESIDENT adapter binary (today the `[message-idle-translation-binary]`), the CLI keeps fetch+verify and hands the APPLY to the daemon over IPC, which per affected endpoint (1) STOPS the resident binary -> releases the OS file lock (fixes the Windows 'Access denied (os error 5)' overwrite failure), (2) swaps on disk ONLY files whose CRC differs from the staged archive (unchanged files + their still-running binaries untouched), (3) RE-CLONES the new on-disk manifest into the running `BrainLifecycle` (the in-memory manifest is cached at bringup and otherwise goes stale -> binaries+manifest back on the same page), (4) RESTARTS the resident binary from the new files. An endpoint NOT running -> CLI swaps directly (no lock, no cache). Only the resident class is cycled; ephemeral adapter binaries (Psyche loop, `[digest]` extractor, `[session.*]` runners, hooks) self-heal on next spawn and are excluded. The daemon keeps a per-endpoint registry of resident adapter children. (ADR-0025, v0.13.2)"
1345	required_stages = ["doc", "impl", "unit", "int"]  # doc=ADR-0025+amendment+CONTEXT. impl/unit from W3a-W3d. int = W3e no-mocks keystone (live_adapt_translation_swap_e2e: broker apply swaps a locked translation binary, brain-parity).
1346	[[requirements]]
1347	id = "REQ-HAZARD-STOP-PATH-PSYCHE-ORPHAN-REAP"
1348	title = "Endpoint-stop and brain-death reconcile MUST reap a brain-less perch's orphan detached Psyche via the cmdline-scoped guard (`psyche_orphan_should_reap`) — the handle-reap (`LiveSet::stop_host`, REQ-HAZARD-UNHOST-PSYCHE-REAP) CANNOT, because the owning brain is gone (its `psyche_child` handle died with it), and the brain-start scoped-reap (REQ-HAZARD-BRAIN-RESTART-PSYCHE-DUP) never fires for a perch being STOPPED rather than re-hosted. So the live-host calls the scoped reap after `stop_host` at the reconcile stop-side AND in `confirm_residency_or_unhost`. Preserves fail-safe-decline (pid-alive AND exe-basename==psyche-program AND cmdline contains `<id>-psyche`; any unreadable signal DECLINES — a missed dup is bounded, a wrong-kill is catastrophic). This is the orphan-leak half of the perri F-010xF-015 field bug (the unsupervised install-dir Psyche that locked an update); the other half is the psyche own-copy (ADR-0025 amendment). (v0.13.2 W3 (a))"
1349	required_stages = ["doc", "impl", "unit", "int"]  # doc = KNOWN-HAZARDS 7.22 + ADR-0025 amendment. impl/unit from W3 (a). int = W3e (live_adapt_psyche_lock_e2e: endpoint stop reaps a brain-less orphan psyche).
1350	[[requirements]]
1351	id = "REQ-ADAPTER-UPDATE-MESSAGE"
1352	title = "An adapter manifest may declare `[update].message` — a plain (multi-line) human notice surfaced to stdout, markdown-rendered (the v0.13.0 helpfmt prose path), ONLY when `spt adapter update` actually APPLIES an update (version changed), not on a no-op. Read from the newly-installed manifest; avenue-agnostic (gh_release/delegated/file_pull). No `{key}` substitution. Use: an adapter telling the operator a post-update action, e.g. spt-claude-code's \"run `/reload-plugins` in any ongoing sessions\". (v0.13.2)"
1353	required_stages = ["doc", "impl", "unit"]  # v0.13.2 W4. doc = MANIFEST.md [update].message + CONTEXT. impl = Update.message field + cmd_adapter_update post-apply notice. unit = adapter_update_notice render/absent. No int (CLI stdout, unit-covered) per the W4 gate.
1354	[[requirements]]
1355	id = "REQ-ADAPTER-GH-TRANSPORT"
1356	title = "The `gh_release` avenue (and `spt adapter add --release`) gain a fetch `transport`: `https` (current reqwest direct, public), `gh` (shell the pre-authorized `gh` CLI — the private-repo path; `gh` honors OAuth and `GH_TOKEN`, so spt custodies no token), or `auto` (default: prefer `gh` when installed+authed, else HTTPS). `--gh`/`--https` force it on `add`. Additive over the existing fetch path; verify->extract->register downstream is unchanged. (v0.13.2)"
1357	required_stages = ["doc", "impl", "unit"]  # doc = MANIFEST.md + CONTEXT transport option. impl/unit activated at the v0.13.2 W2 build. int = HITL (real private repo + gh auth), unit-covered not int.
1358	[[requirements]]
1359	id = "REQ-ADAPTER-PROOF-DIR-OVERRIDE"
1360	title = "The author-time proof commands (`spt adapter digest-proof`, `spt adapter translate-proof`) gain a `--dir <path>` / `--manifest <file>` override so an author proofs a DEV binary against an on-disk manifest+install dir WITHOUT staging a full extracted GhReleaseManaged install (mirrors digest-proof's `--sample` pointing straight at a file). Fixes perri F-011: a bare-file-added gh_release adapter currently can't be resolved by the *-proof commands ('manifest is not present yet at <dir>'); un-stales the bare-file digest-proof int. (perri F-011, v0.13.x DX)"
1361	required_stages = ["doc", "impl", "unit", "int"]  # v0.13.2 W5. doc = harness-contract patterns + MANIFEST.md proof note. impl = resolve_proof_target + the two --dir/--manifest flags. unit = resolve_proof_target resolution contract. int = translate_proof.rs override proofs an UNregistered on-disk install (real binary).
1362
1363	[[requirements]]
1364	id = "REQ-ADAPTER-VERSION-CMD"
1365	title = "`spt adapter version <name>` prints a registered adapter's declared version — the EXISTING mandatory `[adapter].version` manifest field (manifest.rs already requires it; NOT a `[strings].version`, NOT `get-string`, no second version source). A new `AdapterCmd::Version{option}` resolves the option's merged view via `registry::resolve_option` like the sibling adapter subcommands and prints `manifest.adapter.version`; an unresolvable option errors (exit 1) the same way. (v0.13.2 W6)"
1366	required_stages = ["doc", "impl", "unit"]  # v0.13.2 W6 base. doc = harness-contract adapter-cmd note. impl = the Version arm + cmd_adapter_version resolve+print. unit = parse + behavior (registered prints [adapter].version exit 0; unregistered exit 1). No int (read-only CLI print, unit-covered).
1367
1368	[[requirements]]
1369	id = "REQ-DOCS-NO-INTERNAL-CODES"
1370	title = "Public CLI --help (the clap `///` doc-comments) and the generated `docs-site/src/cli/reference.md` MUST NOT contain internal tracker/decision codes — `REQ-*`, `F-###`, `M#-W#`, `ADR-####`. They are meaningless to an end user reading --help and ship to GH-Pages. A CI-gated scan (the `xtask check` docs gate) fails on any such token in the GENERATED reference.md (which by construction contains only clap help, so rustdoc `///` on fns/structs is OUT of scope and keeps its REQ/ADR cross-refs). Substance is kept; codes are rewritten to plain language. (v0.13.2 W6)"
1371	required_stages = ["doc", "impl", "unit"]  # v0.13.2 W6. doc = DOCS-STRATEGY public-help no-internal-codes rule. impl = (a) the forbidden-token scan in xtask check over reference.md; (b) the sweep of all existing clap-/// leak sites. unit = xtask test: a planted forbidden token FAILS the scan, a clean reference PASSES (non-vacuous).
1372	=======
1373	# ── Endpoint-creation-flow milestone (operator grill 2026-06-22; ADR-0026/0027) ──
1374	# doc stage ACTIVE (the ADR IS the doc evidence); impl/unit/int activate at the milestone build (rule 5).
1375	[[requirements]]
1376	id = "REQ-RUN-MULTISUBNET-HOME"
1377	title = "`spt endpoint run` resolves the home subnet at the skeleton-create step and pre-creates the skeleton perch carrying it, so the harness `bind` inherits home via establish_perch's immutable prior-branch (no hook change, no env injection). Resolution: sole-subnet auto; multi-subnet + no --subnet + NON-interactive terminal -> refuse early with MRU-ordered --subnet guidance (never the silent 25s online-timeout); multi-subnet + no --subnet + INTERACTIVE -> print proposed config (id/project/adapter[:profile]/home=MRU-default) + 'Ok to proceed? Y/n', n -> --subnet guidance; --subnet overrides + validates membership. MRU = ordered move-to-front LISTs at two levels (per-project + always-updated node-global fallback). Home stays IMMUTABLE (ADR-0010). Fixes the LATENT multi-subnet bringup gap (perri, not a regression — HOME_REFUSED established >=0.11.0; exposed by the node crossing 1->2 subnets). (ADR-0026)"
1378	required_stages = ["doc"]  # doc = ADR-0026 + CONTEXT home-subnet. impl/unit/int activate at the endpoint-creation-flow milestone build. int MUST run on a multi-subnet node (single-subnet auto-homes + hides the gap).
1379	[[requirements]]
1380	id = "REQ-ENDPOINT-UNBOUND-ATTACH"
1381	title = "An spt-hosted endpoint is ATTACHABLE between spawn and bind: gate the attach on the broker SESSION being attachable (session+PTY+OutputLog exist at spawn, before bind), not on perch STATUS_ONLINE (bind). cmd_endpoint_run + `spt rc <id>` attach to a live broker session regardless of perch status (headless bringups too; lets an operator clear a bind-gating prompt) -- replaces await_endpoint_online; preserves REQ-HAZARD-RC-ATTACH-ONLINE-RACE's 'no attach before a session' intent at the earlier session-exists point; source = the broker sessions map (ADR-0025 W3a); local-only. New on-disk status STATUS_UNBOUND (spawn->unbound, bind->online, death->offline); lifecycle reuses the existing exit-waiter/reconcile (session death->offline); unbound is attachable but NOT message-addressable (messaging stays online/bound-gated). EpDisplay gains Unbound = HOLLOW (+ hollow-controlled variant) -- amber=HarnessOnly is taken + means not-controllable (the opposite of attachable). (ADR-0027)"
1382	required_stages = ["doc"]  # doc = ADR-0027 + CONTEXT "Unbound endpoint". impl/unit/int activate at the milestone build.
1383	>>>>>>> 5fe1f0e (docs: ADR-0026/0027 endpoint-creation-flow milestone (operator grill))
1384

required_stages = ["doc", "impl", "unit", "int"]  # ACTIVATED v0.13.0 P1c (todlando, the last v0.13.0 ship-blocker — pre-existing flaky resume race that gates green-both-runners; doyle root-caused + designed, doyle gates). doc = KNOWN-HAZARDS entry (the reorder + the single-live-writer-per-connection invariant + the two compounding defects) + CONTEXT note. impl = (1) Brain::handoff KEEPS its eager subscribe(prior.session_id, prior.next_seq) [fix #1 REVERTED — load-bearing resume] AND seeds session_cursors.insert(prior.session_id, prior.next_seq); (2) OutputLog.controller_epoch -> Arc<AtomicU64>, become_controller passes the new epoch + Arc::clone into controller_writer, whose INITIAL-BATCH loop returns when controller_epoch != its snapshot (read UNDER send.lock(), atomically with write_frame) — the live recv loop is NOT gated (delivers a superseded controller's terminal Displaced, ends on tx-drop), become_controller/mark_controller_gone/the ControllerJob epoch read switch to atomic load/fetch_add; (3) Brain::subscribe_with resets session_cursors.insert(session_id, from_seq) when in resume mode (non-empty map), shared by attach/attach_as — the attach_as(0) re-subscribe re-delivers seq K to the operator viewport (the kitsubito operator-stream boundary fix; reset moved out of attach() into subscribe_with). unit = epoch-gated controller_writer: a superseded writer (epoch bumped) writes NOTHING from its initial batch (real broker socket, two become_controller on one connection -> only the latest writer's monotonic stream reaches the wire) + handoff seeds session_cursors (session_cursor(sid) == prior.next_seq) + resubscribes for resume. int = the keystone: deterministically force two become_controller-on-one-connection (handoff-then-reserve ordering) on a real broker+brain, NO mocks -> PRE-FIX the wire reorders (got seq 1 want 0 / gap or byte-drop) -> POST-FIX the wire stays monotonic + byte-exact + the session stays live; PLUS attach_survives_target_brain_restart_exactly_once green (doyle runs it 20x isolated single-threaded timeout-wrapped on Linux/kitsubito — the deterministic RED-on-revert carrier). Full seam sweep (attach/broker/resume/brain_swap/inject_control_wedge — the shared W1 controller-writer model). clippy/traceable/docs-drift."

# ── P1c follow-up SEED (doyle proposed, todlando gated, doyle concurred 2026-06-20): the structural per-connection-floor guard — inactive, activate-don't-pre-fail ──
[[requirements]]
id = "REQ-HAZARD-CONTROLLER-RETAKE-FLOOR"
title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"
required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

<<<<<<< HEAD
# ── v0.13.2 adapter packaging + live-update grill (operator-driven, 2026-06-22; doyle captured the design) ──
# doc stage ACTIVE for the two ADR-backed REQs (the ADR IS the doc evidence); impl/unit/int deferred to the
# v0.13.2 build milestone (rule 5). The three additive REQs stay fully inactive until built.
[[requirements]]
id = "REQ-ADAPTER-MULTIPLATFORM-SPT"
title = "A `.spt` adapter archive may pack multiple platforms in one signed asset: shared `manifest.toml` + `strings/` at the root, role binaries under per-Rust-target-triple subdirectories (ADR-0016 triple vocabulary, e.g. `x86_64-pc-windows-msvc/`); install/update extracts the shared root plus ONLY `current_platform()`'s triple subdir, flattened into `install_dir` so flat `<install_dir>/<program>` resolution (REQ-INSTALL-11) is unchanged. Name stays `adapter.spt` (plain-tar or gzip, `--asset` optional default); one whole-archive Ed25519 signature over the fat archive (REQ-UPD-9 single-artifact verify). A legacy flat archive (no triple subdirs) extracts as today (free back-compat); a multi-platform archive sets `min_spt_core_version >= 0.13.2` (forward-compat gate, readable before extract); a multi-platform archive missing the recipient's triple -> typed `NoArtifactForPlatform`, never a silent no-op. Large adapters may still split per-platform (single-triple archives via `--asset`, or ADR-0016 update-set machinery). (ADR-0024, v0.13.2)"
required_stages = ["doc", "impl", "unit", "int"]  # doc = ADR-0024 + CONTEXT "adapter packaging & live update". impl/unit/int activated at the v0.13.2 W1 build.
[[requirements]]
id = "REQ-ADAPTER-LIVE-UPDATE"
title = "An adapter update is live and daemon-coordinated (the adapter analog of brain self-update, ADR-0004): for an endpoint with a running RESIDENT adapter binary (today the `[message-idle-translation-binary]`), the CLI keeps fetch+verify and hands the APPLY to the daemon over IPC, which per affected endpoint (1) STOPS the resident binary -> releases the OS file lock (fixes the Windows 'Access denied (os error 5)' overwrite failure), (2) swaps on disk ONLY files whose CRC differs from the staged archive (unchanged files + their still-running binaries untouched), (3) RE-CLONES the new on-disk manifest into the running `BrainLifecycle` (the in-memory manifest is cached at bringup and otherwise goes stale -> binaries+manifest back on the same page), (4) RESTARTS the resident binary from the new files. An endpoint NOT running -> CLI swaps directly (no lock, no cache). Only the resident class is cycled; ephemeral adapter binaries (Psyche loop, `[digest]` extractor, `[session.*]` runners, hooks) self-heal on next spawn and are excluded. The daemon keeps a per-endpoint registry of resident adapter children. (ADR-0025, v0.13.2)"
required_stages = ["doc", "impl", "unit", "int"]  # doc=ADR-0025+amendment+CONTEXT. impl/unit from W3a-W3d. int = W3e no-mocks keystone (live_adapt_translation_swap_e2e: broker apply swaps a locked translation binary, brain-parity).
[[requirements]]
id = "REQ-HAZARD-STOP-PATH-PSYCHE-ORPHAN-REAP"
title = "Endpoint-stop and brain-death reconcile MUST reap a brain-less perch's orphan detached Psyche via the cmdline-scoped guard (`psyche_orphan_should_reap`) — the handle-reap (`LiveSet::stop_host`, REQ-HAZARD-UNHOST-PSYCHE-REAP) CANNOT, because the owning brain is gone (its `psyche_child` handle died with it), and the brain-start scoped-reap (REQ-HAZARD-BRAIN-RESTART-PSYCHE-DUP) never fires for a perch being STOPPED rather than re-hosted. So the live-host calls the scoped reap after `stop_host` at the reconcile stop-side AND in `confirm_residency_or_unhost`. Preserves fail-safe-decline (pid-alive AND exe-basename==psyche-program AND cmdline contains `<id>-psyche`; any unreadable signal DECLINES — a missed dup is bounded, a wrong-kill is catastrophic). This is the orphan-leak half of the perri F-010xF-015 field bug (the unsupervised install-dir Psyche that locked an update); the other half is the psyche own-copy (ADR-0025 amendment). (v0.13.2 W3 (a))"
required_stages = ["doc", "impl", "unit", "int"]  # doc = KNOWN-HAZARDS 7.22 + ADR-0025 amendment. impl/unit from W3 (a). int = W3e (live_adapt_psyche_lock_e2e: endpoint stop reaps a brain-less orphan psyche).
[[requirements]]
id = "REQ-ADAPTER-UPDATE-MESSAGE"
title = "An adapter manifest may declare `[update].message` — a plain (multi-line) human notice surfaced to stdout, markdown-rendered (the v0.13.0 helpfmt prose path), ONLY when `spt adapter update` actually APPLIES an update (version changed), not on a no-op. Read from the newly-installed manifest; avenue-agnostic (gh_release/delegated/file_pull). No `{key}` substitution. Use: an adapter telling the operator a post-update action, e.g. spt-claude-code's \"run `/reload-plugins` in any ongoing sessions\". (v0.13.2)"
required_stages = ["doc", "impl", "unit"]  # v0.13.2 W4. doc = MANIFEST.md [update].message + CONTEXT. impl = Update.message field + cmd_adapter_update post-apply notice. unit = adapter_update_notice render/absent. No int (CLI stdout, unit-covered) per the W4 gate.
[[requirements]]
id = "REQ-ADAPTER-GH-TRANSPORT"
title = "The `gh_release` avenue (and `spt adapter add --release`) gain a fetch `transport`: `https` (current reqwest direct, public), `gh` (shell the pre-authorized `gh` CLI — the private-repo path; `gh` honors OAuth and `GH_TOKEN`, so spt custodies no token), or `auto` (default: prefer `gh` when installed+authed, else HTTPS). `--gh`/`--https` force it on `add`. Additive over the existing fetch path; verify->extract->register downstream is unchanged. (v0.13.2)"
required_stages = ["doc", "impl", "unit"]  # doc = MANIFEST.md + CONTEXT transport option. impl/unit activated at the v0.13.2 W2 build. int = HITL (real private repo + gh auth), unit-covered not int.
[[requirements]]
id = "REQ-ADAPTER-PROOF-DIR-OVERRIDE"
title = "The author-time proof commands (`spt adapter digest-proof`, `spt adapter translate-proof`) gain a `--dir <path>` / `--manifest <file>` override so an author proofs a DEV binary against an on-disk manifest+install dir WITHOUT staging a full extracted GhReleaseManaged install (mirrors digest-proof's `--sample` pointing straight at a file). Fixes perri F-011: a bare-file-added gh_release adapter currently can't be resolved by the *-proof commands ('manifest is not present yet at <dir>'); un-stales the bare-file digest-proof int. (perri F-011, v0.13.x DX)"
required_stages = ["doc", "impl", "unit", "int"]  # v0.13.2 W5. doc = harness-contract patterns + MANIFEST.md proof note. impl = resolve_proof_target + the two --dir/--manifest flags. unit = resolve_proof_target resolution contract. int = translate_proof.rs override proofs an UNregistered on-disk install (real binary).

[[requirements]]
id = "REQ-ADAPTER-VERSION-CMD"
title = "`spt adapter version <name>` prints a registered adapter's declared version — the EXISTING mandatory `[adapter].version` manifest field (manifest.rs already requires it; NOT a `[strings].version`, NOT `get-string`, no second version source). A new `AdapterCmd::Version{option}` resolves the option's merged view via `registry::resolve_option` like the sibling adapter subcommands and prints `manifest.adapter.version`; an unresolvable option errors (exit 1) the same way. (v0.13.2 W6)"
required_stages = ["doc", "impl", "unit"]  # v0.13.2 W6 base. doc = harness-contract adapter-cmd note. impl = the Version arm + cmd_adapter_version resolve+print. unit = parse + behavior (registered prints [adapter].version exit 0; unregistered exit 1). No int (read-only CLI print, unit-covered).

[[requirements]]
id = "REQ-DOCS-NO-INTERNAL-CODES"
title = "Public CLI --help (the clap `///` doc-comments) and the generated `docs-site/src/cli/reference.md` MUST NOT contain internal tracker/decision codes — `REQ-*`, `F-###`, `M#-W#`, `ADR-####`. They are meaningless to an end user reading --help and ship to GH-Pages. A CI-gated scan (the `xtask check` docs gate) fails on any such token in the GENERATED reference.md (which by construction contains only clap help, so rustdoc `///` on fns/structs is OUT of scope and keeps its REQ/ADR cross-refs). Substance is kept; codes are rewritten to plain language. (v0.13.2 W6)"
required_stages = ["doc", "impl", "unit"]  # v0.13.2 W6. doc = DOCS-STRATEGY public-help no-internal-codes rule. impl = (a) the forbidden-token scan in xtask check over reference.md; (b) the sweep of all existing clap-/// leak sites. unit = xtask test: a planted forbidden token FAILS the scan, a clean reference PASSES (non-vacuous).
=======
# ── Endpoint-creation-flow milestone (operator grill 2026-06-22; ADR-0026/0027) ──
# doc stage ACTIVE (the ADR IS the doc evidence); impl/unit/int activate at the milestone build (rule 5).
[[requirements]]
id = "REQ-RUN-MULTISUBNET-HOME"
title = "`spt endpoint run` resolves the home subnet at the skeleton-create step and pre-creates the skeleton perch carrying it, so the harness `bind` inherits home via establish_perch's immutable prior-branch (no hook change, no env injection). Resolution: sole-subnet auto; multi-subnet + no --subnet + NON-interactive terminal -> refuse early with MRU-ordered --subnet guidance (never the silent 25s online-timeout); multi-subnet + no --subnet + INTERACTIVE -> print proposed config (id/project/adapter[:profile]/home=MRU-default) + 'Ok to proceed? Y/n', n -> --subnet guidance; --subnet overrides + validates membership. MRU = ordered move-to-front LISTs at two levels (per-project + always-updated node-global fallback). Home stays IMMUTABLE (ADR-0010). Fixes the LATENT multi-subnet bringup gap (perri, not a regression — HOME_REFUSED established >=0.11.0; exposed by the node crossing 1->2 subnets). (ADR-0026)"
required_stages = ["doc"]  # doc = ADR-0026 + CONTEXT home-subnet. impl/unit/int activate at the endpoint-creation-flow milestone build. int MUST run on a multi-subnet node (single-subnet auto-homes + hides the gap).
[[requirements]]
id = "REQ-ENDPOINT-UNBOUND-ATTACH"
title = "An spt-hosted endpoint is ATTACHABLE between spawn and bind: gate the attach on the broker SESSION being attachable (session+PTY+OutputLog exist at spawn, before bind), not on perch STATUS_ONLINE (bind). cmd_endpoint_run + `spt rc <id>` attach to a live broker session regardless of perch status (headless bringups too; lets an operator clear a bind-gating prompt) -- replaces await_endpoint_online; preserves REQ-HAZARD-RC-ATTACH-ONLINE-RACE's 'no attach before a session' intent at the earlier session-exists point; source = the broker sessions map (ADR-0025 W3a); local-only. New on-disk status STATUS_UNBOUND (spawn->unbound, bind->online, death->offline); lifecycle reuses the existing exit-waiter/reconcile (session death->offline); unbound is attachable but NOT message-addressable (messaging stays online/bound-gated). EpDisplay gains Unbound = HOLLOW (+ hollow-controlled variant) -- amber=HarnessOnly is taken + means not-controllable (the opposite of attachable). (ADR-0027)"
required_stages = ["doc"]  # doc = ADR-0027 + CONTEXT "Unbound endpoint". impl/unit/int activate at the milestone build.
>>>>>>> 5fe1f0e (docs: ADR-0026/0027 endpoint-creation-flow milestone (operator grill))


Clean union conflict — v0.13.2 block (HEAD) + v0.14.0 block (design). Resolve = keep both, drop markers:


Edit

<<<<<<< HEAD
# ── v0.13.2 adapter packaging + live-update grill (operator-driven, 2026-06-22; doyle captured the design) ──

# ── v0.13.2 adapter packaging + live-update grill (operator-driven, 2026-06-22; doyle captured the design) ──


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)

<<<<<<< HEAD
# ── v0.13.2 adapter packaging + live-update grill (operator-driven, 2026-06-22; doyle captured the design) ──

title = "`become_controller` should STRUCTURALLY refuse a controller re-take whose `from_seq` falls below the connection's already-delivered contiguous floor — making the P1c reorder invariant un-reintroducible by a future caller, not just removed at the one caller. ROOT/SCOPE (doyle proposed, P1c gate dialogue): P1c fixes REQ-HAZARD-CONTROLLER-WRITER-REORDER three ways (handoff single-take + epoch-gate-under-lock + session_cursors seed), removing the one decreasing-floor double-take and bounding any other to already-committed-only. A self-enforcing broker guard would refuse the bad SHAPE outright. BLOCKER: the obvious predicate (`from_seq >= delivered_through`) is UNSAFE because `delivered_through` is SESSION-WIDE (the `Arc<AtomicU64>` on `OutputLog`, shared by all controllers/viewers, advanced monotonic-MAX; `resume_seq` reads it) — a normal fresh-operator `from_seq=0` attach to a producing session legitimately sits below it (full ring replay + consumer dedup-below/snap-above), and monotonic-MAX can't distinguish the hazard (a `seq1`-without-`seq0` write reads as `2`). The structurally-correct guard needs a NEW per-connection contiguous-sent cursor (the true highest-contiguous seq this socket has received) that does not exist today; the guard then refuses a re-take below THAT. Bigger than P1c; no live gap (P1c fully fixes the actual bug). Mint/refine stages when the per-connection cursor is built. (v0.13.0 follow-up, post-ship)"

required_stages = []  # SEED ONLY (rule 5, activate-don't-pre-fail). The shipped fix is covered by REQ-HAZARD-CONTROLLER-WRITER-REORDER; this is the deferred STRUCTURAL guard (DEFERRED.md row). Activate with real stages only when a milestone adds the per-connection contiguous-sent cursor + the become_controller refuse-decreasing-floor guard. Until then NO evidence is owed.

# doc stage ACTIVE for the two ADR-backed REQs (the ADR IS the doc evidence); impl/unit/int deferred to the

# v0.13.2 build milestone (rule 5). The three additive REQs stay fully inactive until built.