---
name: v0294-0295-turnend-confirm-and-canonical-root
description: "2026-08-24 SHIPPED v0.29.4 (#17 turn-end tag confirms park + surface next hook) and v0.29.5 (#19 alt-root post-update FAILED — CC validates the shared store's installLocation lexically; fix = drive the CLI at the junction target's canonical root). Both field-verified."
metadata: 
  node_type: memory
  type: project
  originSessionId: 5d17a0d7-de93-4779-83d2-45ade544ac8c
  modified: 2026-08-24T23:34:45.377Z
---

2026-08-24, two releases in one sitting:

**v0.29.4 — request #17 (turn-end tag confirms), SHIPPED + CLOSED.** A pure-success Stop-leg tag
confirm was dropped by design after F-035, so a delivered turn-end tag read exactly like a lost one
and the sane defensive resend double-delivered every success. Now: Stop PARKS the confirm in
`state/digest/<eid>.confirm` (beside the tag-scan cursor, appends if unsurfaced), and the author's
next UPS/PreToolUse surfaces it framed as the PREVIOUS turn's result with a do-NOT-resend line,
clearing strictly post-emit (wake-park custody). Failure confirms keep the FAILURE-LOUD self-send
(it can WAKE an idle author, a file cannot); a REFUSED failure self-send parks as fallback. Quiet
window doesn't read the park. `REQ-TAG-CONFIRM-NEXT-HOOK`. Agent-facing text updated in
`adapter/strings/briefs/messaging-perch.md` (ships with adapter) AND `plugin/sptc/skills/send/SKILL.md`
(rides the NEXT skeleton release — none shipped for this; skeleton stays 0.1.18).

**v0.29.5 — #19 (filed + fixed + field-closed same hour).** The FIRST alt-root
`spt adapter update` after v0.29.4 reported `ADAPTER_UPDATE_SUMMARY: FAILED` though the binary
applied: CC validates a marketplace's recorded `installLocation` LEXICALLY against the current
config root, and the [[v0293-alt-plugins-junction]]-shared store records primary-root paths — so
the post-step's `claude plugin marketplace update cplugs` was refused under the alt root while the
identical command at the primary succeeded (isolated both ways before filing). ⭐ A junction shares
CONTENT, not PATH IDENTITY — any consumer that compares recorded absolute paths against the current
root breaks under the sharing root, and a WRITE from the sharing root (marketplace add) would
corrupt the shared file for the primary. Fix (`REQ-POST-UPDATE-CANONICAL-ROOT`): when
`<config_root>/plugins` is a link, post_update runs the host CLI with `CLAUDE_CONFIG_DIR` set to
the link target's parent (strip the `\\?\` verbatim prefix — the child compares lexically). Unit
test builds a REAL junction via `alt::link_dir` (now pub(crate); mklink /J needs no elevation).

Traps re-paid this session:
- ⭐ `cmd | tail -N` returns TAIL's exit code — my first `traceable-reqs check | tail -8` "exit 0"
  proved nothing (the [[exit-zero-from-a-flag-order-noop]] class). Re-ran unpipelined before trusting.
- TOML basic strings: a literal `` `\\?\` `` inside a `title = "…"` is an invalid escape sequence —
  registry prose must avoid backslash runs (broke the gates once; reworded to "Windows long-path
  prefix").

FIELD-OBSERVED same day: my own signoff tag to doyle (final output of the ship turn) came back on
the next UPS as the parked `<sptc_tag_send>` block — `delivered → doyle`, previous-turn framing,
one-shot — the #17 mechanism proven live on its own author, not just in units. doyle re-verifies
from his box once it picks up ≥0.29.4, then softens his standing turn-end-unconfirmed memory rule.

Both releases: gates PASS + 503/505 crate tests, three triples rebuilt fresh (musl verified by
mtime), fat adapter.spt → BigscreenVR/claude-spt-bs release, public mirror applied (`--apply` in
POSITION 1) and verified via `git ls-remote --tags`. Node updated 0.29.3 → 0.29.5; the 0.29.5
update run WAS the #19 field-close (same command shape, now `updated` + VERIFIED).
