# Quick Task 260523-648: Default `--period` 8m + `--pulse-psyche` flag — Context

**Gathered:** 2026-05-23
**Status:** Ready for planning

<domain>
## Task Boundary

Background: prior quick task `260521-oyi` (commits `be87fdb` + `5ec99c6`, CHANGELOG `[1.10.26]`) flipped the `$LIVE start --period` default from `1200` to `0` (no scheduled pulse). That was a mistake — `period == 0` means the wrapper outer loop never wakes on cadence, which also means `fire_echo_commune_if_due()` (called at the top of each iteration) never runs, so the entire background echo-commune system goes dormant for bare-start agents.

This task:

1. Change default `--period` for `$LIVE start` (and `revive` / `fork`) from `0` back to **`480` (8 minutes)**.
2. Add a new flag **`--pulse-psyche`** (boolean, default `false`) to `$LIVE start` / `revive` / `fork`.
3. New default behavior (when `--pulse-psyche` is NOT set): routine cadence wakes fire ONLY the echo-commune gate (`fire_echo_commune_if_due` at the top of the wrapper outer loop). The `PULSE_TRIGGER` message emitted by the inner poll is intercepted by the wrapper and the `resume_session_checked(&msg)` call (Psyche LLM resume turn) is SKIPPED.
4. When `--pulse-psyche` IS set: legacy behavior — `PULSE_TRIGGER` flows into `resume_session_checked`, the Psyche LLM evaluates and may nudge Self.
5. Keep all of `260521-oyi`'s sentinel-0 code intact: `period == 0` still means "no cadence wake at all" (explicit opt-out from both echo gate and psyche poke). Min-60 guard with the `(or 0 to disable)` wording stays.

</domain>

<decisions>
## Implementation Decisions

### Default `--period` value
- **`480` seconds (8 minutes)**, minimum-60 guard unchanged. `--period 0` remains the explicit no-cadence-wake opt-out (sentinel-0 from `260521-oyi`).

### Suppression layer (how `--pulse-psyche=false` skips the Psyche poke)
- **Wrapper-side intercept.** Inner poll keeps emitting `PULSE_TRIGGER`. The wrapper outer loop checks `self.pulse_psyche`:
  - `pulse_psyche == false`: when `is_pulse_trigger` is true, skip the `resume_session_checked(&msg)` call (and the marker-processing block that depends on its `response`). Echo gate at the top of the next iteration still fires per existing contract.
  - `pulse_psyche == true`: existing legacy code path runs verbatim — `resume_session_checked` is called, `handle_pulse_trigger_recovery` fires on empty response, markers parsed.
- Rationale: smallest blast radius. No change to `owl poll listen --psyche` or `src/owl/poll.rs`. The `PULSE_TRIGGER` wire format is preserved (test contract at `poll.rs:252` stays intact).

### Flag scope
- **`--pulse-psyche` on all three:** `$LIVE start`, `$LIVE revive`, `$LIVE fork`. Mirrors the existing `--period` plumbing (clap `Option<bool>` → `bool` with `false` default → threaded into `live_start_result` → `WrapperState`).

### Existing on-disk state migration
- **No migration.** Live agents whose wrapper-state.json has `period: 0` (stored from `260521-oyi` default) keep that semantic on rehydrate: never wake on cadence. The new `480` default only applies on fresh `$LIVE start` invocations. No silent on-disk schema bump.

### Prior task (`260521-oyi`) revert scope
- **Keep all of `260521-oyi`'s sentinel-0 code.** Do NOT restore `unwrap_or(1200)`, do NOT restore the fixed `[&str; 7]` argv, do NOT remove the `>0 && <60` guard relaxation. Change only:
  1. `unwrap_or(0)` → `unwrap_or(480)` at both `start::run` and `start::live_start_result`.
  2. `init_session` banner and `build_agents_json` substitution: existing branches stay (period=0 still renders `disabled (no scheduled pulses; event-driven wake only)`).
  3. Skill docs updated to reflect new 8m default + new `--pulse-psyche` flag.

### State persistence
- **`pulse_psyche: bool` field on `WrapperState`.** Threaded the same way `period` is: from `start.rs` constructor → `WrapperState` → persisted in wrapper-state.json (existing handoff state) → rehydrated on wrapper handoff. Inner poll argv (`poll_psyche`) does NOT need to know — the bit is read by the wrapper outer loop only.

### CHANGELOG
- **New entry under next patch version.** Current head is `[1.11.8]`. Bump to `[1.11.9]`. Use the `### Changed` (user-facing) + `### BTS` (mechanics) split established by `quick-260520-uc2`. Mention prior `[1.10.26]` as the entry being corrected.

### Claude's Discretion
- Test coverage shape: at minimum, add CLI parse regression guards (default = 480, `--pulse-psyche` parses, all three commands accept the flag). Wrapper-state.json schema test if cheap. Skip subprocess-level integration tests.
- Whether to add a `WrapperState`-level unit test that asserts the resume-skip path. Add IF the existing test harness exposes the surface cheaply; skip otherwise.
- Init banner wording when `pulse_psyche == false`: include a hint like `pulse-psyche=off (cadence: echo-gate only)` or similar. Planner picks the exact phrasing.

</decisions>

<specifics>
## Specific Ideas

- The wrapper-loop site to modify is around `src/live/wrapper/mod.rs:1317-1334`. The current code reads:
  ```rust
  let is_pulse_trigger = msg.lines().any(|line| line.trim().starts_with("PULSE_TRIGGER"));
  let response = self.resume_session_checked(&msg);
  if is_pulse_trigger && response.is_none() {
      self.handle_pulse_trigger_recovery(&msg);
  }
  ```
  New shape (conceptual):
  ```rust
  let is_pulse_trigger = msg.lines().any(|line| line.trim().starts_with("PULSE_TRIGGER"));
  if is_pulse_trigger && !self.pulse_psyche {
      self.log("[PULSE] pulse-psyche=off — echo gate only; skipping resume");
      continue;  // skip resume + marker processing
  }
  let response = self.resume_session_checked(&msg);
  if is_pulse_trigger && response.is_none() {
      self.handle_pulse_trigger_recovery(&msg);
  }
  ```
  Planner verifies exact placement (must be inside the outer loop, after the `is_pulse_trigger` detection, before `resume_session_checked`).

- Prior task's regression test `live_start_default_period_becomes_zero_sentinel` (tests/cli_parse.rs) needs updating — the default is no longer 0. Either rename + flip the assertion, or replace with a new test asserting the 480 default.

- The `RESEARCH.md` from `260521-oyi` is still mostly valid for the surrounding system (echo gate, orphan detection, COMMUNE delivery). Planner should reference it for system context but not re-research the same ground.

</specifics>

<canonical_refs>
## Canonical References

- Prior task: `.planning/quick/260521-oyi-update-live-start-to-have-default-period/` — SUMMARY.md and PLAN.md document the exact code touched by sentinel-0.
- CHANGELOG: prior entry `[1.10.26] - 2026-05-21` (the entry this task corrects).
- Echo gate contract: `src/live/wrapper/echo_fire.rs` — `fire_echo_commune_if_due`, `ECHO_COMMUNE_WINDOW` (15 min), `.more-done` sentinel flow.
- Wrapper outer loop: `src/live/wrapper/mod.rs:1067-` (`WrapperState::run`); pulse trigger handling at lines ~1317-1334.
- Existing tests: `tests/cli_parse.rs` (parse_live_start_*, live_start_default_period_becomes_zero_sentinel, live_start_period_60_threads_through).

</canonical_refs>
