Skip to content

cast(phase 6): land Phase 1 launcher + verification#99

Merged
BunsDev merged 16 commits into
mainfrom
cast/phase-6-readiness
May 20, 2026
Merged

cast(phase 6): land Phase 1 launcher + verification#99
BunsDev merged 16 commits into
mainfrom
cast/phase-6-readiness

Conversation

@BunsDev
Copy link
Copy Markdown
Member

@BunsDev BunsDev commented May 20, 2026

Summary

  • Lands the Phase 1 launcher contract in tui/shell.rs::render_magical_tui_frame_with_mode_and_width — Phase 3 had added 10 tests for the contract but the implementation was never written. The launcher tests were red on this branch line; they're green now.
  • Replaces the pre-contract launcher chrome (CovenCLI header, ASCII workspace map, task inbox, "Selected command", "Store: ~/.coven", +--+ corner art) with the contract layout: Cast identity, thin rule prompt, two-lane Commands rail + Snapshot body with selection marker + N of 14 scroll hint, spell/detail action preview, single DIM footer hint.
  • Reconciles docs/start/coven-tui.md with reality (slash table now lists the 14 real commands; keyboard shortcuts match shell.rs::run).
  • Adds docs/design/cast-phase6-inspection.md with captured launcher frames at widths 76 + 96 and an explicit "what was NOT tested / risks open" section so reviewers can pick up the gaps.

Gate results

  • cargo fmt --all -- --check — clean
  • cargo clippy -p coven-cli --tests --no-deps -- -D warnings — clean
  • cargo test -p coven-cli — 313 unit + 4 smoke, 0 failures

Risks open before merge

  • theme::BORDER_SUBTLE / theme::BORDER_STRONG are still dead code (4 cargo build warnings). The Phase 1 contract added the tokens; no renderer plumbed them in. Doesn't fail any gate but signals an incomplete handoff.
  • Cast non-interactive (piped) frame still uses pre-contract copy (em-dash headline, capitalised labels, second-person address). Pinned by Phase 1 tests; deliberately out of scope.
  • docs/ROADMAP.md and docs/PRODUCT-SPEC.md unchanged. "Visible work" thesis intact; roadmap not updated since 2026-05-09 and does not yet mention the Cast redesign.

Test plan

  • Open coven in a real terminal at width 80 and width ≥ 96. Confirm Cast identity row is the only PRIMARY_STRONG accent at the top, the prompt sits between two rules, and the Commands rail shows 6 items with next to the selection.
  • Arrow through to /sacrifice (item 13). Confirm the rail scrolls and 13 of 14 renders under the rail.
  • Type into the prompt. Confirm the placeholder fades from DIM to TEXT as the cursor advances; Ctrl+U clears it.
  • Resize the terminal mid-session. Confirm rules and lanes track the new width.
  • Run coven </dev/null. Confirm the non-interactive Cast frame still renders (regression check).

🤖 Generated with Claude Code

BunsDev and others added 12 commits May 19, 2026 07:32
PR #93 already shipped the Cast event follower, transcript renderer, exit
summary, `cast.summary` event writer, and stdin forwarding for *newly
launched* sessions. The remaining Phase 2 gap was `/attach` and `/summon`:
those still routed through the legacy `attach_session` loop in main.rs,
which uses a HashSet<String> for dedup and reads from the SQLite store
directly — bypassing the daemon's `/events` endpoint and `afterSeq` cursor.

This commit closes the gap.

New `cast/attach.rs`:
- `CastAttachSummary` + `find_cast_summary` decode the most recent
  `cast.summary` event from a session's history so the attach outcome can
  describe what the prior run did.
- `summary_already_recorded` lets the launch-side writer skip a duplicate
  summary when attach replays existing events through the same follower.
- `format_summary_note` renders the decoded summary as a one-line outcome
  card note (status, exit code, harness, request — truncated to 60 chars).

`shell.rs` wiring:
- New `attach_via_cast` dispatcher: live sessions stream through
  `follow_until_exit` with the same `afterSeq` cursor as launches and accept
  stdin forwarding; completed sessions replay the full event log through
  the same `TranscriptObserver` so the user sees the transcript shape they'd
  see at original launch, then surface the prior `cast.summary` in the
  outcome.
- Falls back to the legacy `attach_session` loop when the daemon isn't
  running, with an outcome note explaining the fallback.
- `write_cast_summary_event` is now idempotent — guards against double-logging
  when an attach replay reaches the exit event a second time.
- New `AttachOrigin` enum distinguishes `/attach` from `/summon` in the
  outcome card's `launched` label.

`main.rs`:
- Extract `summon_only_command` from `summon_session_command` so Cast can
  un-archive without dragging in the legacy attach loop. The top-level
  `coven summon` CLI behaviour is unchanged.

Tests: 14 new (11 in `cast::attach`, 3 in `shell::attach_tests` covering
AttachOrigin labels and `replay_completed_session` over a stub client).
Total: 275 unit + 4 smoke tests pass. cargo fmt clean, clippy clean,
diff --check clean. Non-interactive `coven` smoke renders the Cast frame
and exits 0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Defines the sleek-minimalist Cast Codes target so Phase 2 has rules to
implement against: surfaces in scope, the 14-char field column,
hierarchy order, color roles re-anchored on PRIMARY_STRONG (#9A8ECD),
the chip system for risk states, copy tone, and twelve explicit
anti-patterns lifted from the current launcher (workspace map graph,
fake task inbox, +---+ ASCII chrome, repeated brand voice, Store
footer, etc.). Ends with the file seam Phase 2 will edit and a
done-when checklist.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Defines the sleek-minimalist Cast Codes target so Phase 2 has rules to
implement against: surfaces in scope, the 14-char field column,
hierarchy order, color roles re-anchored on PRIMARY_STRONG (#9A8ECD),
the chip system for risk states, copy tone, and twelve explicit
anti-patterns lifted from the current launcher (workspace map graph,
fake task inbox, +---+ ASCII chrome, repeated brand voice, Store
footer, etc.). Ends with the file seam Phase 2 will edit and a
done-when checklist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rework the launcher and theming across the TUI: replace the old "CovenCLI" identity with "Cast" and update tests to match the new wording and layout. Add several new theme tokens and helpers (SURFACE_0, SURFACE_3, BACKDROP, TEXT, TEXT_DIM, BORDER_DIM, SCROLL_TRACK), a Status semantic with status_token/status_style, a Palette helper, and a reusable fit_chars utility with tests. Remove duplicated fit_chars implementations and import theme::fit_chars where needed. Refactor cast renderer to use a LauncherSnapshot model and a two-column command+snapshot layout, introduce new rendering helpers (push_line, push_snapshot_row, render_paired_line, launcher_command_window, RowCell), use the U+203A selection marker, and simplify prompt/footer/preview rendering. Update chat renderers to use the new theme tokens (text, dim, border, scroll track, status_style) and replace ad-hoc color choices with semantic tokens. Adjust sessions and shell code to consume the shared utilities.
Plan/outcome cards now follow the Phase 1 TUI visual contract: a 14-char
label column, fixed-width ALL-CAPS risk chips ([  SAFE  ] / [CONFIRM ] /
[ REJECT ]) colored by severity, noun-first risk reasons as continuation
rows (no `!`/`X` glyphs), numbered step list capped at four, and a
risk-aware footer hint. Sacrifice plans now ask for the typed `sacrifice`
word in the footer; rejected plans steer the user to reframe.

Execution semantics are unchanged: planner output, safety classification,
and gate behavior are untouched — only the renderer (and the theme tokens
the renderer leans on) moved.

Also adds `BORDER_SUBTLE` / `BORDER_STRONG` semantic tokens so future
single-rule separators have a brand-aligned color, mirroring the
`--oc-border-subtle` / `--oc-border-strong` CSS variables.

Tests assert key labels, every risk chip, harness-source copy
(`Cast default` / `user-chosen`), the typed-confirm footer for sacrifice,
the intent-row fallback for system actions, step/note caps, and that
plain output never leaks an ANSI escape across any risk state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds cast::quest, a pure module that decomposes a high-level user goal into
an ordered Quest of phases (design → implement → verify by default). Each
phase carries a concrete sub_prompt the harness will receive; advance()
attaches a structured QuestHandoff from the prior phase and recomposes the
next sub_prompt deterministically, while preserving any user-authored
override. render_quest_handoff() turns the handoff into a visible card —
source phase, prior status, carried context, target harness, and the
verbatim sub-prompt — so every delegation is inspectable before it lands.

No LLM planner is introduced; sub-prompts are assembled from structured
templates plus the recorded prior outcome. The cast shell wiring for a
`/quest <goal>` intent is left as the next-phase seam and documented in
docs/design/cast-quest-flow.md.

Covered by 15 new unit tests (11 in cast::quest, 4 in cast::render) for
the composer, advancer, edits, skip, failure framing, long sub-prompt
clipping, and quest exhaustion. Full cast suite: 105/105 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`cargo fmt --check` flagged unformatted regions in three Cast modules left
over from earlier phases. No behavior change; pure formatting cleanup so
the next render-touching commit produces a minimal diff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3 added 10 launcher tests for the Phase 1 design contract but never
landed the implementation -- the renderer in
`tui/shell.rs::render_magical_tui_frame_with_mode_and_width` was still the
pre-contract code (CovenCLI header, ASCII workspace map, task inbox,
"Selected command", "Store: ~/.coven", `+--+` chrome) and the launcher
tests were all failing.

Rewrite the launcher against
[`docs/design/cast-tui-contract.md`](docs/design/cast-tui-contract.md):

- `Cast` identity row in `PRIMARY_STRONG`.
- Single thin `─` rule above and below the prompt -- no bezels, no
  `Ask anything` label.
- Two-lane body: `Commands` rail (windowed, 6 visible, `›` selection
  marker, `N of 14` scroll hint) + `Snapshot` lane (project / harness /
  daemon, resolved best-effort).
- `spell` / `detail` field rows preview the selected slash command.
- One `DIM` footer hint: `enter run · ↑↓ select · esc quit · ctrl+u clear`.

Delete the workspace-map, status, task-inbox, and input-box helpers.
Replace `>` with the U+203A `›` marker. All 10 previously-failing
`magical_tui_frame_*` tests now pass; full `cargo test -p coven-cli`
green (313 unit + 4 smoke).

Reconcile `docs/start/coven-tui.md` with the implementation:

- Slash command table now lists the 14 real commands (was claiming
  `/clear`, `/export`, `/agent` which do not exist).
- Keyboard shortcuts match `shell.rs::run` (drop `h`, `Tab`, `Ctrl+L`;
  add `Backspace`, `Ctrl+U`).
- Arrow-key prose describes the Commands rail, not session-browser
  rituals.
- Intro names Cast and the spell-parser flow.

Add `docs/design/cast-phase6-inspection.md` with the captured NoColor
launcher frames at width=76 and 96 for selection=0 (empty + typed) and
selection=12 (`/sacrifice`), the live non-interactive Cast frame, gate
results, and explicit "what was not tested" / "risks open before merge"
sections.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 20, 2026 09:30
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 implements the Phase 1 “Cast” launcher contract in the CLI TUI (previously only covered by tests), updates Cast rendering primitives and attach/summon flows to better match the new transcript/outcome shape, and reconciles user + design documentation with the new UI.

Changes:

  • Rewrites the launcher frame renderer in tui/shell.rs to the Cast contract layout (identity row, thin-rule prompt, windowed Commands rail + Snapshot lane, compact action preview, single footer hint).
  • Introduces Cast attach helpers + quest flow rendering/logic, and improves attach/summon handling via daemon follower + summary notes.
  • Updates docs to reflect the new launcher behavior/command set and adds Phase 6 verification artifacts.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
docs/start/coven-tui.md Updates end-user TUI docs to describe Cast launcher, commands, and shortcuts.
docs/design/cast-tui-contract.md Adds the Phase 1 visual/design contract for Cast TUI surfaces.
docs/design/cast-quest-flow.md Adds the Phase 5 quest-flow design contract and wiring notes.
docs/design/cast-phase6-inspection.md Adds Phase 6 verification notes with captured frames and manual-check guidance.
crates/coven-cli/src/tui/shell.rs Implements Cast launcher layout; adds daemon-based attach/replay path and summary idempotence.
crates/coven-cli/src/tui/sessions.rs Deduplicates truncation helper by using theme::fit_chars.
crates/coven-cli/src/tui/chat/render.rs Aligns Ratatui chat rendering colors with semantic theme tokens.
crates/coven-cli/src/tui/cast/render.rs Refactors Cast plan/outcome rendering to contract-style rows/chips; adds quest handoff card renderer.
crates/coven-cli/src/tui/cast/quest.rs Adds deterministic quest model + composer + advancer with unit tests.
crates/coven-cli/src/tui/cast/mod.rs Exposes new Cast modules/helpers (attach + quest) to the shell.
crates/coven-cli/src/tui/cast/attach.rs Adds helpers to decode/format cast.summary for attach outcome notes.
crates/coven-cli/src/theme.rs Adds semantic tokens (backdrop, scroll track, border colors, text roles) + palette/status helpers + shared fit_chars.
crates/coven-cli/src/store.rs Adds event_kind_exists query helper with unit test.
crates/coven-cli/src/main.rs Refactors summon into summon_only_command for Cast-driven summon+attach flow.

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

Comment on lines +856 to +869
// For completed/replayed sessions, surface the original Cast summary so
// the user can see what the prior run was about. Live attaches just wrote
// the summary themselves, so showing it again would only echo the exit
// line we already printed.
if !is_live {
let history = client.list_events(ChatEventQuery {
session_id: &session.id,
after_seq: None,
limit: None,
})?;
if let Some(note) = cast::find_cast_summary(&history).and_then(|s| format_summary_note(&s))
{
notes.push(note);
}
Comment on lines +391 to +400
/// `label value` row with a fixed 14-char label column. Two-space gap
/// before the value so the eye locks onto a single value column across the
/// whole frame.
fn push_label_row(frame: &mut String, p: &Palette, label: &str, value: &str) {
let label_block = format!("{:<width$}", label, width = LABEL_COLUMN_WIDTH);
frame.push_str(&format!(
"{}{}{} {}{}{}\n",
p.field_label, label_block, p.reset, p.text, value, p.reset
));
}
Cast, your Coven familiar, is ready. Type a spell, or use a slash command.

Context
Project /Users/buns/Documents/GitHub/OpenCoven/coven
BunsDev and others added 4 commits May 20, 2026 04:37
The Phase 1 contract added `theme::BORDER_SUBTLE` and `theme::BORDER_STRONG`
but no renderer plumbed them in, leaving four `dead_code` warnings on every
build. Apply them per the docstrings in theme.rs:

- Top rule above the prompt → `BORDER_SUBTLE` (quiet panel separator)
- Bottom rule below the prompt → `BORDER_STRONG` (focused underline; the
  launcher prompt is always the interactive element)

`cargo build -p coven-cli` no longer emits any warnings. Gates remain
green (fmt, clippy --tests -D warnings, 313 unit + 4 smoke).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Cast redesign (Phases 1–6 on `cast/*` branches) is the largest in-flight
Coven runtime change and was not yet on the public roadmap. Add it under
`Coven > Now` with links to the visual contract and quest-flow design docs
and a pointer to PR #99 as the current review slice. Refresh the
"Last updated" stamp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Cast non-interactive frame (printed when `coven` runs without a TTY)
shipped with three contract violations called out in `cast-tui-contract.md`
§2.6 and §3:

- "Cast — your Coven familiar" headline used an em-dash decoration and
  lampshaded the familiar's name.
- "Cast, your Coven familiar, is ready. Type a spell, or use a slash
  command." used second-person greeting + "is ready" copy that §2.6
  forbids.
- "Project" and "Default harness" field labels were Title Case; §2.3
  requires lowercase labels in a fixed 14-char column.
- Two consecutive `Tip:` lines (one from `render_cast_frame_with_mode`,
  one appended by `print_cast_non_interactive_frame`) repeated the same
  instruction.

Tighten to:

- Identity row: `Cast` alone (PRIMARY_STRONG), no decoration.
- One subtitle line in `FIELD_LABEL`:
  `Coven familiar · type a spell or pick a slash` -- keeps the brand
  positioning without second-person greeting or lampshading.
- `project` / `harness` field rows now use the shared `push_label_row`
  helper so they live in the canonical 14-char label column alongside
  the plan and outcome cards.
- Single dim footer hint:
  `run \`coven\` in a terminal to open the launcher · empty input runs a slash`.
  Drops the duplicate `Tip:` println from the shell-level printer.

All `cast_non_interactive_frame_*` and `non_interactive_frame_*` tests
still pass -- the "Coven familiar" substring lives in the subtitle, and
the project / harness assertions match the new lowercase labels by
substring. Full `cargo test -p coven-cli` green (313 unit + 4 smoke);
fmt and clippy --tests -D warnings clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@BunsDev BunsDev merged commit 48b60f3 into main May 20, 2026
8 checks passed
@BunsDev BunsDev deleted the cast/phase-6-readiness branch May 20, 2026 09:53
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.

3 participants