---
name: v0160-w1-manifest-runtime
description: "v0.16.0 update-arc W1 (manifest/runtime foundations) COMMITTED @1590857, awaiting doyle gate"
metadata: 
  node_type: memory
  type: project
  originSessionId: d5288847-4461-4e16-a07f-147390fe3db8
---

v0.16.0 = adapter-update arc + CLI/UX. Branch `v0.16.0-update-arc` (off main 18d5045). Binding design: ADR-0029 (resolve-not-execute) + docs/design/v0.16.0-update-arc-and-cli.md + V0.16.0-UPDATE-ARC-AND-CLI-JIT.md (6 waves). doyle gates, todlando executes, perri lands claude-spt v0.8.0 downstream (min_spt_core→0.16.0). Counter at release = 35.

**W1 COMMITTED @1590857 (todlando), AWAITING doyle gate.** REQ-MANIFEST-SUBST + REQ-TRANSLATE-COMMAND activated impl+unit (int defers W6). Three parts:
1. `{adapter_dir}`(=record source_dir)/`{adapter_name}` subst keys: catalog += adapter_dir; `runtime::inject_adapter_keys` (entry/or_insert, no-clobber) at session subst sites (ManifestRuntime::command_for + new `with_adapter_name`; harnesshost::prepare_harness_spawn now takes install_dir) + [digest] extractor keys (activity_spanned gains adapter_name).
2. Lazy `runtime::subst_adapter_static` (adapter-static keys only, leaves session/unknown `{..}` intact, never errors) applied in registry::get_string to literal AND file-backed values (recurses tables/arrays). Parity w/ file-backed lazy resolve.
3. `[message-idle-translation-binary]` `command`(Option) beside deprecated `path`(now Option). Validate refuses both-set/empty; neither=no binary. `read_translation_path`→`read_translation_command` + `resolve_translation_argv` carry argv (program+args) END-TO-END: msg.rs SpawnReq `Option<Vec<String>>` (IPC wire), broker build_translation/respawn, translation.rs spawn(&[String]), harnesshost PreparedSpawn, cli translate-proof. Spawn/stdin protocol UNCHANGED. Manifest schema re-blessed (SPT_BLESS=1).

**OPEN RATIFY (sent doyle):** translation `command` subst scoped to adapter-static keys ONLY, not session `{key}` as REQ title says. Rationale: session/endpoint ctx flows via stdin Init protocol; live-update respawn site (read_translation_command) has NO session ctx → a `{id}` command would MissingKey→spool there. Symmetric+safe both spawn sites. doyle to amend title OR direct full session-fill at harnesshost site only.

Gates ALL PASS: nextest spt-runtime 76 / spt-daemon 485 / spt-live 63 / spt 294; clippy --workspace 0; traceable 306 complete/0 findings; xtask gen no-drift; translate_proof + live_adapt e2e green.

GOTCHAs hit: (a) schema snapshot test `checked_in_schema_is_current` → re-bless `SPT_BLESS=1 cargo test -p spt-runtime` after ANY manifest derive change; (b) clippy "doc list item without indentation" on a `/// + args` doc line → avoid leading `+`/`-` after wrap; (c) `{adapter_name}` in an assert! message = format placeholder → escape `{{}}`. Pre-kill workspace-scoped spt.exe before each nextest (shared runner).

**W1 GATED GREEN @1590857** (doyle). Ratify confirmed: translation command subst = adapter-static (doyle amended title+ADR-0029§2+design @fedc6ba — no code change). 

**W2 COMMITTED @6db75f9, AWAITING doyle gate.** REQ-ADAPTER-UPDATE-POST impl+unit+int. `UpdatePost{command,self_verifies}` on Update (manifest.rs); validate command-non-empty. cmd_adapter_update (cli.rs) restructured: version no-op FALLS THROUGH (no continue) → post-step runs unconditionally after pull+re-register. `run_update_post_step` composes stdin seam {adapter_applied,adapter_name,profile_name=null,version,previous_version,adapter_dir} + pure `post_step_notice` arbitration (custom supersedes / sentinel `!!update-message!!` fires [update].message / empty nothing); exit orthogonal; post-fail=loud+overall-nonzero+fallback-to-applied-message; fail-isolated (pull never rolled back). {adapter_dir} subst, program vs install_dir. post install_dir = dest on apply else record.source_dir. Tests: manifest update_post_sub_table + cli post_step_notice_arbitration + int adapter_post_step (REAL `spt adapter update` w/ post_step_fixture bin, SPT_TEST_GH_LATEST network seam). Schema re-blessed.
3 OPEN NOTES sent doyle: (1) sentinel token `!!update-message!!` — perri emits verbatim, ratify; (2) self_verifies parsed-but-inert in W2 (spec=unconditional run) — confirm attestation-only; (3) added test-only SPT_TEST_GH_LATEST seam.

**GOTCHA (binding):** a manifest-less test/fixture exe whose NAME contains "update" trips Windows installer-detection → forced UAC elevation → `os error 740` "requires elevation" at test-list time → CI can't run it. Name test bins WITHOUT update/install/setup/patch (used `post_step`). Also: spt-daemon+spt-live full-suite has an intermittent load-TIMEOUT (seedmap-class starvation on shared box w/ live agents up) — passes isolated + `--no-fail-fast`; rerunnable, not a code defect.

**W3 COMMITTED @a0f8979, AWAITING doyle gate.** REQ-SEND-REPLYTO-REMOVE + REQ-RUN-EMPTY-CREATE impl+unit. Hard-removed --reply-to (clap flag + cmd_send is_reply/REPLIED→always SENT/QUEUED/WAN; target now REQUIRED positional). Dropped --reply-to from both how-to topics + corrected docs-site prose (overview+quickstart/messaging) + REQ-DOCS-6 comment + reference.md regen. Empty-scope: PickerModel::new → Screen::CreateAdapter when endpoints.is_empty() (subnet-only still picks). Tests: send_reply_to_flag_is_removed_and_target_required, empty_scope_opens_create, how-to no-reply-to asserts, kind_routes populated. impl tag on removal = Cmd::Send target field (traceable needs evidence even for a removal). Gates: spt 297 / spt-daemon+spt-live 548 / clippy 0 / traceable 306-0 / xtask gen. NOTE sent doyle: I corrected 2 docs-site PROSE pages (his W6 turf normally) — offered to revert if he wants to own all prose at W6.

**W4 COMMITTED @6550106, AWAITING doyle gate.** REQ-CLI-JSON impl+unit. Global `--json` (clap global=true on Cli) + shared `print_json()` (pretty) + EXPLICIT per-command `*Json` DTOs across 14 read/status cmds (endpoint list/whoami=self+subnets+local, daemon status, subnet status/show-code, endpoint description/role, adapter list/version, notif/grant/access/shell list, how-to); internal structs NEVER serialized verbatim (copied into DTOs). endpoint digest folded onto global flag. Coverage test `every_read_status_command_emits_valid_json` (parse-coverage: all 14 capture --json). GOTCHA: serde-derive was NOT a direct dep of spt crate (only serde_json) — added `serde={features=["derive"]}` to spt/Cargo.toml. Delegated 14-handler impl to a general-purpose subagent w/ exact DTO specs (foreground review after: verified no internal-struct-Serialize, endpoint_list branch faithful). Gates: spt 298 / spt-daemon+spt-live 548 / clippy --workspace 0 / traceable 306-0 / xtask gen --json×96. doyle ruled prose-boundary W3.

**W4 GATED @6550106** (doyle). 2 adjudications: serde dep accepted; parse-coverage accepted BUT carries a W6 int — REQ-CLI-JSON int = `--json` runtime-emit smoke over the daemon-reachable subset (whoami/how-to/adapter-version/daemon-status vs the live test daemon), assert parseable-JSON-not-human-text (doyle recorded in JIT W6 @703e825). REQ-CLI-JSON int activates W6.

**W5 IN PROGRESS (REQ-DIGEST-CURSOR), BLOCKED on doyle seq-ruling.** Scope: `--last <N>` turns + per-entry source-derived `seq` + `--after <seq>` + in-flight `partial:true` + per-entry `ts`, threaded through project_endpoint_digest (spt-daemon/digest.rs:134) + Turn/DigestEntry JSON (spt-term/digest.rs + projection.rs project_timeline:321). doc-guidance (extractor classifies delivered msgs as turn-opening input) DEFERRED to W6 docs-ride (doyle confirmed). Activate impl+unit (doc-stage W6). **OPEN Q to doyle (sent):** seq BASIS — A1 composite(session_id+line) / A2 cumulative-from-K-span (not roll-stable) / A3 cumulative-across-full-sessions.log-ledger (my lean: single int + roll-stable); GRANULARITY per-entry + ToolSprint seq=last-collapsed-record-idx; PARTIAL turn-level (last open turn partial, prior committed). CRUX = seq stability across re-projection (extractor re-runs per projection, spans last-K-sessions → naive counter renumbers on session-roll). Pipeline: extract_digest re-runs extractor per session (lines NOT persisted w/ idx) + digest.log context merged by ts → project_timeline windows to last N turns.

**(W4 DONE):** REQ-CLI-JSON — global `--json` (clap global=true) honored by 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 to SubnetStatusRow/NodeRow/grant/access/notif/shell rows). Coverage test every cmd emits valid JSON. Model on existing `endpoint digest --json` (digesthub.rs:360). Activate impl+unit. Ledger [[v0150-published]].
