# v0.16.0 — adapter-update arc + CLI/UX — build JIT

> Next spt-core minor (after v0.15.0 / counter 34). **Design (binding):**
> `docs/design/v0.16.0-update-arc-and-cli.md` + **ADR-0029**. REQs seeded in `traceable-reqs.toml`
> (cluster A doc-ratified by ADR-0029; everything else `required_stages = []`). Grill 2026-06-25.
> Pairs with downstream **claude-spt adapter v0.8.0** (perri) that consumes these — its
> `min_spt_core_version` bumps to 0.16.0 once shipped.

## Build invariants (every wave)

- **Activate per wave, int at the final wave** (rule 5 / [[traceable-per-wave-activation]]). Tag
  evidence in the same commit (`[impl->]`/`[unit->]`/`[int->]` on real code/tests).
- **Gate each wave:** `cargo nextest` (spt-daemon + spt + spt-live; NEVER bare `cargo test` on Win —
  env races = false flakes), `cargo clippy --workspace` (CI denies warnings workspace-wide),
  `traceable-reqs`/`xtask check`, `xtask gen` (reference.md drift) where a CLI surface changed.
- **Pre-kill the orphan `target/debug/spt.exe`** (scoped to `$GITHUB_WORKSPACE/target` / PID — never
  machine-wide on the shared runner) before xtask/full-daemon builds, or it locks the rebuild +
  races handoff::brain_restart. ([[no-machinewide-killon-shared-runner]])
- **CLI/manifest change → `xtask gen` + no internal codes in clap `///`** ([[cli-command-docs-drift]],
  [[public-docs-version-not-milestone]]).

## Waves

### W1 — manifest/runtime foundations (REQ-MANIFEST-SUBST + REQ-TRANSLATE-COMMAND)
- `{adapter_dir}` (= registry record `source_dir`) + `{adapter_name}` substitution keys; wire into
  the existing command-substitution path (the `[session.*]`/`[digest]` substitution site).
- Lazy substitution **inside `[strings]` values** at `get-string` read time, adapter-static keys
  only — parity with file-backed-string lazy resolution. `get-string` impl + `[strings]` resolver.
- `[message-idle-translation-binary]`: add `command` (Option) beside `path`; deprecate `path`
  (parse + registration warn); refuse both-set; `read_translation_path` → `read_translation_command`
  (`spt-daemon/src/translation.rs:242` spawn; manifest struct `spt-runtime/src/manifest.rs:410`).
  Protocol unchanged.
- Activate REQ-MANIFEST-SUBST + REQ-TRANSLATE-COMMAND **impl+unit**.

### W2 — composite update (REQ-ADAPTER-UPDATE-POST)
- `[update.post] = {command, self_verifies}` parse (`spt-runtime/src/manifest.rs:441` Update struct).
- Run after pull+re-register in `adapter update` (`spt/src/cli.rs:6720`); **unconditional**; compose
  the stdin JSON seam (`adapter_applied, adapter_name, profile_name, version, previous_version,
  adapter_dir`); arbitrate the notice from stdout (custom supersedes / sentinel fires
  `[update].message` / empty nothing) vs `adapter_update_notice()` (`cli.rs:6715`); exit orthogonal;
  failure-isolated (no rollback); no-post-step + post-fail fallbacks.
- Activate **impl+unit+int** (int = delegated post-step fires + supersede/sentinel/empty +
  unconditional-on-noop + fail-isolated). Sweep-all path (`adapter update` no-name) runs post per
  gh_release adapter.

### W3 — CLI batch (REQ-SEND-REPLYTO-REMOVE + REQ-RUN-EMPTY-CREATE)
- Hard-remove `--reply-to` (`cli.rs:71` flag, `cmd_send` `cli.rs:3609` is_reply/REPLIED → always
  SENT/QUEUED, `cli.rs:1155` dispatch, HOW_TO_SEND `cli.rs:5899`); amend REQ-DOCS-6 title.
- Empty-scope create: `PickerModel::new` (`spt/src/picker/model.rs:453`) opens `Screen::CreateAdapter`
  when `gather_endpoints()` (`picker/data.rs:85`) is empty.
- Activate both **impl+unit**. `xtask gen` (reply-to leaves reference.md).

### W4 — global `--json` (REQ-CLI-JSON)
- Global `--json` (clap `global=true`) honored by the read/status set (list/whoami, daemon status,
  subnet status/show-code, endpoint description/role, adapter list/version, notif/grant/access/shell
  list, how-to). Shared `print_json()`; **explicit output DTOs** per command (NOT internal structs);
  add `Serialize` where missing (`SubnetStatusRow`, `NodeRow`, grant/access/notif/shell rows).
- **Coverage test** asserting every command in the set emits valid JSON under `--json`.
- Activate **impl+unit**. Model on the existing `endpoint digest --json` (`digesthub.rs:360`).

### W5 — digest cursor (REQ-DIGEST-CURSOR)
- `--last <N>` (turns), per-entry **stable source-derived `seq`** (transcript record index across the
  session ledger / `digest.log` index — stable across re-projection, NOT window-position), `--after
  <seq>`, `partial:true` for in-flight entries, per-entry `ts` where present. Thread seq through
  `project_endpoint_digest` (`spt-daemon/src/digest.rs:134`) + the `Turn`/`DigestEntry` JSON
  (`spt-term/src/digest.rs:44`, `projection.rs:185`).
- **Doc-guidance** (MANIFEST.md + integration-checklist): extractor/`api digest-entry` must mark
  delivered user-facing messages as turn-opening `input`.
- Activate **impl+unit**.

### W6 — rc identity, int, docs, release
- REQ-RC-IDENTITY: reserved top status row via `DECSTBM` (shrink reported rows by 1), right-aligned
  `SUBNET : ID @ NODE`, cyan; re-assert on alt-screen/`DECSTBM`-reset/resize (scan output like
  `mouse_scanner`, `rc.rs:53`); resolve subnet/node/id at attach (`rc.rs:760` run_attach_inner) and
  thread into `pump` (`rc.rs:1006`); subnet = home/primary, "local" if none; **no window title**.
  Activate **impl+unit+int**.
- **Activate int stages** for W2/W6 (and any deferred) at the fold; doyle gates the matrix ×3 both
  runners.
- **CARRY from W4 (doyle gate):** REQ-CLI-JSON shipped with a PARSE-coverage unit (every read/status
  cmd captures `--json`) + DTO-build asserts — but no runtime proof a handler actually *branches* to
  `print_json`. Add a **`--json` runtime-emit smoke** over the daemon-reachable read/status subset
  (whoami / how-to / adapter version / daemon status against the live test daemon already stood up
  here) — assert each emits parseable JSON, not human text. Activate **REQ-CLI-JSON int** for it.
  Closes the capture-flag-but-doesn't-route drift the W4 unit can't catch.
- **Public docs ride the release** (VERSION numbers, no internal codes): `MANIFEST.md`
  (`[update.post]` + stdin seam, translation `command`, strings substitution), `reference.md` via
  `xtask gen`, gh-pages integration-checklist + messaging + digest via `docs-publish.yml`.
- **Release:** bump-in-PR ([[release-standard-bump-in-pr]]), doyle CHANGELOG-vet, sign FRESH,
  cross-check counter **35** monotonic from published metadata, publish. Then perri lands
  **claude-spt adapter v0.8.0** consuming these (min_spt_core → 0.16.0) + real-CC validation.

## Coordination
- perri has the resolved cluster-A contract (sent 2026-06-25); their UNIFY-CONSOLIDATE prep
  (consolidated `claude-spt` binary: `digest`/`psyche`/`post-update`/`translate`/`hook` subcommands)
  consumes W1–W2. deployah cuts the release on doyle's vet.
- Shared working tree with doyle's own design edits / perri — coordinate `traceable-reqs.toml`
  boundaries; restore in-flight design out when needed.
