---
name: v0230-published
description: "v0.23.0 PUBLISHED — counter 43, F-028 RUNTRUTH, first RC-WINDOW-HOLD release (perri 4 RC ints pre-flip)"
metadata: 
  node_type: memory
  type: project
  originSessionId: 26d7f056-5571-45c0-8cc3-2452d759ae26
---

v0.23.0 PUBLISHED — counter 43 @289bdcd (PR#48 merge commit; parent2 = doyle-gated 5341b97, tree IDENTICAL; NO [twohost], single-node wave). F-028 RUNTRUTH: honest run/resume/shutdown of agent sessions.

**Cut flow (clean):** published counter confirmed==42 BEFORE cut → reused existing wip PR#48 (f028→main) as the release PR: pushed bump commit on gated head @5005a75 (Cargo.toml 0.22.0→0.23.0 workspace.package [crates inherit via version.workspace=true] + 11 first-party Cargo.lock lines [no third-party @0.22.0; darling family already 0.23.0, untouched] + CHANGELOG [0.23.0]), retitled "release: v0.23.0 — RUNTRUTH (F-028)", removed draft, marked ready → doyle CHANGELOG-gate found 2 under-scoped user-facing surfaces → CHANGELOG-only amend @5341b97 → CI both legs green + doyle per-sha worktree GATE-PASS (1531/1531) → merge → tag v0.23.0 @289bdcd → release.yml 28686433086 draft → **RC-WINDOW HOLD** → doyle RC-GREEN → release-publish --version 43.

**RC-WINDOW PROTOCOL (first use, binding):** after assets upload to tag but BEFORE Latest flip, HELD + pinged doyle → she pulled draft binary (checksum-verified vs SHA256SUMS), staged for perri (isolated SPT_HOME, box's live 0.22.0 untouched) → perri 4 RC ints ALL PASS (INT-1 env-scrub, INT-2 resume-UUID argv, INT-3 crashloop backstop [persisted psyche_host_error stamp], INT-4 /clear boundary-race CLEAN — B6 stays open, zero regression) → doyle RC-GREEN cleared flip. Only doyle's RC-GREEN/FLIP-BLOCKED moves publisher during hold.

**SETTLE-CHECK GREEN attempt 1** — served update-set version==43 product==0.23.0, no stale window. draft=false, published 2026-07-03T23:31:44Z. HASHES: linux `2fb6a4a770240418…` / windows `7a0b468f2d0869b6…`.

**doyle CHANGELOG-gate catch:** W5 hardening pair (7a1ebb9) is NOT purely internal — 2 user-visible surfaces leaked, binding scope rule (every user-facing surface vPREV..vNEW) wanted them: (1) `spt daemon status` now WARNS on stale legacy at-logon task (`daemon run` no `--detached`) + re-register guidance (boot_hint string); (2) piped `spt daemon run` output now discarded by design (stderr FILE_TYPE_PIPE → null std handles; console+`2>file` still captured). My diff-analysis agent had dismissed both as internal — LESSON: "hardening" commits can still ship user-facing messages/behavior; scope by observable surface not by commit intent. [[changelog-scope-vs-commit-range]]

**POST-PUBLISH terminology fix (operator catch, 2nd instance of the class after v0.22.0 PR#47):** three v0.23.0 bullets said "companion" for the **Psyche** — not spt terminology (every prior CHANGELOG entry + CONTEXT.md use Psyche). Fixed: PR#49 (repo CHANGELOG) + `gh release edit v0.23.0 -R SaberMage/spt-releases --notes-file` (live notes body — the release object lives on spt-releases, NOT spt-core; `gh release view` on spt-core = "release not found"). **CHANGELOG-gate rule going forward: vet WORDING against CONTEXT.md glossary terms, not just scope** — novel synonyms for established terms are a red.

**GOTCHAS:** Git Bash no `jq` — Monitor loops must use `gh --jq` or grep, NOT jq (silent no-op). release-publish flip is a SINGLE op (sign+upload+flip) — RC-window hold = pause at draft BEFORE running release-publish, not a flag. Ledger: [[v0121-published]] / [[v0220-published]].

**doyle addendum (RC-int mechanics for next window):** (1) `spt update fetch` AT THE HOLD serves the OLD counter (Latest unflipped = the point) — candidate acquisition is a direct draft download, needs repo auth (doyle stages locally for perri). (2) Iso-stack recipe verified: `SPT_HOME` env var (perch.rs) + ALL daemon sockets home-tagged (`spt-daemon-broker-<home_tag>.sock`) → iso daemon coexists with live daemon zero-contact; boots netless fine; UNDOCUMENTED on public surface = docs-gap seed. (3) psyche_host_error + cooldown are FILE-STAMP + IN-MEMORY — stderr greps structurally blind; `LIVEHOST_PSYCHE_THRASH` is the sole log token of the whole C3(b) trip (stamp+un-host+reap+cooldown). (4) Pre-existing-bug hunt ints (INT-4 class) get pre-ruled verdict semantics — reproduction = root pinned ≠ flip-blocker; only new-regression evidence blocks. (5) Published bytes verified BYTE-IDENTICAL to the RC-tested candidate (same sha256) — keep asserting this. Post-release: **adapter claude-spt v0.13.0 CUT + doyle-GATED same day** (Latest @1c61ffe; C3(a) thrash guard in field; min_spt_core floor 0.23.0; env_remove intact; verified against published asset). Still open: B6 root (REQ open, boundary-race capture rig proven), B2 absent-guard live leg (daemon-bounce auto-resume rig, nice-to-have), perri F-027 (trust-seam + account-root, sharpened by 2 field observations), todlando backlog seeds (churn-resilient pump / rest_state void / eviction live-session leg / D1/D2), SPT_HOME isolation docs-gap.
