Skip to content

cast(phase 7): wire /quest + cast.quest.* event ledger#100

Merged
BunsDev merged 1 commit into
mainfrom
cast/phase-7-quest-wiring
May 20, 2026
Merged

cast(phase 7): wire /quest + cast.quest.* event ledger#100
BunsDev merged 1 commit into
mainfrom
cast/phase-7-quest-wiring

Conversation

@BunsDev
Copy link
Copy Markdown
Member

@BunsDev BunsDev commented May 20, 2026

Summary

  • Lands /quest <goal> (and four natural-language triggers) end to end: parser → plan card → shell loop → per-phase gate → dispatch → advance.
  • Writes cast.quest.{started, phase_started, phase_completed, advanced, completed} events to the anchor (phase-0) session so a future re-attach can reconstruct quest state from the event log.
  • Adds a minimal re-attach detector: coven attach <anchor> surfaces a one-line Quest anchor — \<title>` (phase N/M, in progress / complete)` note alongside the existing cast.summary note.
  • Closes the explicit Phase 6 deferral in docs/design/cast-quest-flow.md §7 (boxes now ticked); adds a new §8 listing what is deliberately deferred.

Scope decisions (locked at start of phase)

Question Choice
Per-phase interaction Auto-advance (no edit/skip prompt)
cast.quest.* storage First-session anchor
Daemon coverage Daemon path only; ledger writes silently skipped in local-PTY fallback
Re-attach UX Detect + inform; no full state rebuild

Gate results

  • cargo fmt --all -- --check — clean
  • cargo clippy -p coven-cli --tests --no-deps -- -D warnings — clean
  • cargo test -p coven-cli — 325 unit + 4 smoke, 0 failures (12 new tests this phase: 4 intent, 2 plan, 6 attach)

Deferred to a later phase

Documented in docs/design/cast-quest-flow.md §8:

  • Edit / skip UX per phase. set_phase_sub_prompt, skip_phase, compose_sub_prompt, QuestPhaseStatus::Skipped remain in the crate surface but reachable only via tests.
  • Full re-attach state rebuild. /attach <anchor> prints a one-liner; replaying events to reconstruct a Quest and re-render the next handoff card is the long pole.
  • Local-PTY fallback ledger. No daemon → no anchor session → no quest events.
  • `QuestPhaseStatus::Running` transition. Auto-advance loop is synchronous; the Running state is only meaningful for a future detached / async quest UX.

Test plan

  • Start the daemon (`coven daemon start`), then in a checkout where Codex or Claude Code is on PATH run `/quest fix the failing tests` inside the launcher. Confirm three handoff cards print in order (design / implement / verify) and each phase dispatches the underlying harness with the composed sub-prompt as the task.
  • After the quest completes, run `coven sessions --plain`. Confirm three distinct phase sessions exist.
  • Run `coven attach ` (the oldest of the three). Confirm the outcome card includes the `Quest anchor — ...` note.
  • Run `/quest` with no goal in the launcher. Confirm the error message names `/quest` and asks for a goal.
  • Trigger one of the natural patterns (`start a quest to ship the redesign`). Confirm the same plan card renders.
  • Cancel a phase at the gate prompt (e.g., a goal that triggers `Confirm` risk and decline). Confirm the outcome card reports the cancellation and the quest stops.

🤖 Generated with Claude Code

Phase 5 landed the standalone `cast::quest` module (data model, composer,
advance, render_quest_handoff) but the shell had no way to invoke it. The
explicit Phase 6 deferral in `docs/design/cast-quest-flow.md` §6/§7 (shell
wiring + cast.quest.* event ledger) is the entire scope of this phase.

Per the four scope answers locked at the start of Phase 7:

- **Auto-advance per phase** — Cast prints the handoff card, gates the
  sub-prompt, dispatches, waits for exit, advances. No edit / skip prompt.
- **First-session anchor** — every `cast.quest.*` event is written to
  phase 0's session log; each phase still gets its own `cast.summary`.
- **Daemon path only** — quest event writes are best-effort; in the
  local-PTY fallback (no session id) they are silently skipped.
- **Minimal re-attach** — `/attach <anchor>` surfaces a one-line note
  (`Quest anchor — `<title>` (phase N/M, in progress)`) alongside the
  existing cast.summary note. No full state rebuild.

Changes:

- `tui/cast/intent.rs` — new `CastIntent::Quest { goal }` variant.
  `/quest <goal>` slash branch and four natural-language triggers
  (`start a quest to …`, `begin a quest to …`, `quest to …`, `quest: …`).
  Empty goal errors clearly. 4 new tests.
- `tui/cast/plan.rs` — `quest_plan` builds a plan card listing the
  default design → implement → verify rhythm plus the resolved harness;
  risk is `Safe` because each phase reruns the gate against its own
  sub-prompt. 2 new tests.
- `tui/cast/quest.rs` — drops the blanket `#![allow(dead_code)]` (the
  module is no longer dead); narrows the allow to the deferred-UX surface
  (`set_phase_sub_prompt`, `skip_phase`, `compose_sub_prompt`,
  `QuestPhaseStatus::Running`/`Skipped`, convenience accessors). Doc
  comments name the Phase 7 scope decision so a future phase knows why
  they're still in the crate surface.
- `tui/cast/attach.rs` — new `find_cast_quest_info` /
  `format_quest_attach_note` helpers decode the anchor session's
  `cast.quest.{started, phase_completed, completed}` events into a
  `CastQuestAttachInfo` and a one-line outcome-card note. 6 new tests.
- `tui/cast/mod.rs` — re-exports the new helpers; trims the broad
  `#[allow(unused_imports)]` on quest types now that most are wired.
- `tui/shell.rs` — `dispatch_cast_quest` loop (build quest, render
  handoff, gate per-phase sub-prompt, dispatch via dispatch_cast_launch,
  derive QuestPhaseSummary from the cast.summary event, write the
  cast.quest.* event, advance). `attach_via_daemon` surfaces the quest
  attach note for non-live replays.
- `docs/design/cast-quest-flow.md` — ticks the §7 Phase 6 done-when boxes
  (now landed in Phase 7) and adds a §8 "Deferred to a later phase"
  section listing what auto-advance does NOT cover (edit/skip UX, full
  re-attach rebuild, local-PTY fallback ledger, async Running state).

Gates: cargo fmt clean, cargo clippy --tests -D warnings clean,
325 unit tests + 4 smoke tests pass (12 new tests in this phase).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 20, 2026 11:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR wires Cast “quests” end-to-end in the CLI TUI: parsing /quest <goal> (plus natural-language triggers), rendering/dispatching multi-phase handoffs, and recording cast.quest.* ledger events on an anchor session so coven attach <anchor> can surface minimal quest progress.

Changes:

  • Add CastIntent::Quest, plan-card support, and shell dispatch loop that gates + launches each phase and advances via cast.summary-derived QuestPhaseSummary.
  • Write cast.quest.{started,phase_started,phase_completed,advanced,completed} events to the phase-0 “anchor” session and detect/format a one-line quest note on attach.
  • Update design docs and add unit tests around intent parsing, planning, and attach quest detection.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
docs/design/cast-quest-flow.md Marks Phase 7 scope as landed; documents deferred items for future phases.
crates/coven-cli/src/tui/shell.rs Implements /quest dispatch loop and best-effort quest event ledger writes; surfaces quest note on attach.
crates/coven-cli/src/tui/cast/quest.rs Updates quest module docs and narrows dead_code allowances to deferred APIs.
crates/coven-cli/src/tui/cast/plan.rs Adds quest plan card + tests for default/no-harness behavior.
crates/coven-cli/src/tui/cast/mod.rs Re-exports new attach helpers and quest APIs for shell/tests.
crates/coven-cli/src/tui/cast/intent.rs Adds /quest parsing and natural-language quest triggers + tests.
crates/coven-cli/src/tui/cast/attach.rs Adds quest-anchor detection/formatting helpers + tests.
Comments suppressed due to low confidence (1)

crates/coven-cli/src/tui/shell.rs:658

  • Same ownership issue as above: this payload moves quest.title into the JSON value. Even after fixing the earlier cast.quest.started payload, this will still need a clone/borrow to avoid moving out of quest.
            serde_json::json!({
                "title": quest.title,
                "phase_count": quest.phases.len(),
            }),

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +595 to +596
"title": quest.title,
"goal": quest.goal,
if let Some(anchor) = anchor_session_id.as_deref() {
write_quest_event(
anchor,
CAST_QUEST_PHASE_STARTED,
Comment on lines +505 to +510
/// Event kind prefix Cast writes to the anchor session's event log so a
/// future `coven attach <anchor>` can detect that the session belongs to a
/// quest. Per the Phase 7 scope decision (first-session anchor), every
/// `cast.quest.*` event lives on phase-0's session; later phases still
/// emit their own `cast.summary` events on their own sessions.
const CAST_QUEST_STARTED: &str = "cast.quest.started";
});
let harness_note = match harness {
Some(plan_harness) => format!(
"Each phase delegates to {} unless you override the sub-prompt",
/// happy path).
pub(crate) fn format_quest_attach_note(info: &CastQuestAttachInfo) -> Option<String> {
let title = info.title.as_deref().unwrap_or("(untitled quest)");
let progress = match info.total_phases {
Comment on lines +149 to +150
- **Edit / skip UX per phase.** Phase 7 auto-advances every phase. `set_phase_sub_prompt`, `skip_phase`, `compose_sub_prompt`, `QuestHandoff`, and `QuestPhaseStatus::Skipped` are still in the crate surface but reachable only through tests; their `#[allow(dead_code)]` notes call this out.
- **Full re-attach state rebuild.** `/attach <anchor>` currently prints a one-line note ("phase N/M, in progress / complete"). Replaying `cast.quest.*` events to reconstruct a `Quest` and re-render the next handoff card is the long pole and a separate phase.
@BunsDev BunsDev merged commit c369c10 into main May 20, 2026
14 checks passed
@BunsDev BunsDev deleted the cast/phase-7-quest-wiring branch May 20, 2026 11:35
BunsDev added a commit that referenced this pull request May 20, 2026
Re-applies the two improvements the Copilot SWE bot wrote on PR #98's
branch (commit 438690b) but never landed on main, adapted to the current
quest.rs surface (phases 7-10 evolved it further). The original PR
#98 was overtaken by the squash-merges of #99 and #100; this commit
brings the bot's fix forward on its own so reviewers can read it
independently.

The two changes:

1. **Structured failure detection.** Today's `handoff_reason` keyed off
   string patterns (`failed`, `error`, `exit 1`, `interrupted`) which
   misclassified non-zero exit codes other than 1 (e.g. exit 2, 137,
   130) as success framing. New `phase_failed(summary)` helper checks
   `exit_code != 0` first, then falls back to the status-string match
   for cases where exit_code is `None` (interrupted runs).
2. **Advance over Skipped phases.** `advance` (and `skip_phase` when
   nudging the cursor) now uses a new `next_pending_index` helper so
   the cursor never lands on a Skipped or Complete row. Previously the
   shell loop carried a defensive `if matches!(..., Skipped { .. })`
   guard to walk past those rows; that guard still exists as a
   safety-net for a hypothetical async UX that mutates `cursor`
   directly, but the common path is now correct at the data layer.

Two new tests pin the behaviour:

- `advance_skips_over_skipped_phases_and_preserves_skip_reason`
- `non_zero_exit_codes_use_failure_handoff_reason`

`skip_phase_advances_cursor_and_marks_status` updated to assert quest
exhaustion (instead of "cursor lands on the skipped row") since the
new cursor advances past Skipped.

Gates: cargo fmt clean, cargo clippy --tests -D warnings clean, 346
unit + 4 smoke tests pass (2 new).

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants