---
quick_task: 260517-6om
title: version-change owl-transport hotfix
status: partially_reverted_2026-05-20
revert_scope: deferred-spool transport (N/A — see banner)
preserved_scope: owl-message envelope, AUQ 3-option shape, version-remind deprecation
deployed_version: 1.10.12
marketplace_head: 09a98d9ec7c2475614ab7ade66d48f3a7b6e5f22
date: 2026-05-17
commits:
  - 5ede3d7 fix(34): emit version-change as owl message instead of Stop block
  - acbb696 chore(34): deprecate version-remind subcommand
  - 79193f1 test(34): rewrite integration tests for spool transport
  - fadc5b8 docs(34): fill CHANGELOG.md 1.10.11 backfill entry
  - a75583e chore: bump spt plugin to v1.10.12
  - e724a11 docs(34): fill 1.10.12 CHANGELOG entry + sync Cargo.lock
fixture_sha256: a1b07fb14c7a98ae6ebd1262d04fafe332bbecb0e7f5055e328a36635d474332
files_modified:
  - src/owl/version_changelog.rs
  - src/owl/hook_idle.rs
  - src/cli.rs
  - src/owl/mod.rs
  - tests/version_changelog.rs
  - tests/fixtures/version_changelog_block_reference.txt
  - CHANGELOG.md
  - plugin/spt/.claude-plugin/plugin.json
  - Cargo.toml
  - Cargo.lock
---

# Quick Task 260517-6om: Version-Change Owl-Transport Hotfix

> **⚠ PARTIAL REVERT 2026-05-20 — `deferred-spool` subpart marked N/A.**
>
> The hotfix originally chose `spool_message_deferred` (deferred=1, no TCP
> wake) as the transport so the version-change envelope would not interrupt
> the parent agent. That rationale is N/A — version-change is emitted from
> the Stop hook, so the agent's turn is already ending when the payload is
> generated; there is no current task to interrupt. The deferred-spool path
> also hid the version transition from any live perch stream until the next
> UserPromptSubmit hook drain.
>
> Commit `49f7598` (2026-05-20) flipped the transport to `send::deliver_body`
> (TCP-first, spool fallback on non-deferred row) — the conventional message
> delivery path used by every other inter-agent send in the codebase.
> Receiver-side urgency was also reverted in `5f39375` (n4b defect 2 → N/A):
> `is_informational` no longer matches `<spt-version-changelog>`, so the
> changelog AUQ surfaces the HIGHEST PRIORITY banner. See also the n4b
> SUMMARY (`260517-n4b-SUMMARY.md`) where defect 2 is marked N/A.
>
> **Still in force from this hotfix:** owl-message envelope (replaces the
> old red "Stop hook blocking error" banner from the Phase 34-02 JSON
> `decision:"block"` transport), AUQ 3-option shape (4 → 3, "Remind me
> later" removed), and `version-remind` subcommand deprecation.

## Outcome

Phase 34 UAT regression closed. The Stop hook's version-change emission no longer surfaces as a user-visible "Stop hook blocking error" — payload is now delivered as a silent owl message via deferred-spool insert. AskUserQuestion reduced from 4 options to 3 (`Remind me later` dropped due to infinite-loop pathology). `version-remind` subcommand deprecated (hidden from `--help`, still callable). Plugin deployed at v1.10.12.

## Per-task commits

| Task | SHA       | Subject                                                  |
|------|-----------|----------------------------------------------------------|
| 1    | `5ede3d7` | fix(34): emit version-change as owl message instead of Stop block |
| 2a   | `acbb696` | chore(34): deprecate version-remind subcommand           |
| 2b   | `79193f1` | test(34): rewrite integration tests for spool transport  |
| pre-3 | `fadc5b8` | docs(34): fill CHANGELOG.md 1.10.11 backfill entry       |
| 3    | `a75583e` | chore: bump spt plugin to v1.10.12 (DEPLOY.ps1)          |
| 3+   | `e724a11` | docs(34): fill 1.10.12 CHANGELOG entry + sync Cargo.lock |

Marketplace push: `09a98d9` on `cplugs/main`.

## Transport change

**Old transport (Phase 34-02):**

```
Stop hook -> println!({"decision":"block","reason":"<spt-version-changelog>..."})
          -> Claude Code surfaces as red "Stop hook blocking error" banner.
```

**New transport (this hotfix):**

```
Stop hook -> spool_message_deferred(self_perch, "version-change", <xml-body>)
          -> next UserPromptSubmit hook drains via peek_all/mark_delivered
          -> Claude sees the body inlined as <owl_messages> XML, silent.
```

`maybe_emit_version_change_block` now takes `&str` (the resolved self owl_id). On `Emitted`, the hook still returns early so `set_idle_ready` + `spawn_echo_commune_if_live` are skipped (preserves the existing ordering invariant). On `NotEmitted`, falls through to the normal Stop flow.

Defense-in-depth: `debug_assert!(!is_init_signoff_envelope(&body))` tripwire guards against the regression class from commit 30c0144. Release builds drop the assert; integration Test 15 carries the same predicate as a runtime check.

## AUQ change

| Option              | Pre-hotfix (4) | Post-hotfix (3) |
|---------------------|----------------|-----------------|
| Yes, full changelog | 1              | 1               |
| Yes, highlights only| 2              | 2               |
| Remind me later     | 3              | _removed_       |
| Skip                | 4              | 3               |

Freeform "Other" mapping simplified: all continuation phrases (`later` / `not now` / `ignore` / `stop asking` / `no`) map to **Skip**. The `<invocation_for_remind>` XML element was removed from the payload.

## Verification gates

| Gate                                                        | Status   |
|-------------------------------------------------------------|----------|
| `cargo build --release` (zero new warnings)                 | PASS     |
| `cargo test --lib version_changelog` (43 tests)             | PASS     |
| `cargo test --test version_changelog` (15 tests)            | PASS     |
| `grep -c 'decision":"block"' src/owl/version_changelog.rs`  | 0 hits   |
| `grep -c 'invocation_for_remind' src/owl/version_changelog.rs` (non-comment) | 0 hits |
| `grep -c spool_message_deferred src/owl/version_changelog.rs` | 2 hits (doc + code) |
| `owl --help` lists `version-remind`                          | NO (hidden) |
| `owl version-remind --help` still parses                     | YES      |
| DEPLOY.ps1 -Bump patch                                       | exit 0   |
| `installed_plugins.json` version pointer                     | 1.10.12  |
| Deployed cache binary `owl.exe --version`                    | `owl 1.10.12` |
| Marketplace HEAD pushed                                      | 09a98d9  |

## Fixture regeneration

`tests/fixtures/version_changelog_block_reference.txt` regenerated via:

```
cargo test --lib version_changelog::tests::print_canonical_block_reason_for_reference -- --ignored --nocapture
```

New fixture reflects the 3-option AUQ wording (no Remind option, no `<invocation_for_remind>` element).

**SHA-256:** `a1b07fb14c7a98ae6ebd1262d04fafe332bbecb0e7f5055e328a36635d474332`

## Deviations from plan

### Rule 3 — fill in pre-existing 1.10.11 CHANGELOG.md `TODO: changelog entry` stub

DEPLOY.ps1's abort gate (Phase 34 D-10) refused to bump 1.10.11 → 1.10.12 until the un-filled 1.10.11 TODO stub from a prior `-Bump` run was resolved. This was blocking Task 3 deploy.

Backfilled the 1.10.11 entry to describe what Plan 02 actually shipped (sentinel + parser + payload + version-remind subcommand) in a separate atomic commit (`fadc5b8`) before re-running DEPLOY.ps1. No scope creep — the entry is purely documentation of work that had already landed in `dbeede6`. Plan unchanged otherwise.

## Notes on DEPLOY.ps1 output

- One non-fatal sharing-violation: cache dir `1.10.10` was renamed to `.pending-prune-1.10.10-1778994347` but its `owl.exe` could not be deleted (still in use). Carry-over cleanup expected on next deploy; resolver-invisible per the renamed (non-semver) leaf. This is the documented Phase 27-07 / Phase 18.8.1 precedent.
- Keep-set: `1.10.12` (new), `1.10.11` (previous — preserved for in-flight handoffs).
- Marketplace pushed cleanly. `claude plugin install spt@cplugs` reported "already installed" (DEPLOY.ps1's atomic `installed_plugins.json` patch handled the pointer flip).

## Tests intentionally green between commits

All test suites pass after each commit:

- After `5ede3d7` (Task 1): `cargo test --lib version_changelog` — 43 pass (unit-test edits + signature change applied together).
- After `acbb696` (Task 2a): no new tests; cli.rs `version-remind` parse + missing-arg unit tests still green (regression guards for the hidden subcommand).
- After `79193f1` (Task 2b): `cargo test --test version_changelog` — 15 pass.
- After `a75583e` (DEPLOY bump): full lib + integration suites still green for the version_changelog scope.

No window of intentional red — Task 1's unit-test edits and signature change land in the same commit, and Task 2b's integration-test rewrite + fixture land together.

## Pre-existing unrelated failures

`cargo test --workspace` reports 23 unrelated failures across `live::*`, `owl::resume::*`, `owl::cleanup::*`, `owl::plugin_session_start::*`, `common::owlery::*`, and `live::wrapper::*` modules. These are pre-existing parallel-test ENV_LOCK isolation flakes documented in `.planning/phases/32-list-overhaul-skill-hint-audit/deferred-items.md` (verified pre-existing by Phase 32 Plan 02 + Plan 03 via git-stash toggle). Plan-tracked count crept 19 → 21 across Phase 34 Task 1/2; this hotfix did not introduce new failures (the version_changelog test in the failure list, `read_sentinel_returns_some_on_happy_path`, passes in isolation and is in the known flake set).

## User action required

The deploy script intentionally stops before `/reload-plugins` per project convention. User must:

```
/reload-plugins
```

inside Claude Code to pick up v1.10.12.

## Self-check

- [x] All 3 plan tasks completed in order.
- [x] Each task committed atomically (Task 1 = 1 commit, Task 2 = 2 commits, Task 3 = DEPLOY-script commit + curated CHANGELOG follow-up).
- [x] `cargo build --release` clean.
- [x] `cargo test --lib version_changelog` and `cargo test --test version_changelog` green.
- [x] Reference fixture regenerated + SHA-256 captured.
- [x] DEPLOY.ps1 exit 0; cache pointer flipped to 1.10.12; binary asserts `owl 1.10.12`.
- [x] No `decision":"block"` JSON envelope construction in source.
- [x] `version-remind` hidden from `--help`; still callable for back-compat.
- [x] INIT_SIGNOFF false-positive regression guarded by both debug_assert + integration Test 15.

## Self-Check: PASSED
