---
phase: 260523-7zy-fix-v1-11-9-handoff-argv-backward-compat
plan: 01
type: quick
completed: 2026-05-23
duration: ~6min
tasks: 2
commits:
  - f105536 (fix: pulse_psyche clap default + regression test)
  - 2328747 (chore: bump spt plugin to v1.11.10 + CHANGELOG)
files-modified:
  - src/cli.rs
  - tests/handoff_integration.rs
  - plugin/spt/.claude-plugin/plugin.json
  - Cargo.toml
  - Cargo.lock
  - CHANGELOG.md
requirements-complete:
  - QUICK-260523-7zy-argv-backward-compat
  - QUICK-260523-7zy-regression-test
  - QUICK-260523-7zy-version-bump
---

# Quick 260523-7zy: Fix v1.11.9 Handoff Argv Backward-Compat Summary

**One-liner:** Add `#[arg(default_value = "0")]` to `pulse_psyche` so v1.11.8 wrappers handing off to v1.11.10+ binaries with the legacy 5-arg `_psyche-wrapper` argv shape clap-parse instead of crashing before logging.

## Root Cause Recap

Commit `3616ed1` (shipped in v1.11.9) added `pulse_psyche: String` as a REQUIRED clap positional on `Commands::PsycheWrapper` in `src/cli.rs`. State-file backward-compat was handled (`#[serde(default)]` on `WrapperHandoffState.pulse_psyche`) but the symmetric argv path was missed. v1.11.8 wrappers exec'd v1.11.9 with the legacy 4-positional shape; clap rejected with `the following required arguments were not provided: <PULSE_PSYCHE>` and exited before `WrapperState::new` ran — no log line, perch went stale, listener orphan-detected and died too. Full root cause: `.planning/debug/binary-handoff-defer-todlando.md`.

## Changes

### Task 1 — `f105536`

| File | Rationale |
| ---- | --------- |
| `src/cli.rs` | One-line addition: `#[arg(default_value = "0")]` above the `pulse_psyche: String,` field inside `Commands::PsycheWrapper` (line 196). No other field, doc comment, or attribute touched. Wrapper-side `arg == "1"` dispatch unchanged — defaulted `"0"` flows through the "off" branch, identical to legacy v1.11.8 behaviour. |
| `tests/handoff_integration.rs` | New `#[test] fn psyche_wrapper_5arg_argv_backward_compat()` appended in a fresh `Quick 260523-7zy — argv backward-compat regression guard` banner block at end-of-file. Function-scoped `use clap::Parser; use owl::cli::{Cli, Commands};` (defensive — no cross-test imports). Two cases: (1) 5-arg argv parses with `pulse_psyche == "0"`, (2) 6-arg argv preserves explicit `"1"`. Round-trips all four leading positionals so future field-reordering would fail loudly. |

### Task 2 — `2328747`

| File | Rationale |
| ---- | --------- |
| `plugin/spt/.claude-plugin/plugin.json` | Plugin version of record: `1.11.9` → `1.11.10`. |
| `Cargo.toml` | Crate version in lockstep: `1.11.9` → `1.11.10`. |
| `Cargo.lock` | `owl` package stanza: `1.11.9` → `1.11.10`. Single-line diff (the lockfile entered the task dirty at `1.11.6` from prior unrelated work and was bumped through to `1.11.10`; no other crate entries touched, no `cargo update` run). |
| `CHANGELOG.md` | New `## [1.11.10] - 2026-05-23` section above `## [1.11.9]` with `### Fixed` bullet (symptom → fix → why state-file compat was insufficient) and `### BTS` bullet referencing the regression test and the quick plan path. Retrospective style matching `[1.11.8]` and `[1.11.9]` entries. |

## Regression Test Output

`cargo test --test handoff_integration` full-suite (full output tail):

```
running 20 tests
test chain_root_still_uses_stdio_relay ... ignored, negative-control: long-running subprocess fixture deferred; positive assertion in handoff_child_defers_via_sentinel_exit_code
test extract_from_missing_plugin ... ok
test extract_from_valid_manifest ... ok
test is_same_file_literal_path_equality ... ok
test is_same_file_nonexistent_pair_returns_false ... ok
test psyche_wrapper_5arg_argv_backward_compat ... ok
test handoff_none_when_manifest_missing_passes_through ... ok
test handoff_none_when_manifest_malformed_passes_through ... ok
test handoff_none_when_spt_cplugs_missing ... ok
test handoff_none_when_installpath_points_to_same_binary ... ok
test handoff_none_when_installpath_has_no_binary ... ok
test trampoline_guard_breaks_infinite_loop ... ok
test under_wrapper_env_causes_exit_2_and_defer_tag ... ok
test handoff_child_defers_via_sentinel_exit_code ... ok
test trampoline_forwards_to_new_binary ... ok
test under_wrapper_env_without_handoff_polls_normally ... ok
test handoff_child_does_not_wipe_inbox ... ok
test handoff_child_env_bypasses_duplicate_guard ... ok
test nested_psyche_layout ... ok
test psyche_relocate_on_start ... ok

test result: ok. 19 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 30.39s
```

`cargo build --release` finished clean (6 pre-existing dead-code warnings, none introduced by this change).

## Deviations from Plan

None — plan executed exactly as written. The plan correctly anticipated:
- Function-scoped test imports (no file-level `Parser` / `Cli` / `Commands` pollution).
- Field-type preservation (`pulse_psyche: String` retained — wrapper-side `arg == "1"` dispatch untouched).
- `default_value` over `default_missing_value` (positional-correct clap concept).
- Cargo.lock owl-stanza-only edit (no `cargo update`).

## Self-Check

- `src/cli.rs` line 196: `#[arg(default_value = "0")]` present immediately above `pulse_psyche: String,` — FOUND.
- `tests/handoff_integration.rs`: `psyche_wrapper_5arg_argv_backward_compat` test FOUND, passing.
- `plugin/spt/.claude-plugin/plugin.json` version `1.11.10` — FOUND.
- `Cargo.toml` version `1.11.10` — FOUND.
- `Cargo.lock` owl package `1.11.10` — FOUND.
- `CHANGELOG.md` `## [1.11.10] - 2026-05-23` section above `## [1.11.9]` — FOUND.
- `git log --oneline -2`: `2328747 chore: bump spt plugin to v1.11.10`, `f105536 fix(handoff): pulse_psyche clap default…` — both FOUND.
- `cargo build --release` clean, `cargo test --test handoff_integration` 19/19 passed.

## Self-Check: PASSED

## Deploy

`docs/DEPLOY.ps1` was NOT run by the executor — this is the operator's manual follow-up step per CLAUDE.md and the planning constraints. Next operator actions:

1. `powershell -ExecutionPolicy Bypass -File docs/DEPLOY.ps1` — no `-Bump` flag needed (version is already at 1.11.10). Deploy will rebuild, sync `owl.exe` + `plugin/spt/skills/` + `plugin/spt/hooks/` + `plugin.json` to the marketplace clone, refresh the plugin cache, and run `claude plugin install spt@cplugs`. Run `/reload-plugins` manually after deploy completes.
2. `$LIVE revive todlando` — bring the dead live agent back on v1.11.10. The on-disk `wrapper-state.json` (gen=30) at `%LOCALAPPDATA%\spt\owlery\todlando-psyche\` will be picked up by the new wrapper.

Note for the future: any v1.11.8 wrapper still alive on any user's machine will now hand off correctly into v1.11.10. The fix is fully retroactive in the sense that the side that was broken (the receiver's clap parser) is the side that just got patched — old wrappers don't need to be updated to benefit.
