---
gsd_state_version: 1.0
milestone: v1.8
milestone_name: Psyche Restructure
status: ready_to_plan
stopped_at: Phase 35.3 complete (4/4) — ready to discuss Phase 999.1
last_updated: 2026-05-29T12:26:06.289Z
last_activity: 2026-05-29
progress:
  total_phases: 17
  completed_phases: 10
  total_plans: 55
  completed_plans: 77
  percent: 59
---

# Project State

## Deferred Items

Items acknowledged and deferred at v1.7 milestone close on 2026-05-16:

| Category | Item | Status | Disposition |
|----------|------|--------|-------------|
| debug | psyche-stale-after-clear | root_cause_found | pre-v1.7; carry forward for spot-fix in v1.8 |
| uat_gaps | Phase 17 17-HUMAN-UAT.md | passed (0 open) | pre-v1.7; listed in audit but substantively closed |
| uat_gaps | Phase 18 18-UAT.md | passed (0 open) | pre-v1.7 |
| uat_gaps | Phase 18.4 18.4-HUMAN-UAT.md | passed (0 open) | off-roadmap sub-iteration of Phase 18 |
| uat_gaps | Phase 18.5 18.5-HUMAN-UAT.md | passed (0 open) | off-roadmap sub-iteration of Phase 18 |
| uat_gaps | Phase 18.6 18.6-HUMAN-UAT.md | passed (0 open) | off-roadmap sub-iteration of Phase 18 |
| uat_gaps | Phase 18.8 18.8-03-...-UAT-PLAN.md | passed (0 open) | off-roadmap sub-iteration of Phase 18 |
| uat_gaps | Phase 18.8.1 18.8.1-04-...-UAT-PLAN.md | passed (0 open) | off-roadmap sub-iteration of Phase 18 |
| uat_gaps | Phase 26 26-UAT.md | passed (0 open) | UAT PASS post 26-06 gap closure |
| uat_gaps | Phase 28 28-HUMAN-UAT.md | passed | 2 raw-stdout /clear deploy-cycle tests deferred (260421-0ws); non-blocking |
| todos | 2026-03-28-add-willful-flag-to-owl-listen-and-live-commands | open | next milestone candidate |
| todos | 2026-04-13-abrupt-messaging-precede-sendkeys-with-ctrl-b-esc-sequence | open | v1.9 capsule scope |
| todos | 2026-04-13-capsule-psmux-use-winname-flag-for-repo-branch | open | v1.9 capsule scope |
| todos | 2026-04-13-capsule-reattach-existing-psmux-session | open | v1.9 capsule scope |
| todos | 2026-04-18-add-psyche-peek-slash-command-powershell-resume-branch | open | psyche scope (v1.8 candidate) |
| todos | (+2 more) | open | see .planning/todos/pending/ |
| seeds | SEED-003-relocate-working-perches-nested-under-parent | dormant | tied to Phase 25 perch nesting (v1.8) |

Known deferred items at v1.7 close: 16 (acknowledged via gsd-complete-milestone artifact audit).

Items acknowledged and deferred at v1.7.1 milestone close on 2026-05-18:

| Category | Item | Status | Disposition |
|----------|------|--------|-------------|
| debug | psyche-stale-after-clear | root_cause_found | carry-forward from v1.7; v1.8 spot-fix candidate |
| todos | 2026-03-28-add-willful-flag-to-owl-listen-and-live-commands | open | carry-forward from v1.7; v1.9 candidate |
| todos | 2026-04-13-abrupt-messaging-precede-sendkeys-with-ctrl-b-esc-sequence | open | carry-forward; v1.9 capsule scope |
| todos | 2026-04-13-capsule-psmux-use-winname-flag-for-repo-branch | open | carry-forward; v1.9 capsule scope |
| todos | 2026-04-13-capsule-reattach-existing-psmux-session | open | carry-forward; v1.9 capsule scope |
| todos | 2026-04-18-add-psyche-peek-slash-command-powershell-resume-branch | open | carry-forward; psyche scope (v1.8 candidate) |
| seeds | SEED-003-relocate-working-perches-nested-under-parent | dormant | carry-forward; tied to Phase 25 perch nesting (v1.8) |

Known deferred items at v1.7.1 close: 7 (all carry-forward from v1.7 — no v1.7.1-originated deferrals).

## Project Reference

See: .planning/PROJECT.md (updated 2026-05-16)

**Core value:** Reliable, zero-dependency agent-to-agent messaging that just works on any machine, with a live-agent layer that survives `/clear`, `/compact`, binary handoffs, and orphan boundaries without losing context.
**Current focus:** Phase 999.1 — rearrange psyche organization per self id folder general and

## Current Position

Milestone: v1.8 Psyche Restructure (open — phases 23, 24, 24.1 ✓; 25.3 ✓; 25, 35 pending)
Phase: 999.1
Plan: Not started
Status: Ready to plan
Last activity: 2026-06-02 - Completed quick task 260602-2ar: FILE-DROP consume of commune/signoff now clears the .more-done cadence sentinel (no redundant echo commune)
Prior: 2026-05-29

**35-10 (SC1 gap-closure):** Replaced passive SessionStart sync-prompt with ACTIVE owl-message delivery (`src/owl/sync_prompt.rs`); wired from `$LIVE start`/`revive` + `/clear`|`/compact`; deleted `.sync-prompt-due` sentinel; added always-loaded SKILL handler + render-path test; fixed doctor PASS-on-failing rows. Commits 286fe40, e8c78ee, 2c17cd9, d0fcfb6.

**Roadmap Overview:**

| Phase | Goal | Requirements | Deps |
|-------|------|--------------|------|
| 31 | Picker Correctness | PICK-01..06 (6) | none in v1.7.1 |
| 32 | List Overhaul + Skill Hint Audit | LIST-01..08 + HINT-01..05 (13) | none |
| 33 | Fresh-Start Commune + Auto-Resume | FRESH-01..06 + AUTO-01..08 (14) | Phase 31 |
| 34 | Version-Change Changelog | VERS-01..09 (9) | none in v1.7.1; sequenced after 33 |

**Deploy Cadence:** Single `DEPLOY.ps1 -Bump patch` at end-of-milestone (Phase 34 SUMMARY notes the bump), NOT per-phase.

**Research Flags:**

- Phase 33 needs pre-coding design steps for CP-3 allow-list predicate + CP-4 test corpus (15+ should-fire / 15+ should-NOT-fire cases). No full `/gsd-research-phase` required — surface in phase plan.
- Phase 34 must begin with CHANGELOG.md existence check (create from git log if absent; H2-per-version format).
- Phases 31 and 32 follow standard patterns — skip phase research.

## Performance Metrics

**Velocity:**

- Total plans completed: 55 (v1.6)
- Average duration: -
- Total execution time: 0 hours

**By Phase:**

| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| 17 | 2 | - | - |
| 18 | 2 | - | - |
| 18.1 | 4 | - | - |
| 18.3 | 2 | - | - |
| 18.5 | 3 | - | - |
| 18.7.1 | 2 | - | - |
| 18.7 | 4 | - | - |
| 28 | 4 | - | - |
| 31 | 2 | - | - |
| 25.1 | 6 | - | - |
| 25.3 | 6 | - | - |
| 25.4 | 7 | - | - |
| 35.2 | 3 | - | - |
| 35.3 | 4 | - | - |

**Recent Trend:**

- Last 5 plans (v1.5): 225s, 154s, 265s, 183s, 336s
- Trend: Stable (~3-5min per plan)

*Updated after each plan completion*
| Phase 16 P01 | 500 | 2 tasks | 20 files |
| Phase 16 P02 | 238 | 2 tasks | 9 files |
| Phase 16 P03 | 174 | 2 tasks | 4 files |
| Phase 16 P04 | 342 | 2 tasks | 4 files |
| Phase 17 P01 | 186 | 2 tasks | 3 files |
| Phase 17 P02 | 120 | 1 tasks | 3 files |
| Phase 18 P01 | 341 | 3 tasks | 7 files |
| Phase 18 P02 | 264 | 2 tasks | 10 files |
| Phase 18.1 P01 | 165 | 2 tasks | 5 files |
| Phase 18.1 P02 | 124 | 2 tasks | 2 files |
| Phase 18.1 P03 | 290 | 2 tasks | 3 files |
| Phase 18.1 P04 | 391 | 2 tasks | 7 files |
| Phase 18.2 P01 | 163 | 2 tasks | 5 files |
| Phase 18.2 P02 | 180 | 2 tasks | 5 files |
| Phase 18.2 P03 | 282 | 2 tasks | 5 files |
| Phase 18.2 P04 | 212 | 4 tasks | 1 files |
| Phase 18.3 P01 | 184 | 1 tasks | 1 files |
| Phase 18.3 P02 | 197 | 2 tasks | 2 files |
| Phase 18.4 P01 | 179 | 3 tasks | 5 files |
| Phase 18.4 P02 | 150 | 2 tasks | 2 files |
| Phase 18.4 P03 | 305 | 3 tasks | 5 files |
| Phase 18.4 P04 | 3 min | 1 tasks | 2 files |
| Phase 18.5 P01 | 313 | 2 tasks | 4 files |
| Phase 18.5 P02 | 147 | 1 tasks | 1 files |
| Phase 18.5 P03 | 204 | 3 tasks | 5 files |
| Phase 18.6 P01 | 2 | 2 tasks | 2 files |
| Phase 18.6 P03 | 244 | 5 tasks | 6 files |
| Phase 18.6 P02 | 264 | 4 tasks | 5 files |
| Phase 18.7 P01 | 437 | 2 tasks | 3 files |
| Phase 18.7 P02 | 307 | 2 tasks | 2 files |
| Phase 18.7 P03 | 180 | 2 tasks | 11 files |
| Phase 18.7 P04 | 14min | 4 tasks | 9 files |
| Phase 18.7.1 P01 | 40min | 2 tasks | 7 files |
| Phase 18.7.1 P02 | 2 min | 2 tasks | 3 files |
| Phase 18.8 P01 | 5 min | 2 tasks | 2 files |
| Phase 18.8 P02 | 10 min | 1 tasks | 4 files |
| Phase 18.8 P03 | ~45min | 3 tasks | 2 files |
| Phase 18.8.1 P01 | 15min | 3 tasks | 2 files |
| Phase 18.8.1 P02 | 4min | 2 tasks | 1 files |
| Phase 18.8.1 P03 | 4.5min | 3 tasks | 4 files |
| Phase 26 P01 | 18m | 6 tasks | 13 files |
| Phase 26 P26-04 | 35 | 4 tasks | 4 files |
| Phase 26 P26-03 | 9 | 6 tasks | 4 files |
| Phase 26 P26-02 | 22 | 6 tasks | 5 files |
| Phase 26 P05 | 2m 49s | 4 tasks | 3 files |
| Phase 26 P06 | ~6m | 5 tasks | 2 files |
| Phase 27 P02 | 35min | 3 tasks | 6 files |
| Phase 27 P05 | 15min | 2 tasks | 1 files |
| Phase 27 P06 | 25min | 4 tasks | 9 files |
| Phase 27 P07 | 3min | 2 tasks (Task 3 user-owned, pending) | 3 files |
| Phase 28 P01 | ~12min | 2 tasks | 2 files |
| Phase 28 P02 | ~4min | 1 tasks | 1 files |
| Phase Phase 28 PP03 | ~10min | 2 tasks tasks | 2 files files |
| Phase 28 P04 | 20min | 2 tasks | 3 files |
| Phase 30 P01 | 18min | 3 tasks | 3 files |
| Phase 30 P02 | 25 | 3 tasks | 2 files |
| Phase 30 P03 | 12min | 1 tasks tasks | 1 files files |
| Phase 30 P04 | 15 | 2 tasks | 4 files |
| Phase 31 P01 | 3m | 2 tasks tasks | 2 files files |
| Phase 31 P02 | 25 | 2 tasks | 3 files |
| Phase 34 P01 | 25min | - tasks | - files |
| Phase 23-commune-signoff-project-root-head-sha-stamping P03 | 5 min | 1 tasks | 2 files |
| Phase 23 P05 | 5 min | 1 tasks | 3 files |
| Phase 23 P06 | 2 min | 2 tasks | 3 files |
| Phase 24 P01 | 8 | 3 tasks | 4 files |
| Phase 24 P02 | 25 | 2 tasks | 1 files |
| Phase 24 P03 | 35 | 3 tasks | 8 files |
| Phase 24 P04 | 40 | 4 tasks | 8 files |
| Phase 24 P05 | 25 | 1 task | 1 files |
| Phase 24 P06 | 35 | 2 tasks | 2 files |
| Phase 24.1 P01 | 12 | 3 tasks | 4 files |
| Phase 24.1 P02 | 22 | 3 tasks | 1 files |
| Phase 24.1 P03 | 18 | 3 tasks | 5 files |
| Phase 24.1 P04 | 22 | 3 tasks | 4 files |
| Phase 24.1 P05 | 12 | 3 tasks | 1 files |
| Phase 25.1 P01 | 6min | 1 tasks | 1 files |
| Phase 25.1 P02 | 1min | 1 tasks | 1 files |
| Phase 25.1 P03 | 3min | 1 tasks | 1 files |
| Phase 25.1 P04 | 145 | - tasks | - files |
| Phase 25.1 P05 | 4min | 1 tasks | 1 files |
| Phase 25.1 P06 | 1min | 1 tasks | 1 files |
| Phase 25.2 P01 | 644s | 6 tasks tasks | 9 files files |
| Phase 25.2 P02 | 410s | 5 tasks | 5 files |
| Phase 25.2 P03 | 220s | 4 tasks | 1 files |
| Phase 25.3 P01 | 30min | 4 tasks | 4 files |
| Phase 25.3 P03 | 40min | 3 tasks | 3 files |
| Phase 25.3 P02 | 25min | 4 tasks | 5 files |
| Phase 25.3 P04 | ~120min | 9 tasks | 7 files |
| Phase 25.3 P05 | ~90min | 9 tasks tasks | 10 files files |
| Phase 25.3 P06 | 9min | 3 tasks tasks | 2 files files |
| Phase 25.4 P01 | 6min | 1 tasks | 2 files |
| Phase 25.4 P02 | 5min | 1 tasks | 1 files |
| Phase 25.4 P03 | ~25min | 1 tasks | 7 files |
| Phase 25.4 P04 | 22min | - tasks | - files |
| Phase 25.4 P05 | 15min | 3 tasks | 4 files |
| Phase 25.4 P06 | 12min | 5 tasks | 8 files |
| Phase 25.4 P07 | 60min | 4 tasks tasks | 4 files files |
| Phase 35 P01 | 3min | 2 tasks | 1 files |
| Phase 35 P03 | 6min | 1 tasks | 1 files |
| Phase 35 P02 | ~4min | 2 tasks | 3 files |
| Phase 35 P04 | 442s | 2 tasks | 5 files |
| Phase 35 P05 | 7min | 1 tasks | 2 files |
| Phase 35 P07 | 4min | 2 tasks | 4 files |
| Phase 35 P08 | 4min | 2 tasks | 4 files |
| Phase Phase 35 PP06 | 6min | 2 tasks tasks | 2 files files |
| Phase 35 P09 | 12min | 2 tasks | 9 files |
| Phase 35 P10 | 35min | 4 tasks | 10 files |
| Phase 35.1 P01 | 6min | 2 tasks | 7 files |
| Phase 35.1 P02 | 5min | 1 tasks | 1 files |
| Phase 35.1 P35.1-03 | 12min | 3 tasks | 5 files |
| Phase 35.1 P04 | 16 | 3 tasks | 6 files |
| Phase 35.2 P02 | 12min | 3 tasks | 2 files |
| Phase 35.2 P03 | 14min | 4 tasks | 4 files |
| Phase 35.3 P01 | 6min | 2 tasks | 3 files |
| Phase 35.3 P04 | 3min | 2 tasks | 1 files |
| Phase 35.3 P03 | 9min | 2 tasks tasks | 2 files files |

## Accumulated Context

### Decisions

Decisions are logged in PROJECT.md Key Decisions table.
Recent decisions affecting current work:

- [Phase 35-10]: Sync-setup prompt delivers as an ACTIVE owl message (self-contained `<instructions>` + always-loaded SKILL handler, mirror version-change) — NOT passive SessionStart additionalContext (which Claude ignored). SC1 fix.
- [Phase 35-10]: Deleted the `.sync-prompt-due` sentinel cross-session-deferral entirely — active in-session delivery makes it obsolete (write→next-boot-consume could never pair in one session).
- [Phase 35-10]: doctor per-branch sync row — FAIL on active backoff / hard-stop reason, WARN on transient elapsed-backoff failure, PASS only when clean (no more green PASS masking a recorded failure).
- [v1.7.1 Roadmap]: 4 phases derived from research SUMMARY.md grouping — Phase 31 (PICK), Phase 32 (LIST+HINT), Phase 33 (FRESH+AUTO), Phase 34 (VERS); 42 requirements, 100% coverage
- [v1.7.1 Roadmap]: Phase 31 lands first because PICK-* corrected pick-spec shape is prerequisite for Phase 33 (FRESH-01 routes through `kind:"prompt-new"`; AUTO-01 routes through `kind:"auto"`/`kind:"pick"`)
- [v1.7.1 Roadmap]: Items 1+2 batched in Phase 32 — naturally coupled on skill frontmatter (new list flags require new argument-hints on list-* skills); single DEPLOY cycle
- [v1.7.1 Roadmap]: Items 3+5 batched in Phase 33 — both modify `plugin/spt/skills/live/SKILL.md` dispatch table; both depend on Phase 31 pick-spec shape; planning together prevents half-consistent dispatch table
- [v1.7.1 Roadmap]: Phase 34 sequenced last — CHANGELOG.md prerequisite + SessionStart hook isolated from Phase 33 (keeps two SessionStart-hook extensions in separate phases per ARCHITECTURE.md guidance)
- [v1.7.1 Roadmap]: Single DEPLOY.ps1 -Bump patch at end-of-milestone (Phase 34 SUMMARY notes the bump), NOT per-phase — avoids version-churn during in-flight binary handoffs (Phase 18.4/18.5 constraint)
- [v1.7.1 Roadmap]: Schema-freeze D5 preserved — Phase 31 fix introduces NEW `kind:"all-live"` variant rather than reshaping existing `kind:"prompt-new"` (MP-3 prevention)
- [v1.7.1 Roadmap]: env!(CARGO_PKG_VERSION) only for VERS-02; NEVER reads plugin.json at runtime (CP-1 binary handoff race prevention)
- [v1.7.1 Roadmap]: AUTO-03 SessionStart auto-pick rejects silently inside subagent sessions (no stderr leakage into psyche-wrapper / GSD researcher transcripts) — CP-3 prevention
- [v1.7.1 Roadmap]: Bare ambiguous phrases ("keep going", "resume work") explicitly REJECTED as casual-language triggers — AUTO-06 enforces explicit agent/live reference; AUTO-07 mandatory AskUserQuestion confirmation hop before any `$LIVE start` (CP-4 prevention)
- [v1.6 Design]: Hand-rolled JSON-RPC over stdio -- no tokio, no new dependencies
- [v1.6 Design]: Poll listener keeps TCP listener ownership -- MCP server is read-only over spool state
- [v1.6 Design]: _result() variants parallel existing run() functions -- MCP dispatch never calls run()
- [v1.6 Design]: MCP server auto-discovers agent_id via resolve_self_id() for capsule, binds via listen/live-start for non-capsule
- [v1.6 Design]: Phase 15 is a spike to validate MCP works with Claude Code before full build
- [v1.6 Design]: Psyche explicitly excluded from MCP -- CLI only via $OWL/$LIVE
- [Phase 16]: deliver_body/deliver_body_anonymous internal helper names kept as-is (describe TCP mechanics, not CLI command)
- [Phase 16]: Reply kept as hidden deprecated CLI command routing to send::run_reply for backward compat
- [Phase 16]: Live _result() functions take body as direct parameter (no stdin), follow same D-07 pattern as owl _result()
- [Phase 16]: Tool registry uses json! macros for definitions -- no new struct types needed
- [Phase 16]: All 13 MCP tools wired -- action tools use lazy-bind identity via Arc<Mutex>
- [Phase 17]: resolve_agent is read-only -- no lazy-bind side-effect for resource reads
- [Phase 17]: Notification JSON uses json! macro without id field -- T-17-07 mitigated by construction
- [Phase 18]: peek_all + mark_delivered pattern for atomic spool coordination with MCP server
- [Phase 18]: Root-level SKILL.md, LIVE-SKILL.md, commune.md deleted -- plugin skills are canonical
- [Phase 18]: Plugin version bumped to 1.6.0 for MCP fabric milestone
- [Phase 18.1]: Deferred delivery skips TCP entirely, relies on hook-based cadence for delivery
- [Phase 18.1]: Spool timeout uses 300s (5 minutes) with cancellation on idle-ready or spool drain
- [Phase 18.1]: parent_pid is primary liveness check for orphan detection; poll PID is backward-compat fallback only
- [Phase 18.1]: Combined tasks into single commit when intermediate state doesn't compile (cross-file method references)
- [Phase 18.1]: Psyche communicates via [REPLY]/[NOTIFY]/[COMMUNE] text markers instead of $OWL CLI calls
- [Phase 18.1]: Echo commune uses haiku model with low effort, fire-and-forget delivery to Psyche
- [Phase 18.2]: [Phase 18.2]: spt_home() resolver uses three-tier resolution (SPT_HOME > platform default > panic) with no legacy spacetime fallback (D-13 hard cutover)
- [Phase 18.2]: [Phase 18.2]: Registry stays at owlery/.registry per D-07 amended — no registry_db() helper added at spt root
- [Phase 18.2]: [Phase 18.2]: <spacetime-reorientation> XML tag in resume.rs preserved per D-18 — semantic payload, not a path
- [Phase 18.2]: Doc audit wave: literal ~/.claude/spacetime path refs purged from active docs and scripts; brand/concept mentions of 'spacetime' preserved per D-18
- [Phase 18.2]: Test harness SPT_HOME refactor: no shared tests/common/mod.rs helper created — per-file Command builders differ in shape (live prefixing, OWL_BINARY override, direct-spawn blocks); 3-line inline idiom per file is more readable than a 4-way union helper
- [Phase 18.2]: Plan 04 deploy+migration: plugin version bumped 1.7.5→1.8.0 via DEPLOY.ps1 -Bump minor; user state robocopied from ~/.claude/spacetime to %LOCALAPPDATA%/spt with exact 973-entry parity; old tree hard-deleted per D-11; 0 active-repo grep hits for .claude/spacetime
- [Phase 18.2]: Pre-migration destination had 37-entry test pollution from Phase 18.2 dev; removed per checkpoint instructions (empty or clearly non-production fallback); re-ran pre-flight green; proceeded with migration
- [Phase 18.3]: [Phase 18.3]: Stop hook writes .more-done sentinel (zero-byte) at owlery/{psyche_id}/.more-done instead of spawning _echo-commune subprocess. OWL_ECHO_COMMUNE recursion guard now gates sentinel creation. Inline Windows CreateProcessW + Unix setsid helpers deleted (superseded by common::win_spawn for remaining callers).
- [Phase 18.3]: Wrapper-side echo-commune gate: 15-min hardcoded window on Self context mtime, delete-sentinel-before-spawn (D-09), fresh info.json read per fire (Pitfall 5), shared win_spawn helper (no CreateProcessW duplicate). should_fire as pure predicate + WrapperState::fire_echo_commune_if_due method separation for testability.
- [Phase 18.4]: Plan 01: Windows spawn_and_wait_inherit_stdio added as stub in Plan 01 so Wave 1 crate links; Plan 02 Task 1 replaces the body
- [Phase 18.4]: Plan 01: HANDOFF: trampoline -> marker unconditional (not cfg(debug_assertions)) so release-mode integration tests can positively verify exec fired
- [Phase 18.4]: Plan 02: In-loop handoff check placed AFTER teardown (stop/ready/poison) and BEFORE check_message_blocking — explicit teardown wins, cheap stat before blocking wait
- [Phase 18.4]: Plan 02: Windows inherit-stdio spawn omits CREATE_NEW_PROCESS_GROUP so Ctrl+C propagates through shared console group (Pitfall 7)
- [Phase 18.4]: Plan 03: load_and_delete unlinks wrapper-state.json on BOTH successful parse and parse failure — prevents tmp garbage on schema mismatch or crash mid-write
- [Phase 18.4]: Plan 03: hydrated_from_handoff bool on WrapperState gates init_session in single run() path (no parallel run_hydrated entry)
- [Phase 18.4]: Plan 03: perform_wrapper_handoff writes state BEFORE spawning; mid-write crash cold-starts new wrapper (D-08 fallback) — acceptable cost (one commit, one gen bump) vs. race on empty state file
- [Phase 18.4]: Plan 04: All test env manipulation uses Command::env (subprocess-scoped), so integration tests are parallel-safe without --test-threads=1
- [Phase 18.4]: Plan 04: Hardened win_spawn::spawn_and_wait_inherit_stdio to filter invalid std handles and retry without CREATE_BREAKAWAY_FROM_JOB on ERROR_ACCESS_DENIED — discovered by new trampoline E2E test under cargo's job-object harness
- [Phase 18.5]: Plan 01: Bug #10 fixed via argv rewrite in poll.rs (not new subcommand); Bug #11 via OWL_HANDOFF_CHILD env var (not --setup, preserves inbox); Bug #12 child-side via exit code 2 + HANDOFF_DEFER stderr tag with perch state preserved; TRAMPOLINE_GUARD_ENV migrated from std::env::set_var to explicit env-forwarding through spawn helper (closes multi-threaded soundness hazard)
- [Phase 18.5]: Plan 02: wrapper consumes inner-poll exit code 2 via poll_psyche returning (exit_code, stdout); Unix uses per-key cmd.env override (no env_clear, matches Plan 01 spawn_and_wait_inherit_stdio semantics); Windows uses full std::env::vars collect + override push (CreateProcessW lpEnvironment replaces entire block when non-empty); defer-branch placed AFTER destructuring and BEFORE empty-stdout backstop so handoff signal is not mis-classified
- [Phase 18.5]: Plan 03: 4 integration tests codify Plan 01+02 contracts (DUPLICATE bypass, inbox preservation, UNDER_WRAPPER exit-2, no-handoff control); plugin 1.8.6->1.8.7 deployed via DEPLOY.ps1 -Bump patch; fake_handoff_deploy.sh literals realigned (CURRENT_VER_DIR=1.8.7, FAKE_VER=1.8.8-test); HUMAN-UAT created for Test 2 re-run
- [Phase 18.6]: Plan 01: timed-pulse scheduling reduced to persistence-only (no Psyche deliver, no detached subprocess); timed_pulse_wait module deleted
- [Phase 18.6]: Plan 01: wrapper/lifecycle.rs and wrapper/scheduler.rs timed-pulse-wait refs deferred to Plan 02 per explicit carve-out in commit 76279ed
- [Phase 18.6]: Plan 03: D-05 MSYS hardening landed — timed-pulse accepts body via stdin / --message-file / positional (in that precedence); mangling-regex guard rejects MSYS path-conversion shapes with three-transport actionable error; SKILL.md teaches escapes; 2026-04-19 MSYS todo closed
- [Phase 18.6]: Plan 03: D-05 MSYS hardening landed — three-transport body intake (positional > --message-file > stdin), regex-free is_msys_mangled guard, SKILL.md teaches escapes, 9 new tests (6 unit + 3 integration) green
- [Phase 18.6]: Plan 02: wrapper drain_due_pulses + reload_timed_pulses both fire inline to Self via deliver_body; 1h stale filter; MISSED_PULSES batch path deleted
- [Phase 18.6]: Plan 02: [PASSIVE_CONTEXT kind=...] tag convention locked; compose_passive_context helper read-only; wired into all 3 claude.rs --resume sites; psyche.md holds one general rule replacing per-block addenda
- [Phase 18.7]: [Phase 18.7 Plan 01]: NEW-ALARM-INVALID/SCHEDULED replace TIMED-PULSE-* user-visible tags; internal body text unchanged; timed_pulse_result() dropped (no caller, TimedPulseOutcome deletion in Plan 03); now_secs/persist_pulse visibility promoted for poll.rs reuse
- [Phase 18.7]: [Phase 18.7 Plan 01]: Test env isolation via unique-id-per-test (PID+nanos) not std::env::set_var(SPT_HOME) — module-local ENV_LOCK mutexes don't coordinate across modules (cleanup/hook_idle/owlery); process-global env race would clobber concurrent tests
- [Phase 18.7]: [Phase 18.7 Plan 01]: accept_one_message extracted as private helper so check_message_blocking and check_message_blocking_until(deadline) share protocol-read path (RESEARCH Pattern 1c)
- [Phase 18.7]: [Phase 18.7 Plan 02]: Listener-owned firing wired (D-01..D-08); startup scan before loop, D-03 next-epoch deadline cap, D-04 mtime-guarded cache, post-wake drain; IDLE-MODE early-return arm skips drain (D-05 startup scan covers gap on next listener start)
- [Phase 18.7]: [Phase 18.7 Plan 02]: D-10 compose_passive_context filter (epoch>now) + block omission when no future entries remain; Psyche never sees already-fired pulses even if wrapper read races listener writeback
- [Phase 18.7]: [Phase 18.7 Plan 02]: Test-env strategy rejects plan's std::env::set_var+mutex approach — Plan 01 SUMMARY flagged it as a regression class across cleanup/hook_idle/owlery ENV_LOCKs; reused unique-id-per-test pattern writing to real SPT_HOME pulses/
- [Phase 18.7]: [Phase 18.7 Plan 03]: CLI hard cutover — Commands::NewAlarm is sole timed-alarm surface; LiveCommands::TimedPulse, src/live/timed_pulse.rs, src/live/wrapper/scheduler.rs, reload_timed_pulses, drain_due_pulses call sites, TimedPulseOutcome all deleted; resume.rs:110 banner rewritten $LIVE timed-pulse -> $OWL new-alarm (D-12 user-visible); wrapper is now read-only over pulse state via compose_passive_context only
- [Phase 18.7]: [Phase 18.7 Plan 03]: Test fn rename (live_timed_pulse_subcommand_rejected -> legacy_pulse_subcommand_rejected) + explanatory comment detox in owl/mod.rs NewAlarm arm so repo-wide grep 'timed_pulse|TimedPulse|...' in src/ returns zero hits; argv literal 'timed-pulse' in test body preserved as clap-rejection regression guard; ignore guards on tests/timed_pulse_intake.rs bridge Wave 3 -> Wave 4 green
- [Phase 18.7]: [Phase 18.7 Plan 04]: plugin + binary at 1.9.0; listener-owned firing deployed; $OWL new-alarm replaces $LIVE timed-pulse; stale timed-pulse/ dir in plugin cache 1.9.0 awaits cleanup on next claude plugin install (current attempt blocked by owl.exe file lock; marketplace already clean)
- [Phase 18.7.1]: F3 direct spool self-delivery replaces TCP loopback (eliminates H-A deadlock); F4 SPT_TRACE=1 env gates all [POLL/FIRE/DRAIN]-DEBUG eprintlns via crate::trace! macro; F5 fire_entry [FIRE-ERROR]/[FIRE-PANIC] unconditional stderr
- [Phase 18.7.1]: Rule 1 bug fix — post-drain cached_mtime now guards on fired_this_iter (was unconditional on pulse_file.exists); external mid-iteration persists no longer silently swallowed by cache-stat refresh; this is the REAL 554s root cause (H-A TCP deadlock was downstream — listener never reached fire_entry because mtime-reload never triggered)
- [Phase 18.7.1]: Integration test sandbox via HOME/USERPROFILE/SPT_HOME redirect in init_sandbox() — SPT_TRAMPOLINE_GUARD=1 not sufficient (that env is checked only in main.rs startup; poll::run's in-loop handoff_available ignores it); poll + new_alarm modules promoted pub(crate)->pub for integration test access
- [Phase 18.7.1]: plugin + binary at 1.9.1; mid-iteration alarm fire regression closed via F3 spool-direct write + F4 SPT_TRACE gating + F5 panic-logging + Rule 1 cache-mtime guard fix
- [Phase 18.8]: Plan 01: Claude Code projects-dir encoding — every non-[A-Za-z0-9-] char -> '-' no collapse — shipped in owlery::encode_project_path with 3 unit tests against known-good on-machine pairs
- [Phase 18.8]: Plan 01: echo_commune unconditional cursor bump after wait_with_output (D-19 no-retry-on-empty) — empty [COMMUNE][/COMMUNE] consumes the window; only spawn-failure path skips both frame-write and bump
- [Phase 18.8]: Plan 01: atomic_write_string centralized in common::owlery (5 call sites across Plan 01+02 — above break-even); scheduler inline site left untouched this phase
- [Phase 18.8]: Plan 02: six-site cursor bump delivered — 8 actual call sites (commune x4, signoff x2, context x2) via shared write_last_commune_epoch helper; plan's 6-count acceptance criterion was plan-internal inconsistency (prose explicitly specified BOTH branches in commune.rs). All via Plan 01 shared helper — zero inline tmp+rename duplication.
- [Phase 18.8]: Plan 02: Pitfall 5 closed via init_session fs::remove_file on .last-commune-epoch at line 79, strictly before init_cmd.spawn() at line 82 — source-order line-number assertion passes. Soft-stopped-then-restarted perches no longer suppress first-fire excerpts.
- [Phase 18.8]: Plan 03: Deviated from plan literal target 1.9.1 (pre-state already 1.9.1 from Phase 18.7.1 hotfix 7bb5cc6); per user Option B, bumped to 1.9.2 for per-phase cache-path traceability and preservation of 1.9.1 as frozen 18.7.1 artifact. DEPLOY.ps1 -Bump patch atomic-committed plugin.json+Cargo.toml as e535027; follow-up c26465c synced Cargo.lock (script does not stage it). Full-sync verified 21 files plugin/spt/ -> cache/cplugs/spt/1.9.2/. Marketplace HEAD cfe1410 pushed. Task 3 UAT pending user sign-off.
- [Phase 18.8]: Plan 03: UAT approved 5/6 PASS + 1 PARTIAL; T3 [COMMUNE]-delivery empty due to pre-existing doyle-listener info.json staleness (session_id not refreshed on claude session rotation), filed as .planning/debug/doyle-listener-info-json-stale-session-id.md for separate follow-up. D-19 unconditional cursor bump validated on BOTH rich AND empty fires. Phase 18.8 observability goals (stderr capture, framed blocks, fresh-session UUIDs) all met per doyle.log evidence.
- [Phase 18.8.1]: Plan 01: claude_projects_root() helper + component-iterator impl body (sidesteps own REQ-AUDIT-01 rule); EnvSnapshot extended with claude_config_dir; dirs_home() deleted; 3 Rule-3 deviations for plan-internal contradictions between Task 1 test expected-values / helper impl / audit-needle and Task 3 audit rule — all resolved via component-iter idiom + runtime-assembled needle
- [Phase 18.8.1]: Plan 02: ExcerptSource enum replaces .unwrap_or(ExcerptStats{0,0,0}); excerpt_frame_fields + should_bump_cursor as pure helpers; IoErr(String) payload intentionally not exposed in frame header (T-18.8.1-06 mitigation — only the 3-tag set leaks); WaitFailed cursor bump stays unconditional (WR-06 orthogonal to REQ-OBS-03)
- [Phase 18.8.1]: Plan 03: pub(crate) insufficient for integration-test crate access (Rule 3 blocker) — promoted refresh_info_json_session_id + plugin_session_start mod to pub; matches Phase 18.7.1 precedent (poll/new_alarm pub(crate)->pub)
- [Phase 18.8.1]: Plan 03: TDD Task 3 RED phase collapsed — plan sequenced impl in Task 2 before tests in Task 3, so tests arrived against already-GREEN code; single test(...) commit codifies regression guard without artificial RED stub
- [Phase 18.8.1]: Plan 03: refresh placement BEFORE version_trampoline preserves 'state-first' ordering; trampoline only mutates CLAUDE_ENV_FILE, not owlery/{id}/info.json, so refresh survives any trampoline upgrade path
- [Phase 18.8.1]: Plan 04 Task 1: DEPLOY.ps1 -Bump patch atomic-bumped 1.9.6→1.9.7 (commit 3723d47), Cargo.lock synced in follow-up 62cebea per DEPLOY.ps1 contract. Marketplace pushed to cplugs HEAD 71beb08. Cache 1.9.5 sharing-violation warning (non-fatal — owl.exe still mapped); keep-set preserved 1.9.6 alongside new 1.9.7. claude plugin install succeeded.
- [Phase ?]: Phase 26-01: cwd populated uniformly at every Live-state InfoJson::new (plan-review note #7 applied)
- [Phase ?]: Phase 26-01: agent_ids schema v2 write-back deferred until next bump (D1 Q6)
- [Phase ?]: 26-04: Refuse pre-copy when new_id perch exists (clearer error than post-copy COLLISION)
- [Phase ?]: 26-04: src == new_id rejected as INVALID_FORK (prevents no-op self-overwrite)
- [Phase ?]: 26-04: memformat copy is best-effort non-fatal (psyche-download tolerates missing memformat)
- [Phase ?]: 26-03 ships pick-spec JSON contract frozen at v1; new kinds add variants, never re-shape existing
- [Phase ?]: 26-03 validates resolve <name> via id_validate BEFORE filesystem touch — security gate
- [Phase ?]: Revive pre-bumps before delegating to start::run; idempotent last-write-wins (Q2)
- [Phase ?]: Echo-commune bump wired now (not deferred to Phase 29) per Q3
- [Phase ?]: Plugin version bump deferred to user-driven docs/DEPLOY.ps1 -Bump patch
- [Phase ?]: UAT executed by user post-deploy; not gating merge (Phase 26-05)
- [Phase ?]: 26-06: Cancel from D7/D8/D9 always re-fires AskUserQuestion — never auto-launches even for kind:auto (forced-picker rule)
- [Phase ?]: 26-06: kind:auto Cancel re-entry uses a synthetic AskUserQuestion constructed from JSON id only (auto JSON lacks header/question/options/body_addendum)
- [Phase ?]: 26-06: D7 confirm-reuse body uses explicit template substitution + no-omission clause to force the model to fill in actual JSON other_repos values
- [Phase ?]: 26-06: AskUserQuestion's native free-text Other input replaces the explicit 4th Other option for both kind:pick and kind:prompt-new bullets
- [Phase ?]: 26-06: Deploy + UAT re-run deferred to user per project memory (feedback_deploy_all_files.md)
- [Phase ?]: Phase 27 Plan 02: stream-default poll behavior locked; --once is exit-gate only per D12 single-format invariant
- [Phase ?]: Author-specified golden fixtures per plan approach (a); Windows CI skips via cfg-not-windows
- [Phase ?]: Task 2 no-op: mid_iteration_alarm.rs uses prefix-only check; D9 preserves TIMED PULSE prefix
- [Phase 27 Plan 07]: Doc/hook sweep CLEAN — Sweep A all 6 patterns return 0 hits across src/ + plugin/spt/; only legitimate `re-register` mention is inside the explicit Bash-fallback clause in plugin/spt/skills/reboot/SKILL.md:45 (permitted per plan acceptance criteria)
- [Phase 27 Plan 07]: Sweep B7 revive/reboot SKILL.md classified as plan-doc mismatch (not failure) — both files mention `<EVENT>` envelopes substantively and delegate detailed envelope syntax to `/spt:listen` rather than duplicating the `type=` substring; substantive content is what matters
- [Phase 27 Plan 07]: DEPLOY.ps1 v1.9.11 ran clean — marketplace cplugs HEAD pushed to 14f29c4, cache synced to ~/.claude/plugins/cache/cplugs/spt/1.9.11/, installed_plugins.json pointer flipped via Step 9b atomic patch, Step 10 pointer assertion verified; binary version asserted `owl 1.9.11` via deployed --version
- [Phase 27 Plan 07]: Three carry-over .pending-prune-* dirs (1.9.7, 1.9.8, 1.9.9) deferred again due to in-use owl.exe sharing violations — non-fatal per documented policy; resolver-invisible (non-semver names); will reap on next deploy after handoff completes
- [Phase 27 Plan 07]: Human UAT explicitly deferred to user (NOT executor) per original GSD instructions; DEPLOY-NOTES.md has fully-templated 6-scenario UAT section with checkboxes; phase 27 stays in deploy-complete state until user sign-off
- [Phase 27 Plan 07]: /reload-plugins NOT run by executor — CLAUDE.md and docs/DEPLOY.md both stipulate this is user-controlled
- [Phase ?]: [Phase 28-01]: download_payload byte-output preserves pre-refactor println!/print! sequence exactly (no artificial newline before memformat close tag); byte-identical CLI wins over plan-prose 'ensuring newline' language
- [Phase ?]: [Phase 28-01]: strip_pulse_log kept module-private (not pub(crate)) — only download_payload_for_injection routes through it; encapsulation prevents downstream bypass
- [Phase ?]: [Phase 28-01]: strip_tests in separate submodule (not extending tests mod) — pure-string fn needs no ENV_LOCK/SPT_HOME mutation, stays off the parallel-test race code path
- [Phase ?]: [Phase 28-02]: Skipped TDD RED phase per plan body explicit waiver; existing tests bumps_live_perch + skips_non_live act as regression guard for fresh-session inject path
- [Phase ?]: [Phase 28-02]: psyche-context emit inserted between print_skill_context (resume.rs:218) and D-06 orphan_warning; block ordering locked owl-active-perch -> psyche-context -> owl_orphan_warning per Pitfall 7
- [Phase ?]: [Phase 28-03]: Combined commit Tasks 1+2 forced by cross-file dependency (Task 1 caller arity ↔ Task 2 callee signature); Phase 18.1 P03 precedent
- [Phase ?]: [Phase 28-03]: is_live derivation uses .ok().and_then().map().unwrap_or(false) inline chain — single grep target, no panic on malformed info.json (Pitfall 4)
- [Phase ?]: [Phase 28-03]: Block ordering locked — psyche-context FIRST in BOTH paths; clear/compact prepends inside additionalContext JSON envelope (Pitfall 7)
- [Phase ?]: Phase 28 Plan 04 visibility promotion: live::context module + download_payload/download_payload_for_injection helpers from pub(crate) to pub for integration-test access (Phase 18.7.1/18.8.1 precedent)
- [Phase ?]: Phase 28 Plan 04 trampoline-guard requirement: integration tests subprocess-invoking owl plugin-session-start must set SPT_TRAMPOLINE_GUARD=1 to avoid re-exec to installed plugin cache version
- [Phase ?]: [Phase 29 Plan 05]: D15 cutover complete — psyche.md echo_commune handler block + classifier + carve-out; live/listen SKILL.md envelope types 2->4; CLAUDE.md no-op; binary rebuild verified
- [Phase 30 Plan 01]: file_drop EVENT wire shape locked: `<EVENT type="file_drop" kind=... path=... from=...></EVENT>` (empty body, attr order fixed, satisfies body_is_typed_event_envelope per A5). compose_file_drop_event + scan_drop_files pub(crate) in src/owl/poll.rs.
- [Phase 30 Plan 01]: to_forward_slash extended to strip Windows UNC `\\?\` prefix (T-30-02 mitigation) so canonicalize() output is wire-safe; 3 unit tests cover UNC / non-UNC Windows / Unix passthrough.
- [Phase 30 Plan 01]: scan ordering decision locked — commune first, signoff second (Vec ordering). Signoff branch tears down the listener, so any pending commune emit must run BEFORE teardown lest it be silently dropped.
- [Phase 30 Plan 01]: Signoff teardown uses crate::owl::stop::soft_stop_perch (preserves info.json + spool.db + perch dir) per RESEARCH Pattern 1 — NOT the simpler ready-file-remove fallback. perch handle was in scope at the scan-block call site.
- [Phase 30 Plan 01]: D12 audit replaced bare `return;` at poll.rs:172 (drain-once) and poll.rs:300 (PULSE_TRIGGER emit) with explicit `std::process::exit(0);`. Other `if once { return; }` paths at 334/347/476/538 NOT changed — CONTEXT.md D12 named only those two sites and Pitfall 6 attributes user-visible 'failed' surfacing to them specifically. Scope discipline.
- [Phase 30 Plan 01]: exit(0) count in poll.rs: 6 (Ctrl+C, ready-gone, poison, signoff-teardown, drain-once, PULSE_TRIGGER). exit(1) count unchanged at 3 (DUPLICATE, TCP bind, HANDOFF_FAILED — all genuine errors preserved per D12 boundary).
- [Phase 30 Plan 01]: tests/listener_exit_code_audit.rs is canonical UNIT-LEVEL exit-code regression owner for SC5/D12. Plan 04 Task 2 Test 4 is canonical END-TO-END skill-flow integration owner. Both intentional, complementary. signoff_file_drop_teardown_returns_zero + pulse_trigger_emit_returns_zero ACTIVE; drain_once + duplicate-guard cases #[ignore]d (fixtures deferred to Plan 04) per plan-permitted carve-out.
- [Phase ?]: [Phase 30 Plan 02]: OQ1 resolution — added sibling resume_session_with_exit returning (Option<String>, i32); resume_session_checked is now a 1-line wrapper delegating to it. Zero behavior change at the 5 existing call sites.
- [Phase ?]: [Phase 30 Plan 02]: Signoff branch routes via final_session(envelope) directly (not resume_session_with_exit). Treats final_session return as exit-0 success for D8 delete decision; final_session logs exit code internally.
- [Phase ?]: [Phase 30 Plan 02]: Dual-entry disjointness with line-429 init_signoff predicate locked — file_drop signoff wire form lowercased does NOT contain 'init_signoff' substring (kind=signoff uses bare token, never underscored compound). file_drop_signoff_wire_form_disjoint_from_init_signoff unit test enforces T-30-23.
- [Phase ?]: [Phase 30 Plan 02]: parse_file_drop_event validation is three-deep — kind whitelist (T-30-08), path -{kind}.md suffix (T-30-07), /.claude/ containment (T-30-09 stale-emit defense). All cheap string checks before fs::read_to_string.
- [Phase ?]: [Phase 30 Plan 02]: Task 2 ships process_file_drop as a stub so the FileDropDispatcher trait impl compiles; Task 3 expands the stub into the full read/compose/resume/delete-or-retain decision tree. Three-commit cadence preserves task atomicity.
- [Phase ?]: [Phase 30 Plan 03]: append_pending_sections helper takes cwd as parameter for parallel-test safety; strip_pulse_log unchanged (D11b by line-anchor disjointness); SC6 OWNERSHIP split — Plan 03 = unit-level canonical (9 in-process tests); Plan 04 Task 2 Test 5+6 = real-std::env::current_dir() canonical (subprocess-based).
- [Phase ?]: [Phase 30 Plan 04]: signoff/SKILL.md argument-hint set to empty string matching clear-psyche/psyche-download precedent (T-30-24 mitigation; key NOT deleted outright per schema-safety policy)
- [Phase ?]: [Phase 30 Plan 04]: tests/file_drop_integration.rs ships 8 #[test] defs (4 enabled — scan_emit / signoff_exit_zero / psyche_download_pending_commune / psyche_download_both — plus 4 documented #[ignore]'d with canonical-coverage cross-references to Plan 02 file_drop_handler_tests)
- [Phase ?]: [Phase 30 Plan 04]: DEPLOY.ps1 + UAT deferred to orchestrator per spawn-time directive; SUMMARY ships UAT-1..UAT-5 runbook (commune flow, psyche-download append, signoff teardown, retain-on-error, CLI backward-compat) for orchestrator to relay
- [Phase ?]: [Phase 30 Plan 04]: Test 1 uses --pulse-interval 3 so listener exits via PULSE_TRIGGER (D12 exit 0) rather than relying on outer Command::timeout kill (which yields non-zero exit on Windows signal-terminate)
- [Phase ?]: [Phase 31-01]: PICK-03 deferred to v1.8+ per D-10/D-11 — doc-only strike + ROADMAP success-criterion 2 trimmed to D5-only; plan-internal contradiction (footer-note directive vs grep-zero criterion) resolved by 'former PICK item #3' rewording; Phase 26 LIVE-PICK-03 substring retained per scope discipline; atomic per-task commits 8070d33 + 33aecc2
- [Phase ?]: Phase 31-02: emit_all_live cwd-match uses std::fs::canonicalize equality (matches build_resolve_spec pattern)
- [Phase ?]: Phase 31-02: emit_all_live caps options at take(3) for D-05 symmetry with emit_pick
- [Phase ?]: Phase 31-02: build_pick_spec guards state.ids.is_empty() BEFORE offline.len() match (PITFALL 1)
- [Phase ?]: Phase 31-02: single combined commit per Task 2 step (4) explicit subject+3-file scope (deviation from per-task default)
- [Phase 35-05]: UserPromptSubmit async-pull dispatch appended AFTER both branches' output_hook_response (orthogonal-hook posture, Phase 25.4 / hook_idle.rs:62-82); no-early-return Test 3 kept strict-zero (run() had zero `return;` statements pre-edit — its no-perch guard is a `None => return,` match arm)
- [Phase ?]: [Phase 34-01] CHANGELOG.md authored 38 H2 entries (v1.5.4 to v1.10.10) per CONTEXT D-09; Keep-a-Changelog 1.1.0 format validated against Plan 02 parser regex
- [Phase ?]: [Phase 34-01] DEPLOY.ps1 stub-append runs AFTER git commit (RESEARCH Pitfall 5) -- stub stays unstaged, next -Bump abort gate fires until author commits
- [Phase ?]: [Phase 34-01] DEPLOY.ps1 abort gate triggers on missing CHANGELOG.md (not just stale TODO marker) -- file is now a hard -Bump prerequisite
- [Phase ?]: [Phase 34-01] CHANGELOG sync targets {Marketplace}/plugin/spt/CHANGELOG.md AND {CacheVer}/CHANGELOG.md sibling to plugin.json (NOT inside .claude-plugin/) per CONTEXT D-11
- [Phase ?]: [Phase 34-02 Task 3] tests/version_changelog.rs `base_hook_idle_cmd` env_removes OWL_SESSION_ID + OWL_HANDOFF_CHILD + OWL_SKIP_RESUME -- cargo-test inherits Claude Code session UUID via OWL_SESSION_ID, which overrides stdin session_id at hook_idle.rs and breaks perch resolution (same fix class as tests/auto_pick_integration.rs base_cmd)
- [Phase ?]: [Phase 34-02 Task 3] integration test stdin payloads carry {"session_id":"test-session"} (or "test-session-live") so perch lookup uses the session-match fast path; `{}` falls through to parent_pid match which fails on Windows because get_parent_pid walks the ancestor chain to claude.exe rather than the cargo-test runner
- [Phase ?]: Plan 23-05 reused canonical id_validate::validate_agent_id helper — validate_agent_id covers all hostile-input categories (path traversal, separators, shell metachars, whitespace, control chars, empty, length cap) — no new private validate_simple_id was needed. Same helper used by src/live/fork.rs for INVALID_SRC: / INVALID_NEW_ID:.
- [Phase ?]: Plan 23-05 round-trip test uses synthetic stamped content rather than git-init-in-tempdir — Spawning git in a tempdir requires set_current_dir which races against other lib-suite tests under cargo's parallel runner. Plan 01 Deviation 1 documented exactly this — 8 false failures induced by chdir-based tests. Synthetic stamped content (mirroring Plan 04's download_directive_suppressed_by_marker setup) exercises the same download_payload drift-detection code path with zero global mutation.
- [Phase ?]: Phase 24-01 foundation: tracked module + commit_trailers renderer + structured GitError primitive
- [Phase ?]: Plan 24-02 — ensure_worktree shared via WorktreeScope enum; D-18 dedup updates ts in place
- [Phase ?]: Phase 24-03: Routed all four write-path call sites (context/echo/daemon-log/fork) into agents/{id}/ worktrees through tracked::commit_payload pipeline with D-07 subject + D-08 trailers; NO git push (D-13 amendment); explicit timeout: Duration arg per iter-1 WARNING 1
- [Phase 24-05]: migrate_legacy_if_needed wired into ensure_seed at BOTH cold-path (seed_existed_before=false → "import legacy flat layout" subject) and fast-path (seed_existed_before=true → "(orphan recovery)" suffix per Pitfall 4). Thread-local MIGRATION_IN_PROGRESS re-entry guard (RAII Reset Drop impl) breaks the ensure_seed→migrate→ensure_agent_worktree→ensure_seed recursion. Migration commits via commit_agent_payload_with_timeout(.., 2000ms) — sole standard-code call site of the extended budget per WARNING 1 iter-1.
- [Phase 24-05]: Rename-error fallback generalized beyond ErrorKind::CrossesDevices (unstable in stable Rust): any rename Err triggers copy+remove. Symlink rejection via fs::symlink_metadata + file_type.is_symlink() BEFORE rename (T-24-05-04); Phase 23-era tracked/.git/ preserved through migration (Pitfall 6 — directories skipped at depth=1 scan).
- [Phase 24-05]: RED+GREEN combined into single feat(...) commit (tests reference to-be-implemented symbol, separate test: commit would not compile, breaking per-commit hygiene). 9 new tests (8 universal + 1 Unix-only #[cfg(unix)] symlink test). 620 lib tests pass (was 612).
- [Phase ?]: 24-06: use worktree-list-porcelain prunable marker as canonical orphan source (D-05 silences worktree prune --dry-run on git 2.43/Windows)
- [Phase ?]: 24-06: --fix orphan prune uses --expire=now to override D-05 locked gc.worktreePruneExpire=never
- [Phase ?]: 24-06: subtract bootstrap commit from LocalOnly count via saturating_sub so fresh worktrees collapse to Clean
- [Phase ?]: Phase 24.1 Plan 01 foundation primitives added
- [Phase 24.1 Plan 02]: Tracked-side helpers landed in src/common/owlery.rs — tracked_agent_info_path (D-15 path resolver, no mkdir), bump_tracked_agent_info (D-06/D-07/D-08/D-09/D-10/D-12 honored, ensure_agent_worktree first per Pitfall 4, atomic write, returns bool for write-amp guard), read_tracked_agent_info_or_fallback (tracked-first / perch-fallback with mixed-shape tolerance), TrackedAgentInfoSummary (lightweight projection for doctor/listings), append_history_entry + normalize_legacy_strings_to_objects (shared primitives — One helper, two flavors via Option<&str> branch)
- [Phase 24.1 Plan 02]: append_project_history upgraded in place to record shape — signature gained branch: &str + bool return; W1 closure locks `changed` semantics to pre/post Value comparison; normalize-before-dedup (Pitfall 5); atomic_write_string replaces std::fs::write (D-12 symmetry / Open Question 1 closure — closes Phase 32 partial-write window)
- [Phase 24.1 Plan 02]: CONTRACTED build break — cargo build --release fails with exactly 2 signature-mismatch errors at src/owl/poll.rs:135 and src/live/start.rs:281 (Plan 03 fixes). All 17 owlery-cluster tests that DO compile pass: 7 Task 1 + 10 Task 2; Task 3 tests compile but cannot link until Plan 03 lands. Net-new test surface: +24 (7+10+7 net-new minus 7 pre-existing test maintenance migrations)
- [Phase 24.1 Plan 02]: perch_has_repo_history + perch_has_any_repo_history reader upgrade DEFERRED to Plan 04 — the existing Phase 32 as_str-based reader continues to find legacy String entries; new Object entries written by the upgraded append_project_history are temporarily invisible to these readers. Test migration seeds legacy String entries directly via raw JSON inject to preserve regression-guard semantics; scope-preserving choice consistent with Plan 02's single-file invariant
- [Phase ?]: [Phase 25.1 Plan 01]: Sentinel <project-context-resolved name="..."/> emission added to download_payload() — Shape A (XML self-closing) chosen over Shape B (H2 header) for symmetry with existing <psyche-stamp/> / <current/> tags and zero collision with Psyche-LLM H2s in project body; sentinel gated by same 3 guards as project body push (cwd_project + file exists + read succeeds); download_payload_for_injection inherits via Phase 25 D-15 single-producer rule (no separate edit).
- [Phase ?]: [Phase 25.1 Plan 01]: TDD task — RED 6a71c6d (2 failing tests) + GREEN 5717e2b (sentinel emission); REFACTOR skipped (minimal impl). Pre-existing parallel-test flake (38-41 failures across owl::* unrelated to live::context::tests) confirmed out-of-scope per PROJECT.md known issue; all 56 live::context::tests green.
- [Phase ?]: [Phase 25.1 Plan 02]: commune/SKILL.md teaches two-slice envelope contract via new ## Two-slice body shape (Phase 25 D-10/D-11) section; in-project detection keyed deterministically on <project-context-resolved sentinel from Plan 01; three behavior rules cover D-25.1-01..03; silence on untagged fallback (D-25.1-07) honored; taxonomy linked to psyche.md not paraphrased
- [Phase ?]: [Phase 25.1 Plan 03]: commune.md teaches two-slice envelope contract end-to-end via new section, Memformat reframe, three worked examples, and routing sub-bullet — D-25.1-01..04, D-25.1-07, D-25.1-08 all operationalized; Rule 1 deviation reworded 'safety net' -> 'backstop' in pre-existing Commune Diligence section to honor silence-rule grep gate
- [Phase ?]: [Phase 25.1 Plan 03]: Detection rule prose uses substring-presence ('<project-context-resolved') not exact-tag-match — robust to future attribute additions; consistent with Plan 02 phrasing
- [Phase ?]: [Phase 25.1-04]: Cross-link to /spt:commune for full two-slice teaching rather than duplicating three worked examples — signoff/SKILL.md stays concise; drift hazard eliminated by single-source-of-truth at /spt:commune.
- [Phase ?]: [Phase 25.1-04]: Plain-signoff empty-body path explicitly preserved as distinct from two-slice contract — empty file body is NOT a two-slice body; carve-out flagged in the new section third bullet.
- [Phase ?]: [Phase 25.1 Plan 05] echo_commune envelope catalog entry at live/SKILL.md:268 teaches Phase 25 D-10/D-11 two-slice body shape via cross-link to /spt:listen (parsing) and /spt:commune (authoring) — no rule duplication, four-shape catalog preserved
- [Phase ?]: Plan 25.1-06: revive/SKILL.md gains ## Echo-commune brief (post-revive) H2 section; 4 net lines added; cross-links /spt:live + /spt:listen; cites D-25.1-05 two-slice one-brief-absorption; silent on untagged fallback per D-25.1-07; all 6 grep gates pass
- [Phase ?]: Phase 25.2-01: Form B reader/writer split per Q2 RESOLVED
- [Phase ?]: Phase 25.2-01: read_wrapper_state_with_retry_with_budget is pub so integration tests exercise shortened-budget exhaustion without 20s real waits
- [Phase ?]: Phase 25.2-01: filetime stays absent — stale-lock test uses std::fs::File::set_modified (Rust 1.75+) per CLAUDE.md zero-runtime-dep posture
- [Phase ?]: Plan 25.2-02: drain_stale_signoff_file forwards <EVENT type=latent signoff> to {id}-psyche via TCP/spool; file deleted only after deliver returns Ok (D-10 deliver-then-die).
- [Phase ?]: Plan 25.2-02: D-12 invariant guarded via debug_assert! in production + in-module Test C (predicate-level) + integration Test D (envelope-string level).
- [Phase ?]: [Phase 25.2 Plan 03]: Ghost tracked/.git/ cleanup landed via unconditional best-effort remove_dir_all inside migrate_legacy_if_needed. No sentinel — RESEARCH §#2 Idempotency. Test inverted to migrate_legacy_removes_ghost_dot_git + idempotency companion added.
- [Phase ?]: [Phase 25.3-01]: info.json cwd is single source of truth for project name resolution (locked decision #2)
- [Phase ?]: [Phase 25.3-01]: resolve_self_project_name_via_info_cwd lives in owlery.rs pub(crate); CURRENT_PROJECT_CONTEXT header carries (name=X) debug token
- [Phase ?]: 25.3-03: LLM stdin boundary helper (compose_llm_prompt_from_envelope) applied INSIDE resume_session_with_exit + final_session — single edit point catches all callers; idempotent fallthrough makes raw PULSE_TRIGGER paths safe
- [Phase ?]: 25.3-03: ENCODING CONTRACT doc lives at top of src/owl/poll.rs as a single 80-line block (within plan's extraction threshold; no separate encoding.rs needed)
- [Phase ?]: 25.3-03: end-to-end test placed INLINE per cycle-4 PARTIAL fallback (clause c) — no clean public seam to capture LLM stdin from subprocess; helper-driven INLINE test is pure-function equivalent
- [Phase ?]: [Phase 25.3-02]: psyche.md <absorption> section added (rules 1-6) - Option A no-name shape locked across psyche.md + commune.md + signoff/SKILL.md; SPT routes the envelope, LLM emits only
- [Phase ?]: [Phase 25.3-02]: Consolidated deploy of Plans 25.3-01+03+02 at v1.11.5 - minimizes binary-handoff churn during in-flight psyche-wrapper migrations
- [Phase ?]: [Phase 25.3-02]: Static prompt-contract tests placed in tests/native_owl.rs use ONLY include_str! + std::fs::read_to_string (no pub(crate) calls) - integration-crate placement correct per cycle-4 HIGH 4
- [Phase ?]: [Phase 25.3-05]: D-E-01 single-writer contract LOCKED — psyche-download is READ-ONLY over .claude/{id}-{commune,signoff}.md; wrapper's process_file_drop is sole deleter
- [Phase ?]: [Phase 25.3-05]: D-E-04 strip_ansi at log sink (not NO_COLOR env propagation) — single concern at the SINK; trivially testable
- [Phase ?]: [Phase 25.3-05]: D-E-05 Rule 3 deviation — note relocated from deleted plugin/spt/skills/psyche-download/SKILL.md to plugin/spt/skills/live/SKILL.md (quick-260518-2d6 consolidation)
- [Phase ?]: [Phase 25.3-05]: D-E-07 revised HAPPY-PATH-ONLY — wrapper post-LLM-exit hook + 3 call sites + RefCell re-entry guard; G2 self-heal SPLIT to Plan 25.3-06 per cycle-3 plan-checker
- [Phase ?]: [Phase 25.3-05]: cycle-3 B1 fix — llm-after-llm both succeed; route_two_slice_with_precedence_llm_after_llm_writes_both invariant test locks should_suppress_llm_write contract
- [Phase ?]: [Phase 25.3-05]: cycle-3 B4 fix — WrapperState.live_ctx_route_in_flight: RefCell<bool> + hand-rolled ReentrancyGuardSentinel Drop sentinel (no scopeguard dep)
- [Phase ?]: [Phase 25.3-05]: Task 10 deploy + UAT deferred to operator per CLAUDE.md project policy
- [Phase ?]: [Phase 25.3-06]: D-G2-01 Locked — G2 self-heal fires ONLY when all three: (a) parse_two_slice project None, (b) resolve_self_project_name_via_info_cwd Some, (c) last_prompt contains CURRENT_PROJECT_CONTEXT
- [Phase ?]: [Phase 25.3-06]: D-G2-02 Locked — Re-entry via Plan 25.3-05 live_ctx_route_in_flight RefCell guard; NO allow_respawn parameter; inner respawn re-invocation early-returns SkippedReentrancyGuard
- [Phase ?]: [Phase 25.3-06]: D-G2-03 Locked — ResumeRespawnDispatcher trait test seam mirrors FireDispatcher + FileDropDispatcher; production impl delegates to resume_session_with_exit; TestResumeRespawn mock writes configurable body on call
- [Phase ?]: [Phase 25.3-06]: D-G2-04 Locked — Corrective prompt literal contains 'did not honor the two-slice envelope contract' as test anchor + cites psyche.md absorption rule 4
- [Phase ?]: [Phase 25.3-06]: Hook sites pass: init_session Some(init_msg) self (G2 never fires), resume_session_with_exit Some(timestamped) self (full LLM-stdin prompt), final_session None self (exit path G2 never fires)
- [Phase ?]: [Phase 25.3-06]: Generic D: ResumeRespawnDispatcher bound chosen (NOT &dyn) mirroring handle_fire_echo_commune_arm pattern; single production caller per site
- [Phase ?]: [Phase 25.3-06]: Deploy v1.11.7 to v1.11.8 deferred to operator per project policy + Plan 25.3-05 precedent; plugin.json still at v1.11.6 because 25.3-05 deploy also pending
- [Phase ?]: [Phase 25.4-01]: perch_path resolver module landed; PerchKind classifier (suffix-based, worker-first agreement with owlery::is_worker_perch pinned by test); ParentHint::Explicit/Infer (explicit preferred per D-04); 4 child-file helpers; 25 inline unit tests passing
- [Phase ?]: [Phase 25.4]: Plan 02 landed ready-file landmine regression test BEFORE Wave 2 — pins wrapper/mod.rs:1168 loop-exit predicate (CONTEXT D-06); two tests pass via SPT_HOME tempdir sandbox + ENV_LOCK pattern
- [Phase ?]: Plan 25.4-03: poll.rs perch-path composition routed through perch_path resolver via new --parent flag; wrapper passes --parent <self_id>, Self listener passes None (flat via Infer + PerchKind::Self_)
- [Phase ?]: [Phase 25.4-05]: wrapper-state.json writers nested-canonical (3 sites migrated to write_wrapper_state_at); reader wrapper_state_path_resolved UNCHANGED per CONTEXT D-03 (one deploy cycle's handoff transition safety margin); legacy id-based fns deprecated and routed via ParentHint::Infer
- [Phase ?]: [Phase 25.4-06]: Test-fixture migration is mandatory when migrating readers — flat-write + nested-read silently breaks tests; migrated commune/signoff/cleanup test fixtures in lockstep with production readers
- [Phase ?]: [Phase 25.4-06]: stop.rs run_single/run_all NOT migrated — plan-speculated additional Class-E sites don't exist; grep confirmed only line 18 has id-based perch composition
- [Phase ?]: [Phase 25.4-06 D-09 resolved]: live/stop.rs:18 kill_psyche_wrapper now symmetric with wrapper/lifecycle.rs:127 — both use resolver-routed nested cleanup; flat path no longer special-cased
- [Phase ?]: [Phase 35-01]: Sync namespace persists at $SPT_HOME/settings.json (NOT ~/.claude/settings.json, Pitfall 7) — separate from auto_setup's claude-code file
- [Phase ?]: 35-01: write_sync_settings splices only the sync key via serde_json::Map::insert; preserve_order keeps sibling top-level keys intact
- [Phase ?]: 35-01: SyncSettings timestamps stay Option<String> ISO-8601 (no chrono parse); compared lexicographically downstream
- [Phase ?]: [Phase 35-03]: spawn_detached_unix uses single-fork+setsid (not double-fork) — claude-code hook short-lived so zombies reap via init; returned pid is the actual child
- [Phase ?]: [Phase 35-03]: Unix mirror drops the envs param vs win_spawn::spawn_detached_no_inherit — Plan 35-05 cfg-splits the call site (RESEARCH Open Q 1)
- [Phase ?]: [Phase 35-02]: classify_and_record_outcome takes &Result<T,GitError> by reference; GitError not Clone (E0204); no Clone derive added (B1 Resolution C)
- [Phase ?]: [Phase 35-02]: pull_branch uses two-step fetch+rebase -X theirs, never git pull --rebase (Pitfall 4)
- [Phase 35-04]: Sync remote URL is HTTPS (no SSH key prereq) — RESEARCH Open Q2 researcher recommendation
- [Phase 35-04]: plugin.json carries no skills array (auto-discovered); SKILL.md enumeration step was a verified no-op
- [Phase ?]: test
- [Phase ?]: [Phase 35-07]: D-08 sync-prompt predicate owned by plugin_session_start.rs, reused by sync.rs queue_sync_prompt_if_due; single binary crate so no module-cycle inversion needed
- [Phase ?]: [Phase 35-08]: recovered_aborts bump moved to abort_stale_rebase call site — single source of truth
- [Phase ?]: [Phase 35-06]: Post-commit sync hook soft-failed via let _ = ... at both commit_*_payload sites (D-14); sync failure never blocks durable local commit
- [Phase ?]: [Phase 35-06]: ensure_*_worktree wires origin via maybe_add_origin after inner ensure_worktree (D-10 step 5); Phase 24 D-13 no-push doc-comment amended
- [Phase ?]: [Phase 35-09]: Promoted GitError pub(crate)->pub (and git module to pub) — public sync::pull_branch/push_branch signatures leaked the crate-private error type, blocking external integration-test crates
- [Phase ?]: [Phase 35-09]: 4 fake-bare-remote integration tests (6 fns) give Phase 35 CI-green-bar coverage; operator two-machine UAT (35-OPERATOR-UAT.md) is the remaining milestone-close gate
- [Phase ?]: [Phase 35.1-01]: Routed all 8 production info.json writers through owlery::atomic_write_string; test-only sites under #[cfg(test)] left untouched.
- [Phase ?]: [Phase 35.1-02]: Both new owlery symbols gated behind #[allow(dead_code)] until Plan 03 wires callers; narrowly-scoped to keep release build warning-clean during Wave 1.
- [Phase ?]: [Phase 35.1-03]: list_filter::collect() is now signature-pure read-only — cleanup_orphans param removed entirely; orphan_count field added; wrapper-alive + 60s grace gates classify without mutating; orphan-count hint emitted in $OWL list only.
- [Phase ?]: [Phase 35.1-03]: Added #[cfg(test)] PHASE35_LIST_ORPHAN_GRACE_OVERRIDE + resolver in owlery.rs mirroring SWEEP_GRACE_OVERRIDE — unit tests collapse grace without 60s sleeps.
- [Phase ?]: Phase 35.1 closure: doctor --fix is sole authorized orphan-dir GC; nested orphans soft-clean, top-level hard-delete; SAFETY GUARD refuses cascade-wipe of Layer-1 dirs with non-empty nested/ subtree
- [Phase ?]: Plan 35.1-04 doctor.rs Gate B uses phase35_list_orphan_grace_secs() resolver (Plan 03) rather than raw const — keeps doctor + list_filter on the same test-aware resolver path
- [Phase ?]: [Phase 35.2-01]: ensure_seed commit-tree -> inline Command with GIT_*_DATE locked to 1970-01-01T00:00:00Z for byte-identical cross-machine main SHA (SYNC-BOOTSTRAP-DET-01)
- [Phase ?]: [Phase 35.2-02]: reconcile_against_remote rebases in the branch's linked worktree, not the bare seed (git rebase requires a work tree).
- [Phase ?]: [Phase 35.2-02]: reconcile_against_remote is bare pub (not pub(crate)) so the tests/ integration crate can call it (E0603); matches pull_branch/push_branch.
- [Phase ?]: [Phase 35.2-03]: accept_flow returns (String, Vec<PerRefOutcome>); per-ref push origin b:b replaces push --all, skipped on RebaseFailed; dispatcher emits PUSHED/RECONCILED/DIVERGED/PUSH_FAILED status tags. Phase 35.2 data-loss surface closed.
- [Phase ?]: [Phase 35.3-04]: psyche-sync-setup recovery docs kept INLINE in SKILL.md (D-08, no sibling doc/ADR); manual seed/rebase is a one-line last-resort pointer only since Phase 35.2 per-ref dispatcher obsoletes the git update-ref workaround
- [Phase 35.3-03]: doctor sync:partial Warn row probes the bare seed repo config (seed/config) for an origin remote when state==Unset, with a 500ms-bounded ls-remote check via the promoted pub(crate) run_git_with_timeout — surfaces half-succeeded setup (D-03..D-07, Warn-only)

### Pending Todos

10 pending todos (areas: tooling, capsule, psyche, live) -- see .planning/todos/pending/
*(2026-04-20: +1 — auto-fire echo commune on SessionStart and wrapper self-exit [psyche])*
*(2026-04-20: +1 — fix perform_wrapper_handoff stale pid in psyche-wrapper pidfile [psyche]) — COMPLETED same-day in SessionEnd cleanup-session fix*
*(2026-04-21: +1 -- rebounder executable trampolines OWL/LIVE to latest spt binary [tooling])*

### Roadmap Evolution

- Phase 18.1 inserted after Phase 18: Various improvements — fix owl list count, psyche resume injection, psyche tool limitations, stop-hook commune, deferred delivery, PULSE_TRIGGER recovery, revive listener gap, TCP spool timeout (INSERTED)
- Phase 18.2 inserted after Phase 18: Relocate spacetime out of ~/.claude to %APPDATA%/.spt (Psyche Write permission blocker) — URGENT (INSERTED)
- Phase 18.4 inserted after Phase 18: Seamless binary handoff after plugin marketplace update for long-running spt processes (listener poll, psyche wrapper) (URGENT) (INSERTED)
- Phase 18.5 inserted after Phase 18: Handoff bug fixes — listener argv, duplicate check, wrapper inner-poll preempt (URGENT, closes 18.4 UAT gaps for bugs #10/#11/#12) (INSERTED)
- Phase 18.6 inserted after Phase 18.5: Refactor scheduled pulses — wrapper delivers to Self (not Psyche), Psyche gets passive awareness via routine stdin only, scheduling never wakes Psyche, reload never batches MISSED_PULSES to Psyche (URGENT, root-caused 2026-04-19 incident: waiter killed by Bash tool Job Object AND MISSED_PULSES mis-routed to Psyche triggered wrong-agent /gsd-plan-phase 19 execution) (INSERTED)
- Phase 18.8 inserted after Phase 18: echo-commune stderr capture (no retry-on-empty) and refactor to fresh session with jsonl excerpt — closes silent-drop observability gap AND eliminates Self-session contention race class (URGENT, root-caused 2026-04-20 from doyle.log investigation: sdk-cli haiku subprocess posted user turn to shared Self jsonl but never got assistant response while foreground opus wrote to same jsonl 2s later; stderr suppressed at echo_commune.rs:99 made failures invisible) (INSERTED)
- Phase 18.8.1 inserted after Phase 18.8: ccs-aware projects path + excerpt ENOENT observability + info.json session rotation refresh (URGENT, root-caused 2026-04-21 from witty.log line-37 investigation: ccs CLI sets CLAUDE_CONFIG_DIR=~/.ccs/instances/<account>/ relocating Claude projects dir; echo_commune.rs hardcodes ~/.claude/projects/ so ccs-launched agents always hit ENOENT on self_jsonl; .unwrap_or(ExcerptStats{0,0,0}) at echo_commune.rs:100-110 silently masks the failure; doyle stale-info.json rotation bug is separate but related -- bundled here to close both classes) (INSERTED)
- Phase 18.7 inserted after Phase 18.6: Relocate timed-pulse firing from Psyche wrapper to Self listener — drain_due_pulses + reload_timed_pulses move into src/owl/poll.rs with sentinel-aware wake; wrapper keeps only compose_passive_context (read-only, filtered to epoch>now) for Psyche awareness; scheduler bumps wake sentinel after persist; skill renamed /spt:timed-pulse → /spt:new-alarm (timed-pulse naming only made sense under wrapper-firing model) (URGENT, 18.6 UAT revealed unacceptable fire latency — pulses deferred to 20min routine poll tick instead of firing near target epoch) (INSERTED)
- Phase 28.1 inserted after Phase 28: Commune/signoff file-drop protocol — agents write .claude/{agent_id}-{commune|signoff}.md, listener poll forwards to psyche wrapper via REST, psyche-download appends pending file content (URGENT)
- Phase 30 added: Commune/signoff file-drop protocol — agents write .claude/{agent_id}-{commune|signoff}.md, listener poll forwards to psyche wrapper via REST, psyche-download appends pending file content. Moved from initial insert as 28.1 — properly slotted at end of v1.7 milestone.
- v1.7.1 Seamlessification II opened 2026-05-16: 4 phases (31-34), 42 requirements, derived from research SUMMARY.md grouping. Phase 31 (PICK fix) lands first to unblock Phase 33 dependents. Single end-of-milestone DEPLOY.
- Phase 25.1 inserted after Phase 25: Revise /commune + /signoff skill docs + echo commune instruction to split commune into project-specific vs agent general (phase 25 psyche context alignment) (URGENT)
- Phase 25.2 inserted after Phase 25.1: Doyle cluster fix candidates — blast radius sanity check across SPT listener wrapper and tracked-repo paths (URGENT)
- Phase 25.4 inserted after Phase 25: Perch-path single-source-of-truth — finish D-01 nested migration (URGENT)
- Phase 35.1 inserted after Phase 35: owl-list-data-loss-cqrs-decouple-orphan-detection-hardening-nested-perch-soft-clean (URGENT)

### Blockers/Concerns

_active. Legacy MCP/Phase-15 blockers cleared 2026-05-17 — MCP transport stripped in 260414-28p; CLI-first model adopted; no longer applicable._

- Phase 35 close-gate: operator must execute 35-OPERATOR-UAT.md (two-machine real-GitHub) and record PASS in 35-OPERATOR-UAT-RUN.md before phase is closeable

### Quick Tasks Completed

| # | Description | Date | Commit | Directory |
|---|-------------|------|--------|-----------|
| 260413-6p7 | Fix plugin hooks to use CLAUDE_PLUGIN_ROOT instead of OWL env var | 2026-04-13 | 7a8334c | [260413-6p7-fix-plugin-hooks-to-use-claude-plugin-ro](./quick/260413-6p7-fix-plugin-hooks-to-use-claude-plugin-ro/) |
| 260413-7bt | Update skill docs to reference MCP tools and fix missing background listener on live start | 2026-04-13 | 6da5af9 | [260413-7bt-update-skill-docs-to-reference-mcp-tools](./quick/260413-7bt-update-skill-docs-to-reference-mcp-tools/) |
| 260413-8k0 | MCP messaging tools should return simple confirmations not echo message body | 2026-04-13 | d798875 | [260413-8k0-mcp-messaging-tools-should-return-simple](./quick/260413-8k0-mcp-messaging-tools-should-return-simple/) |
| 260414-28p | Strip MCP transport layer, keep spool/hook/rename improvements, restore CLI-first skill docs | 2026-04-14 | bab876c | [260414-28p-strip-mcp-transport-layer-keep-spool-hoo](./quick/260414-28p-strip-mcp-transport-layer-keep-spool-hoo/) |
| 260414-3kp | Rename remaining STASH_FINAL to INIT_SIGNOFF across codebase | 2026-04-14 | 2354ea1 | [260414-3kp-rename-remaining-stash-final-to-init-sig](./quick/260414-3kp-rename-remaining-stash-final-to-init-sig/) |
| 260414-4dl | Fix poll loop spool drain-respool race with hook and remove subagent idle-ready clearing on parent | 2026-04-14 | 9f48394 | [260414-4dl-fix-poll-loop-spool-drain-respool-race-w](./quick/260414-4dl-fix-poll-loop-spool-drain-respool-race-w/) |
| 260414-7kj | Rebuild and deploy owl binary to fix stale MCP references (deferred — 18.1 unbuildable) | 2026-04-14 | — | [260414-7kj-rebuild-and-deploy-owl-binary-to-fix-sta](./quick/260414-7kj-rebuild-and-deploy-owl-binary-to-fix-sta/) |
| 260414-8co | Wire deferred delivery into SubagentStart hook messages | 2026-04-14 | 5e4e80d | [260414-8co-wire-deferred-delivery-into-subagentstar](./quick/260414-8co-wire-deferred-delivery-into-subagentstar/) |
| 260414-8ip | Add info priority to informational owl messages | 2026-04-14 | 82ed5cf | [260414-8ip-add-info-priority-to-informational-owl-m](./quick/260414-8ip-add-info-priority-to-informational-owl-m/) |
| 260414-915 | Bake no-sleep-before-read lesson into listener skills | 2026-04-14 | 5b3c2dd | [260414-915-bake-no-sleep-before-reading-background-](./quick/260414-915-bake-no-sleep-before-reading-background-/) |
| 260414-9an | UserPromptSubmit: check spool for undelivered messages on every prompt | 2026-04-14 | 4da7325 | [260414-9an-userpromptsubmit-check-spool-for-undeliv](./quick/260414-9an-userpromptsubmit-check-spool-for-undeliv/) |
| 260415-txh | DEPLOY.md: bump installed_plugins.json gitCommitSha after cache wipe to prevent plugin orphan | 2026-04-15 | 74d1086 | [260415-txh-update-docs-deploy-md-after-the-cache-re](./quick/260415-txh-update-docs-deploy-md-after-the-cache-re/) |
| 260415-ujn | SessionStart hook syncs OWL/LIVE into settings.json to mitigate Anthropic #27987 on Windows | 2026-04-15 | 16e4338 | [260415-ujn-sessionstart-hook-syncs-owl-live-into-se](./quick/260415-ujn-sessionstart-hook-syncs-owl-live-into-se/) |
| 260415-vec | DEPLOY.ps1 script automates spt deploy steps for agent-driven deploys (skips /reload-plugins) | 2026-04-15 | 120ba2c | [260415-vec-create-a-deploy-ps1-which-agents-can-run](./quick/260415-vec-create-a-deploy-ps1-which-agents-can-run/) |
| 260416-1lc | Migrate remaining taskkill subprocess calls to TerminateProcess Win32 API | 2026-04-16 | 305c29a | [260416-1lc-migrate-remaining-taskkill-subprocess-ca](./quick/260416-1lc-migrate-remaining-taskkill-subprocess-ca/) |
| 260416-4y2 | Fix Psyche permission on context/memformat files by setting claude subprocess cwd to tracked dir and correcting psyche.md paths | 2026-04-16 | f088b0e | [260416-4y2-fix-psyche-permission-on-context-memform](./quick/260416-4y2-fix-psyche-permission-on-context-memform/) |
| 260418-7k9 | Wrapper auto-commit for psyche context changes | 2026-04-18 | 2373d43 | [260418-7k9-wrapper-auto-commit-for-psyche-context-c](./quick/260418-7k9-wrapper-auto-commit-for-psyche-context-c/) |
| 260418-mni | Dynamic short-pulse override in Psyche wrapper for echo commune gate crossing | 2026-04-18 | ab9fd14 | [260418-mni-dynamic-short-pulse-override-in-psyche-w](./quick/260418-mni-dynamic-short-pulse-override-in-psyche-w/) |
| 260418-n7k | SubagentStart [WORKING_PERCH_NOTICE] still wakes poll listener — fix deferred delivery wake-up path | 2026-04-18 | 47fe073 | [260418-n7k-subagentstart-working-perch-notice-still](./quick/260418-n7k-subagentstart-working-perch-notice-still/) |
| 260418-nt3 | Phase 18.3 amendment: gate echo-commune staleness on .more-done CREATION time, not psyche context mtime | 2026-04-19 | 801a8e8 | [260418-nt3-phase-18-3-amendment-gate-echo-commune-s](./quick/260418-nt3-phase-18-3-amendment-gate-echo-commune-s/) |
| 260418-owu | Rename PULSE REQUEST to SCHEDULE_PULSE across project | 2026-04-19 | 9435dc7 | [260418-owu-rename-pulse-request-to-schedule-pulse-a](./quick/260418-owu-rename-pulse-request-to-schedule-pulse-a/) |
| 260419-6i2 | Make DEPLOY.ps1 handoff-safe: stop killing owl.exe, prune old cache only | 2026-04-19 | 4a3a87e | [260419-6i2-make-deploy-ps1-handoff-safe-stop-killin](./quick/260419-6i2-make-deploy-ps1-handoff-safe-stop-killin/) |
| 260419-pwy | Harden echo-commune subprocess permissions (drop --dangerously-skip-permissions, add --allowed-tools whitelist + --disable-slash-commands, CWD=psyche_dir) | 2026-04-20 | f9fdea0 | [260419-pwy-harden-echo-commune-subprocess-permissio](./quick/260419-pwy-harden-echo-commune-subprocess-permissio/) |
| 260421-0ws | Expand SessionStart reorientation with send/receive + poll-revival primer; verify skill docs clean of removed $OWL listen subcommand; bump 1.9.2→1.9.4 | 2026-04-21 | 551ac68 | [260421-0ws-update-skill-docs-and-sessionstart-hook-](./quick/260421-0ws-update-skill-docs-and-sessionstart-hook-/) |
| 260510-vng | Harden docs/DEPLOY.ps1: atomic rename-first prune + explicit installed_plugins.json patch + post-deploy pointer assertion (closes 26-06 regression class) | 2026-05-10 | b38ea4d, 1e3f9f6, 7c6f115 | [260510-vng-deploy-ps1-hardening-atomic-prune-and-po](./quick/260510-vng-deploy-ps1-hardening-atomic-prune-and-po/) |
| 260513-63n | Wire TCP wake into psyche-wrapper inner poll (pass --once to inner owl poll subprocess so IDLE-MODE TCP delivery exits immediately; eliminates ~20min commune→psyche.md latency bound by pulse cadence) | 2026-05-13 | db08bf5 | [260513-63n-wire-tcp-wake-into-psyche-wrapper-inner-](./quick/260513-63n-wire-tcp-wake-into-psyche-wrapper-inner-/) |
| 260513-v8f | Fix endless INIT_SIGNOFF loop in psyche-wrapper: EVENT-aware predicate, orphan return-value plumbing, INIT_SIGNOFF EVENT envelope cleanup | 2026-05-14 | ed21251, b41c94e, f444066, c9db074, 9dddae8 | [260513-v8f-fix-endless-init-signoff-loop-in-psyche-](./quick/260513-v8f-fix-endless-init-signoff-loop-in-psyche-/) |
| 260513-vzw | Fix EVENT envelope blast-radius: wrapper REPLY routes via from= attribute, boot_spine PSYCHE_DEAD accepts EVENT envelope, PULSE_TRIGGER raw-emit contract pinned | 2026-05-14 | 04bba62, 1882a25, 48c5f97 | [260513-vzw-fix-event-envelope-blast-radius-wrapper-](./quick/260513-vzw-fix-event-envelope-blast-radius-wrapper-/) |
| 260515-uf1 | Make psyche-download destructively consume `.claude/{id}-{commune,signoff}.md` drop files into on-disk psyche-context (mtime-stamped headers, retain-on-error); deprecate `/spt:amend-signoff` skill (binary preserved); document `/spt:signoff` offline persist-until-absorbed path; deploy v1.10.8 | 2026-05-15 | 4648a50, b2749fd, ddc44bd, 5be20a8, add6bc6 | [260515-uf1-psyche-download-consumes-drop-files](./quick/260515-uf1-psyche-download-consumes-drop-files/) |
| 260517-6om | Phase 34 UAT hotfix: silent Stop-hook owl-message transport (replaces decision:"block"); drop "Remind me later" AUQ option (infinite-loop risk); deprecate `version-remind` subcommand; deploy v1.10.12 | 2026-05-17 | 5ede3d7, acbb696, 79193f1, a75583e, fadc5b8, e724a11 | [260517-6om-version-change-owl-transport-hotfix](./quick/260517-6om-version-change-owl-transport-hotfix/) |
| 260517-n4b | Version-change UAT defect cleanup: step_count floor + info-priority + DEPLOY.ps1 curation gate; deploy v1.10.13 | 2026-05-17 | 2c19d3f, 97e5a62, c99d7c9, ce73046, 919e957 | [260517-n4b-version-change-uat-defect-cleanup](./quick/260517-n4b-version-change-uat-defect-cleanup/) |
| 260517-q3h | Phase 34 wrap-up doc bundle: STATE ledger row for 260517-n4b, 34-03-SUMMARY UAT amendment (6om + n4b + v1.10.13 UAT closure), 34-01-SUMMARY HISTORIC note for c99d7c9 | 2026-05-18 | 7a1bfd5, 5ff8bd0, 2375cb9 | [260517-q3h-phase-34-wrap-up-doc-bundle-state-md-row](./quick/260517-q3h-phase-34-wrap-up-doc-bundle-state-md-row/) |
| 260517-rhw | SPT first-install primer flow: PreToolUse hook detects absent `$SPT_HOME/last-seen-version.json` → emits direct-stdout `<spt-primer>` additionalContext (perch-less); agent fires Yes/Skip AUQ, on Yes renders verbatim 5-step blurb. Single shared sentinel suppresses both primer and version-change banner. 6 unit + 7 integration tests; replan once (v1 spool-perch path scrapped after user catch) | 2026-05-18 | fb998b3, 504c819 | [260517-rhw-spt-first-install-primer-flow](./quick/260517-rhw-spt-first-install-primer-flow/) |
| 260517-wpf | v1.7.1 audit follow-up: CHANGELOG.md reordered to newest-first (1.10.11/12/13 moved from bottom to top); mojibake em-dashes repaired; DEPLOY.ps1 curation-gate stub insertion switched from append-at-bottom to insert-above-first-H2 (prevents tech-debt recurrence). Regression: 16/16 version_changelog tests green | 2026-05-18 | (pending commit) | [260517-wpf-fix-changelog-md-ordering-and-tighten-de](./quick/260517-wpf-fix-changelog-md-ordering-and-tighten-de/) |
| 260518-2d6 | Consolidate SPT skills: new `/spt:list-agents` (merges list-live/list-psyche/list-ready) + `/spt:force-stop` (merges listen-stop/live-stop); deleted 8 wrapper SKILL.md manifests (above two + context-save/psyche-download/reboot — binary subcommands intact); fixed 3 cross-refs (listen/live/signoff) + resume.rs runtime copy (Rule 1 deviation); updated tests/skill_hints.rs pinned set (4 rows out, 2 rows in). All 4 skill_hints tests green | 2026-05-18 | 34b1ad2, 2e3dae7, 9a6cb65, 313d3c9 | [260518-2d6-consolidate-skills-list-agents-merge-lis](./quick/260518-2d6-consolidate-skills-list-agents-merge-lis/) |
| 260520-mth | Fix phantom INIT_SIGNOFF race after binary handoff: reorder `check_orphan` in `src/live/wrapper/orphan.rs` so 5s grace sleep + parent-liveness recheck precede INIT_SIGNOFF compose/deliver; prevents self-sent envelope from draining into wrapper's own poll predicate when Self recovers during grace window. 2 new source-order tests pin invariant; 13/13 orphan + 622/622 lib tests green | 2026-05-20 | 19d3a5e, e7679fd | [260520-mth-fix-phantom-init-signoff-race](./quick/260520-mth-fix-phantom-init-signoff-race/) |
| 260520-pra | Fix spool-retain race + producer-side dedupe for file_drop controls (defense in depth). Surface A: `process_file_drop` in `src/live/wrapper/mod.rs:1209-1218` gets `ErrorKind::NotFound` arm that logs "dropped" not "retaining" when consumed file is gone. Surface B: `src/owl/poll.rs` carries `HashSet<String> emitted_drops` across poll iterations + new `dedupe_drops` helper — suppresses re-emit while path present, `retain()` clears vanished paths so re-creation re-emits. Prevents 649-dupe pileups (doyle gen 49 incident). 18 file_drop tests + 26 poll tests (incl. 4 new) green; cargo build --release clean | 2026-05-20 | c1adb43, a9ba7d0, d464b7d | [260520-pra-fix-spool-retain-race-file-drop-dedupe](./quick/260520-pra-fix-spool-retain-race-file-drop-dedupe/) |
| 260520-pzs | Fix poll-listener events truncated by Claude Code Monitor 500-char per-notification cap. M0 empirical reproduction (2 probes, varying `from` attr) pinned cap at exactly 500 wire chars (envelope + body inclusive). `EVENT-PART seq="K/M" id="<8hex>"` chunking in `src/owl/poll.rs::chunk_if_oversized` + `EVENT_LINE_THRESHOLD=400` const — short bodies emit byte-identical single `<EVENT>` (backward compat), long bodies split into N parts each under cap. Receiver reassembly prose in `plugin/spt/skills/listen/SKILL.md` + embedded spacetime-reorientation in `src/owl/resume.rs`. 4 new chunking unit tests + 30/30 poll tests green. Smoke: 2500-char/25-marker body round-tripped via 8 EVENT-PART chunks intact through Monitor stream. Deploy v1.10.17 (patch bump for Phase 18.4 handoff). Bonus finding: Monitor 200ms batching renders multi-line block but cap applies per-line → strategy doubly safe | 2026-05-20 | 7f67b72, 0f5b6c6, bc6d0b7, 1ac0e86, d710a23, 7ff4fee | [260520-pzs-fix-poll-listener-events-get-truncated-b](./quick/260520-pzs-fix-poll-listener-events-get-truncated-b/) |
| 260520-r2f | Fix fresh-init first-commune flow + stale `$LIVE commune <id> <message>` refs. `plugin/spt/skills/live/SKILL.md:220` (FRESH-01/02 native-Other path) now points at canonical Write tool → `.claude/<id>-commune.md` per `/spt:commune` skill instead of `$OWL deliver` (which bypasses commune EVENT envelope) or `$LIVE commune` CLI (which the skill explicitly forbids — Bash/heredoc non-canonical). Two `src/owl/resume.rs` context strings (`resume_xml` live branch + `print_skill_context` live Self perch) replaced `$LIVE commune {} <message>` with `/spt:commune` pointer. Out-of-scope (left alone): `src/live/commune.rs`/`src/live/mod.rs` (CLI impl still valid), `psyche.md:42` (Psyche-outbound rule, orthogonal). Build clean | 2026-05-20 | 800ec6f | [260520-r2f-fix-fresh-init-commune-flow-refs](./quick/260520-r2f-fix-fresh-init-commune-flow-refs/) |
| 260520-we4 | --verbose flag for `$OWL list` and `$LIVE list`. Default emits one terse `{TAG}:{id}` line per agent (TAG ∈ ACTIVE/LIVE/OFFLINE); `--verbose` reproduces pre-change full dump byte-identical. Two `#[arg(long)] verbose: bool` on `Commands::List`/`LiveCommands::List` (src/cli.rs); 4 format-site gates across `src/owl/list.rs` + `src/live/list.rs`; dispatch threading in `src/owl/mod.rs` + `src/live/mod.rs`. `LIVE:` tag preserved for online live agents (not collapsed to `ACTIVE:`). Collector `src/common/list_filter.rs` byte-identical; `list_result`/`ListOutcome` MCP path untouched. 4 clap parser tests + 2 native integration tests + `tests/cli_parse.rs` struct-pattern updates. `cargo build --release` clean | 2026-05-21 | 3fa3e6d, 7cac631 | [260520-we4-verbose-flag-for-live-list-and-owl-list](./quick/260520-we4-verbose-flag-for-live-list-and-owl-list/) |
| 260521-3av | Fresh live agent psyche onramp + scoped HIGHEST-PRIORITY banner. (A) `src/owl/resume.rs` — when `is_live=true`, `<spacetime-reorientation>` block gains a "Talking to your Psyche" section teaching the modern Write-tool drop-file flow (`.claude/{id}-commune.md`, `.claude/{id}-signoff.md`) + clarifies that inbound `{id}-psyche` messages are FYI/no-ACK. (B) `src/common/hook_output.rs` — new `pub(crate) classify_priority(from, body)` 3-tier classifier (`info` from `[WORKING_PERCH_NOTICE]`, `normal` from `*-psyche` sender, else `high`). `format_owl_messages` refactored to a 3-branch banner ladder: `has_high` → refined banner ("high-priority owl messages above"); else `has_info` → existing info banner; else only `normal` → no banner. `is_informational` retained as thin wrapper for `src/owl/poll.rs:1027` drain-filter. Root cause: fresh live agents (witness: webber gen-1) saw only `$OWL deliver/ring/send/reply` in reorientation + got `priority="high"` STOP-and-ACK banner on echo-commune briefs → ACK'd back via `$OWL deliver {id}-psyche` (wrong channel). 5 new hook_output tests + 2 plugin_session_start tests extended with onramp positive/negative assertions; 34/34 tests green across affected suites | 2026-05-21 | 863cbd0, 845fc03, e1f9f54, 4127c48 | [260521-3av-fresh-live-agent-psyche-onramp](./quick/260521-3av-fresh-live-agent-psyche-onramp/) |
| 260521-myj | Remove `$LIVE context-save` subcommand (operator-callable footgun on tracked-repo: smoke-test invocation could clobber rich live_context.md with 228-byte stub — observed d708974→0ad3ece on agents/doyle). Callsite audit: 0 bucket-(a) essential, 12 bucket-(b) operator-facing, 2 bucket-(c) dead. Removed `LiveCommands::ContextSave` clap variant, dispatcher arm, `run_save` handler, dead `context_save_result` + `ContextSaveOutcome`, resume.rs skill banner line, SKILL.md mentions, `parse_live_context_save` + `golden_context_save` tests, regenerated `tests/golden/live/unknown_cmd.stderr`. Psyche LLM remains sole writer of `agents/{id}/live_context.md` via Write tool — `psyche.md` byte-identical. Plugin patch-bumped v1.10.24→v1.10.25 via DEPLOY.ps1. 703/704 lib tests pass (1 pre-existing release-mode test unrelated). Stopped before /reload-plugins per CLAUDE.md | 2026-05-21 | eac0b9e, 7752cfd, 104ac27, 00f28e2, 6cdc733 | [260521-myj-investigate-context-save-removal](./quick/260521-myj-investigate-context-save-removal/) |
| 260521-oyi | Default `$LIVE start --period` to 0 (no scheduled pulse). Pulses become opt-in via `--period <seconds>`; bare-start wrapper omits `--pulse-interval` entirely from inner-poll argv (NEVER passes literal 0 — would tight-loop firing PULSE_TRIGGER on every iteration). Sentinel-0 representation: `period: u64` stays, `0` = no pulse. Minimum-60 guard relaxed: allow 0, still reject 1..=59. Touched src/live/{start,wrapper/mod,wrapper/claude}.rs (argv → Vec<&str> conditional push; init banner + agents-JSON conditional phrasing). Skill docs (live, revive) reworded to opt-in; CHANGELOG 1.10.26 entry (split UX/BTS per 260520-uc2 convention). 4 orchestrator-flagged soft spots (psyche.md verbatim, echo-fire override path, WrapperState::new, perform_wrapper_handoff re-emit) inspected — none required edits. 2 new cli_parse regression guards added; full suite 703/704 (1 pre-existing flake). Stale `poll_psyche_argv_contains_once_flag` unit test deferred for cleanup | 2026-05-22 | be87fdb, 5ec99c6 | [260521-oyi-update-live-start-to-have-default-period](./quick/260521-oyi-update-live-start-to-have-default-period/) |
| 260522-4sq | Update commune/signoff skill messaging — in-project detection rule keys on `<current ... project="..."/>` tag attribute (always emitted when payload exists) instead of conditional `<project-context-resolved/>` sentinel (only emitted when project file has prior content). Sentinel demoted to secondary "prior content" indicator. Three skill docs rewritten in place: `plugin/spt/skills/commune/SKILL.md`, `plugin/spt/skills/commune/commune.md`, `plugin/spt/skills/signoff/SKILL.md`. Three routing rules (D-25.1-01..03) preserved verbatim. No code changes — `src/` and `psyche.md` untouched. Root cause of original misrouting: first-time-in-project agent has no project file → no sentinel → docs' "marker absent → outside project" rule misrouted project-bound work to `<live-context>` even though `<current/>` carried `project="claude_skill_owl"`. Positive reframing per user direction (no "Common Mistake" warning section) | 2026-05-22 | aedfdea | [260522-4sq-update-and-clarify-commune-signoff-skill](./quick/260522-4sq-update-and-clarify-commune-signoff-skill/) |
| 260521-m8y | Scope EVENT-PART chunking to non-psyche listener output only. Wrapper-fed `--psyche --once` poll pipes stdout straight into `claude -p --resume` stdin (no Monitor per-notification cap), so chunking was pure context bloat forcing the Psyche session to spend tokens reassembling EVENT-PART chunks for zero defensive value. New pure helper `assemble_event_line(self_id, from, body) -> Option<String>` factored out of `emit_event_line` (preserves the info-body suppression early-return + the three constructive shapes byte-for-byte). `emit_event_line(self_id, from, body, psyche: bool)` gains a single gating site: `psyche=true` → `println!` assembled line verbatim; `psyche=false` → `chunk_if_oversized` as before. All 5 call-sites inside `pub fn run` updated (poll.rs:191, 372, 590, 592, 653) — `psyche` was already in scope via `pub fn run(..., psyche: bool, ...)`. One new unit test `emit_event_line_skips_chunking_when_psyche_true` (asserts 500-char body assembles to single line + WOULD have chunked under chunk_if_oversized + wire-shape invariants). Out-of-scope: `boot_spine.rs` Spine listener (short control envelopes, chunking never fires today), wrapper-side changes (already passes `--psyche`), SKILL.md (receiver contract documents both wire shapes), goldens (short-body fixtures unaffected). 31/31 poll-module unit tests green; full-suite failure count below baseline (33 vs 36 pre-existing Windows env failures, none poll-related). No version bump — debug-style fix | 2026-05-21 | f1dfa05 | [260521-m8y-scope-event-chunking-to-listener-output-only](./quick/260521-m8y-scope-event-chunking-to-listener-output-only/) |
| 260523-7zy | Fix v1.11.9 binary-handoff regression — argv backward-compat. Commit `3616ed1` (in 260523-648) added required clap positional `pulse_psyche: String` to `Commands::PsycheWrapper` (`src/cli.rs:188-197`) without `#[arg(default_value)]`, while bumping `perform_wrapper_handoff`'s `wrapper_args` from `[&str;5]` → `[&str;6]`. v1.11.8 wrappers handing off to v1.11.9 still spawn the 5-arg shape → v1.11.9 clap rejects → new wrapper exits before any log/state-file consumption → listener orphan-cascades. State-file backward-compat already worked (`#[serde(default)]` on `WrapperHandoffState.pulse_psyche`); argv backward-compat was missed. Fix = one-line `#[arg(default_value = "0")]` on `pulse_psyche` at `src/cli.rs:196` + new `psyche_wrapper_5arg_argv_backward_compat` regression test in `tests/handoff_integration.rs` (asserts both 5-arg defaulting to `"0"` and 6-arg preserving explicit `"1"`). Type stays `String` (not `bool`) to avoid touching `arg == "1"` dispatch in `src/live/wrapper/mod.rs`. Version bumped v1.11.9 → v1.11.10 across `plugin.json`+`Cargo.toml`+`Cargo.lock` (owl stanza only, no `cargo update`); CHANGELOG `[1.11.10]` Fixed + BTS entry prepended. 19/19 handoff_integration tests pass incl. new guard; `cargo build --release` clean. Root cause investigation: `.planning/debug/binary-handoff-defer-todlando.md`. Deploy = operator's manual `docs/DEPLOY.ps1` (no `-Bump`, version pinned) + `$LIVE revive todlando` to recover dead live agent | 2026-05-23 | f105536, 2328747 | [260523-7zy-fix-v1-11-9-handoff-argv-backward-compat](./quick/260523-7zy-fix-v1-11-9-handoff-argv-backward-compat/) |
| 260523-opn | Option D file-drop single-writer (signoff side, end-to-end). Closes `.planning/debug/file-drop-file-gone-todlando.md` race plus its listener-side analog. Two-commit landing: (1) wrapper-side mtime-vs-`WrapperState.gen_start` discriminator in `process_file_drop` — init-stale signoffs (file mtime < gen_start) absorb via `resume_session_with_exit` + Continue (wrapper keeps polling); normal-flow signoffs preserve existing `final_session` + BreakLoop teardown. Plus `gen_start: SystemTime` field added to WrapperState (cold + handoff both `now()`), empty-body skip in process_file_drop, Phase 30 ENOENT diagnostic cleanup, `is_init_signoff_envelope` cross-agent inbox teardown PRESERVED (D-06 asymmetry). (2) Follow-up: `drain_stale_signoff_file` + both callsites REMOVED from `src/live/start.rs` (redundant under new contract — `psyche-download` already covers offline absorption, wrapper picks up live); listener-side symmetric mtime discriminator added at `src/owl/poll.rs` scan_drop_files signoff branch — init-stale emits `INIT-STALE-SIGNOFF:{id}` + continue, normal-flow preserves `STOP:{id} (signoff dropped)` + soft_stop + exit(0). Both discriminators required: without listener-side, stripping drain re-opens the bug via orphan-cascade (listener exit → wrapper `check_orphan` → INIT_SIGNOFF → wrapper exit). End-to-end contract: $LIVE start no longer touches signoff/commune files; listener and wrapper both mtime-discriminate; single source of truth = wrapper as sole deleter. Tests: `tests/native_latent_signoff_deliver_then_die.rs` DELETED (drain-specific). `tests/file_drop_integration.rs` updated — Test 9 switched to `poll listen` direct invocation, Tests 10+11 (drain) removed, new Test 10 `listener_emits_init_stale_signoff_status_for_stale_file`. `signoff_listener_exits_zero` forward-dates file mtime to drive normal-flow path. cargo build clean; lib 854 pass / 1 pre-existing flaky; file_drop_integration 6 pass / 4 ignored | 2026-05-23 | 7f819f5, 4b3c56f | [260523-opn-option-d-file-drop-single-writer-snapsho](./quick/260523-opn-option-d-file-drop-single-writer-snapsho/) |
| 260523-648 | Default `$LIVE start --period` flipped from 0 → 480 (8 min); new `--pulse-psyche` boolean flag on `$LIVE {start,revive,fork}`. Corrects 260521-oyi/[1.10.26] over-correction: `period=0` (no cadence wake) meant the wrapper outer loop never iterated → `fire_echo_commune_if_due` (top-of-iteration gate) never fired → echo-commune system dormant for bare-start agents. New default: wrapper wakes every 8 min, runs echo gate, and (when `--pulse-psyche` is NOT set) intercepts the `PULSE_TRIGGER` message and `continue`s past `resume_session_checked` — echo gate only, no Psyche LLM resume turn. `--pulse-psyche` opts back into legacy PULSE_TRIGGER → resume → markers path. Sentinel-0 mechanics from 260521-oyi preserved verbatim (`period=0` still = no cadence wake; min-60 guard with `(or 0 to disable)` wording untouched). `pulse_psyche: bool` added to `WrapperState` + `WrapperHandoffState` (`#[serde(default)]` for v1.11.8 backward-compat — no migration); threaded through CLI → dispatch → start/revive/fork → run_wrapper; argv extended `[&str;5]` → `[&str;6]` at three sites (two cold-start spawns + handoff re-emit) with outer-scope `pulse_psyche_str` for lifetime safety. Three independent `#[arg(long)] pulse_psyche: bool` additions on `LiveCommands::{Start, Revive, Fork}`. 4 new CLI parse tests + 2 new wrapper_state focused tests + renamed `live_start_default_period_becomes_zero_sentinel` → 480-default regression guard. Auto-fix: `tests/skill_hints.rs` pinned argument-hint values updated for new flag advertisement. CHANGELOG `[1.11.9]` entry (Changed + BTS split, quick-260520-uc2 rule); `plugin.json` UNTOUCHED (user runs DEPLOY.ps1 separately). `cargo build --release` clean; `cargo test --test cli_parse` 48/48; `cargo test --lib common::wrapper_state` 11/11; `cargo test --test skill_hints` 4/4 | 2026-05-23 | 3616ed1, 733ccd7 | [260523-648-default-period-8m-pulse-psyche](./quick/260523-648-default-period-8m-pulse-psyche/) |
| 260523-vk1 | Announce "Fresh live agent. Preparing for init." before first-commune AskUserQuestion synthesis (FRESH-01 + FRESH-02 triggers). Single inserted instruction at the converged "### First-commune flow (FRESH-01 / FRESH-02 / FRESH-03)" section in `plugin/spt/skills/live/SKILL.md` (Option 1 — both trigger paths reach this site, DRY). Eliminates silent multi-second dead pause caused by session-memory + README/CLAUDE/STATE synthesis between trigger detection and the AskUserQuestion firing. No Rust, no `psyche.md`, no hooks — single skill-doc edit. Plugin version untouched (operator runs `docs/DEPLOY.ps1` separately per CLAUDE.md) | 2026-05-23 | 381593b | [260523-vk1-fresh-live-agent-init-announcement](./quick/260523-vk1-fresh-live-agent-init-announcement/) |
| 260524-02w | Patch psyche.md to recognize typed `<EVENT type="commune">` envelope as canonical commune classification trigger (decision-tree entry 1 + `<commune>` handler header + `<self_request>` Critical note), and global positive-tone rewrite reducing prohibition phrases 31 → 3 (only documented permitted exceptions remain: passive-context safety, encoding pass-through, parse-failure session-survival). Closes `ling.log:43` root cause: typed envelope from `$LIVE psyche-download` first-commune fell through legacy `COMMUNE (timestamp):` matcher to `<self_request>` handler; ling psyche hallucinated needing Bash to ACK despite `<tool_access>` denying it. Wrapper markers `[REPLY]`/`[NOTIFY]`/`[COMMUNE]` preserved verbatim (`src/live/wrapper/mod.rs::parse_markers` untouched). `owl.exe` rebuilt + `include_str!`-embeds patched `psyche.md`; v1.11.13 → v1.11.14 via DEPLOY.ps1 -Bump patch; marketplace pushed (`6d7dd8a`). Operator runs `/reload-plugins` to activate | 2026-05-24 | 75bb2d6, 6f48d61 | [260524-02w-patch-psyche-md-recognize-typed-event-co](./quick/260524-02w-patch-psyche-md-recognize-typed-event-co/) |
| 260524-2wo | SPT verb scrub: wipe stale `$OWL deliver`/`$OWL reply` user-facing strings + "formerly X" provenance comments across `src/`+`plugin/spt/skills/` to align with Phase 16 verb taxonomy (deliver→send, send/ask→ring, standalone reply→`$OWL send --reply-to <perch>`). Driven by ling /grill-with-docs handoff alongside new CONTEXT.md + docs/adr/0001-0005. Task 1: rewrote agent-facing XML strings in `src/owl/resume.rs` (resume_xml, print_skill_context, inject_reorientation, live-only addendum), `src/owl/hook_check.rs` (`<owl_working_perch>` first-call awareness), `src/owl/hook_subagent_start.rs` (WORKING_PERCH_NOTICE body + SubagentStart additionalContext). Task 2: dropped "formerly deliver"/"formerly send/ask" comments in `src/owl/{send,ring,mod}.rs`, `src/cli.rs:59`, `src/common/outcomes.rs:7,25`, `src/live/commune.rs:2,39,40,42`; restructured `plugin/spt/skills/{live,listen,revive,send}/SKILL.md` to current verbs. Task 3: full-tree sweep verified zero `$OWL deliver|$OWL reply` matches in scope. PRESERVED back-compat: `#[command(alias = "deliver")]`, `#[command(alias = "ask")]`, hidden deprecated `Reply` variant in `src/cli.rs`, all `tests/` references (exercise back-compat surface by design). CHANGELOG.md historical entries untouched. `psyche.md` audit: only English-prose "wrapper will deliver" usage — no `$OWL` command strings — no edit needed (binary `cargo build --release` ran anyway via Task 1 verify gate, clean). Residual: `src/common/owlery.rs:8` pre-existing Phase-18.2 `spacetime_dir()` rename comment (out of scope). Pre-existing flaky tests confirmed via baseline-revert+rerun (not caused by scrub). Plugin version untouched (operator runs `docs/DEPLOY.ps1` separately) | 2026-05-24 | a4be4b0, 524e30a | [260524-2wo-spt-verb-scrub-wipe-stale-deliver-old-se](./quick/260524-2wo-spt-verb-scrub-wipe-stale-deliver-old-se/) |
| 260524-3p3 | SPT rename "plain owl listener" → "ready agent" across code + skill text. Driven by ling /grill-with-docs handoff (CONTEXT.md locks "ready agent" canonical for agent-with-perch+poll-listener-no-Psyche-wrapper, retires "plain owl listener"/"plain listener"). 4 files, +9/-9: `src/owl/resume.rs:55,71` (prior-session reorientation prose), `plugin/spt/skills/force-stop/SKILL.md:4,9,41` (frontmatter description + body header), `plugin/spt/skills/list-agents/SKILL.md:4,8,24` (frontmatter + bullet), `plugin/spt/skills/revive/SKILL.md:58` (agent-type guard prose). Disambiguation: `force-stop/SKILL.md:58` ("every listener / every live agent") LEFT — "listener" there = poll-listener process per CONTEXT.md:31, not retired agent-kind term. `CONTEXT.md:61` `_Avoid_` glossary entry LEFT by design (lists retired term). Verify: `rg 'plain owl listener\|plain listener' src/ plugin/ docs/agents/ CLAUDE.md AGENTS.md` → 0 matches; CONTEXT.md → 1 match (line 61, expected). `cargo build --release` clean. Plugin version untouched (operator runs `docs/DEPLOY.ps1` separately) | 2026-05-24 | eadb1ee | [260524-3p3-spt-rename-plain-owl-listener-to-ready-a](./quick/260524-3p3-spt-rename-plain-owl-listener-to-ready-a/) |
| 260524-436 | SPT rename `/spt:listen` skill → `/spt:ready` for taxonomy symmetry with `/spt:live` (matches CONTEXT.md "ready agent" vs "live agent" agent-kind names). Commit 1 (ac94cd2): `git mv plugin/spt/skills/listen → plugin/spt/skills/ready` (history-preserving folder rename) + SKILL.md frontmatter `name: listen` → `name: ready` (line 2) + body H1 `# /spt:listen` (line 10) + H2 `## /spt:listen --reboot` (line 206) all retargeted to `/spt:ready`. Commit 2 (bc47eed): cross-ref sweep across 6 files — `plugin/spt/skills/{whoami:31,live:274+280,revive:85+89}/SKILL.md` parsing-rule cross-links, `src/owl/resume.rs:55,73,120,137` runtime resume hints, `src/owl/poll.rs:939,1024,1738,1740,2286` code-comment file-path refs (5 callsites — path retargeted `plugin/spt/skills/listen/SKILL.md` → `ready/SKILL.md`), `docs/DEPLOY.md:345` example. Line-169-173 anchor in cross-link prose preserved (only frontmatter+headers changed in target SKILL.md, body offsets unaffected). DISAMBIGUATION (LEFT UNTOUCHED): all `"listen"` poll-mode CLI string args across `src/{owl,live,common}/**` + `tests/**` (~50+ refs — `$OWL poll <id> listen` arg, distinct namespace from skill name); CHANGELOG.md historical entries; `.planning/` archival refs. Verify: `rg 'spt:listen|skills/listen' src/ plugin/ docs/agents/ docs/DEPLOY.md CLAUDE.md AGENTS.md CONTEXT.md` → 0; `^name: listen$` in `plugin/spt/skills/` → 0; `^# /spt:listen` in `plugin/spt/skills/` → 0; `plugin.json` untouched (folder-based skill discovery, no index). `cargo build --release` clean (8s, no new warnings); `cargo test --test skill_hints` 4/4 green. Hard-break for `/spt:listen` after `/reload-plugins` accepted (sole user, no muscle-memory concern). Plugin version untouched (operator runs `docs/DEPLOY.ps1 -Bump patch` separately) | 2026-05-24 | ac94cd2, bc47eed | [260524-436-spt-rename-spt-listen-skill-to-spt-ready](./quick/260524-436-spt-rename-spt-listen-skill-to-spt-ready/) |
| 260527-6ah | Fix two `accept_flow` idempotency bugs in `src/common/sync.rs` that broke `$OWL psyche-sync-setup` (live Windows failure: exit 1, push 404 vs stale `origin=https://github.com/u/spt-agent-storage.git`). **Bug A (Step 4):** origin wiring now authoritative — per-worktree soft `remote add origin <url>` followed by unconditional soft `remote set-url origin <url>`, so origin == canonical `https://github.com/{user}/spt-agent-storage.git` regardless of stale shared-worktree-config (git worktrees share config). **Bug B (Step 1):** case-insensitive `"already exists"` `gh repo create` stderr now treated as idempotent success (checked AFTER the unchanged scope-fallback `missing required scopes`/`HTTP 403` disposition) instead of aborting `RepoCreateFailed` — survives a partial prior run that created the repo but never persisted `state=Enabled`. Both git calls stay `let _ =` soft-failed (D-14); `psyche_sync_setup` exit-code contract untouched. 2 new `#[cfg(unix)]` fake_gh regression tests (`accept_flow_repo_exists_is_idempotent`, `accept_flow_corrects_stale_worktree_origin`) — compile-only on Windows host, run on unix CI. `cargo build`/`build --release` clean; `cargo test --lib common::sync` 23/23. Operator recovery already applied to live runtime (seed `remote set-url` → correct url, `push --all`, per-branch `--set-upstream-to`, `settings.json sync.state=enabled`); sync verified `$OWL doctor` PASS, 16 branches on remote. Plugin version untouched (operator runs `docs/DEPLOY.ps1` separately) | 2026-05-27 | b7668dd, e4ceca4 | [260527-6ah-fix-two-idempotency-bugs-in-src-common-s](./quick/260527-6ah-fix-two-idempotency-bugs-in-src-common-s/) |
| 260527-s8l | Fix `p-<project>` branches never receiving commits on `spt-agent-storage` (visible symptom: GitHub web UI showed branch ref but no project content; semantically the branch was pinned at the seed-init SHA). Root cause traced via `/gsd:debug` (`.planning/debug/p-branches-not-pushed-origin.md`): `route_two_slice` in `src/owl/echo_commune.rs` was writing the project `<agent>.md` file into `psyches/tracked/projects/<name>/` BEFORE calling `commit_project_payload`, which pre-populated the dir and made the downstream `git worktree add` (primary + fallback) fail with `'...' already exists`. Worktree never materialized, error silently swallowed as `(payload on disk)`. **Fix 1 (`4866fb9`)**: reordered all 3 production sites in `src/owl/echo_commune.rs` — `ensure_project_worktree` FIRST → `fs::write` → `commit_project_payload`. **Fix 2 (`2eb23eb`)**: defense-in-depth salvage path in `src/common/tracked.rs::ensure_worktree` — when target dir is non-empty + lacks `.git` AND both `worktree add` attempts fail with `'...' already exists`, content moved to `<wt>.salvage-<unix_ts>/`, retry `worktree add`, restore files into the now-real worktree. Salvage auto-repairs existing broken installs on next commune carrying `<project-context>`. Verified grep hits: 6 of 9 grep-matched call sites are test code or read paths and were NOT touched (`src/live/signoff.rs:789/824/863/904/970`, `src/live/context.rs:470/2338/2401/2517`); only echo_commune production sites had the bad order. 2 new regression tests (RED→GREEN for the reorder, salvage path round-trip). `cargo build --release` clean; `cargo test --lib` 951 pass / 0 fail / 5 ignored; `cargo test --test handoff_integration` 19 pass; `cargo test --test hook_chain` 7 pass. Out-of-scope test breakage discovered in `tests/native_wrapper_state_retry.rs` (missing `pulse_psyche` field in `WrapperHandoffState` initializers, introduced by upstream commit `3616ed1`) logged to `deferred-items.md` — trivial follow-up (`pulse_psyche: None` in 3 sites). User's local broken install will auto-repair via salvage path on next commune; operator runs `docs/DEPLOY.ps1` separately | 2026-05-28 | 4866fb9, 2eb23eb | [260527-s8l-fix-p-project-branches-never-receiving-c](./quick/260527-s8l-fix-p-project-branches-never-receiving-c/) |
| 260602-2ar | Clear the `.more-done` echo-commune cadence sentinel whenever FILE-DROP consumes a manual commune/signoff drop file — a manual commune/signoff already flushes "more done" context, so a pending cadence sentinel would otherwise fire a redundant echo commune right after. Extracted the previously-inlined delete-both logic in `src/live/wrapper/echo_fire.rs` into a shared free fn `remove_both_more_done(nested, flat)` + `WrapperState::delete_more_done_sentinel()` (derives both paths via `owlery::nested_perch_dir` + `perch_dir`, honoring the reader/writer path-asymmetry KNOWN-HAZARD — see `.planning/debug/resolved/more-done-sentinel-not-written.md`); rewired `fire_echo_commune_if_due` off its two inlined `remove_file` calls onto the helper so fire-path + consume-path share ONE code path and can't drift. `src/live/wrapper/mod.rs::process_file_drop` now calls `self.delete_more_done_sentinel()` at exactly 2 consume exits: the empty-body signoff skip branch + the shared `exit_code == 0` delete block (commune + init-stale signoff + normal-flow signoff). NOT in the retained/`else` arm — a failed consume keeps the cadence sentinel. 2 new echo_fire unit tests. `cargo build --release` clean; `cargo test --lib -- echo_fire` 22/22; single-threaded full-lib delta baseline 961→963 pass (exactly +2 new tests), same 1 pre-existing unrelated failure (`version_changelog::current_version_honors_override_in_debug_builds`); zero new failures. No traceable-reqs in this repo. Operator runs `docs/DEPLOY.ps1` separately to ship to live agents | 2026-06-02 | 0559386 | [260602-2ar-communes-and-signoffs-delete-the-more-do](./quick/260602-2ar-communes-and-signoffs-delete-the-more-do/) |

## Session Continuity

Last session: 2026-05-29T12:20:51.268Z
Stopped at: Phase 35.3 context gathered
Resume file:
None

## Operator Next Steps

- `/gsd-execute-phase 34` — runs Plan 34-03 (block-body wording inside `<instructions>` + UAT). `[PLAN_03_INSTRUCTIONS_PLACEHOLDER]` slot ready for grep+replace; payload XML structure locked
- Then end-of-milestone `DEPLOY.ps1 -Bump patch` per Phase 34 sequencing
- Then `/gsd-verify-work 32` — verify Phase 32 deliverables against 13 requirements (LIST-01..08, HINT-01..05)
- Then `/gsd-discuss-phase 33` or `/gsd-plan-phase 33` — Fresh-Start Commune + Auto-Resume (depends on Phase 31)
- Optional pre-Phase-33: triage pre-existing `cargo test --lib` Windows-state failures (logged in `.planning/phases/32-list-overhaul-skill-hint-audit/deferred-items.md`) via `/gsd-debug` — count crept from 19 → 21 across Phase 34 Task 1/2 work; appears tied to ENV_LOCK isolation between test modules, NOT introduced by Phase 34 logic (run_version_remind_valid_arg_writes_sentinel_and_returns_zero is non-deterministic under parallel cargo test)
