yoi/work-items/open/20260605-190330-tui-ticket-role-actions/thread.md

16 KiB

Created

Created by tickets.sh create.


Plan

Plan: implement after ticket-role-pod-launcher lands.

TUI should expose explicit user-triggered Ticket role actions/commands and call the shared launcher. It should not duplicate profile/config/prompt/workflow launch construction, introduce automatic scheduling, or add a spawned-Pod panel in this ticket.


Plan

Delegation intent: TUI Ticket role actions

Intent

Add explicit TUI commands/actions that launch fixed Ticket-role Pods through the shared client Ticket role launcher.

TUI should not duplicate role/profile/workflow/prompt construction. It should parse user commands, build a typed launcher context, call the client launcher, and surface success/failure diagnostics in the TUI.

Worktree / branch

  • worktree: /home/hare/Projects/yoi/.worktree/tui-ticket-role-actions
  • branch: work/tui-ticket-role-actions

Dependencies

ticket-role-pod-launcher is complete and merged. Use the client API added there:

  • client::TicketRoleLaunchContext
  • client::TicketRef
  • client::launch_ticket_role_pod
  • related launch errors/result types

Requirements

  • Add user-triggered TUI commands for fixed Ticket roles.
  • Prefer a single :ticket <action> ... command if it fits the current command parser.
  • Support at least these actions:
    • :ticket intake <context...>
    • :ticket route <ticket-id-or-slug> [instruction...]
    • :ticket investigate <ticket-id-or-slug> [instruction...]
    • :ticket implement <ticket-id-or-slug> [instruction...]
    • :ticket review <ticket-id-or-slug> [instruction...]
  • Map actions to roles:
    • intake -> TicketRole::Intake
    • route -> TicketRole::Orchestrator
    • investigate -> TicketRole::Investigator
    • implement -> TicketRole::Coder
    • review -> TicketRole::Reviewer
  • Use the shared launcher; do not build SpawnConfig, Profile selectors, Workflow segments, or first-run prompt content directly in TUI.
  • Make command parsing/test behavior deterministic.
  • Surface launcher failures as TUI command/actionbar diagnostics without crashing.
  • Make UnsupportedInheritProfile especially clear: the user must configure a concrete role profile in .yoi/ticket.config.toml for top-level TUI launches.
  • Keep actions explicit and user-triggered; no scheduler/automation.
  • Do not add spawned-Pod panel or dashboard redesign.
  • Do not add arbitrary role registry UI.

Current code map

  • crates/tui/src/command.rs
    • Current command registry is synchronous and returns CommandExecution { method: Option<Method>, diagnostics, ... }.
    • Existing commands are help, noop, compact, rewind, and peer.
    • Add a command action variant or equivalent so command parsing can request a Ticket role launch without overloading protocol::Method.
  • crates/tui/src/app.rs
    • submit_command / apply_command_execution currently return Option<Method>.
    • May need a small result enum to carry either a Pod Method or a TUI-local action.
  • crates/tui/src/single_pod.rs
    • Has PodRuntimeCommand at launch entrypoints, but run_loop currently only receives App + PodClient.
    • To execute role launch commands, pass PodRuntimeCommand into the loop/handler where needed.
    • Command execution can call client::launch_ticket_role_pod(...) asynchronously and then show success/error notice.
  • crates/client/src/ticket_role.rs
    • Shared launcher API; use this instead of duplicating launch construction.

Command semantics

MVP command syntax:

:ticket intake <context...>
:ticket route <ticket-id-or-slug> [instruction...]
:ticket investigate <ticket-id-or-slug> [instruction...]
:ticket implement <ticket-id-or-slug> [instruction...]
:ticket review <ticket-id-or-slug> [instruction...]

For non-intake actions, treat the first argument as a Ticket id/slug. It is acceptable to use TicketRef::slug(value) in the MVP unless a clear id/slug parser already exists.

For intake, allow freeform context and no Ticket id.

Pod name may use the launcher default unless command syntax for --name is easy; do not overbuild CLI parsing.

Non-goals

  • Implementing the role launcher.
  • Prompt resource resolution.
  • Stateful workflow engine.
  • Worktree creation automation.
  • Multi-Pod dashboard redesign.
  • Spawned-Pod panel.
  • Scheduler/lease/queue automation.
  • Generic role registry/UI.
  • Arbitrary filesystem Ticket edits.

Validation

Run at least:

  • focused command parsing/action tests;
  • cargo test -p tui ticket --lib or relevant focused TUI tests;
  • cargo test -p client ticket;
  • cargo check --workspace --all-targets;
  • cargo fmt --check;
  • git diff --check;
  • ./tickets.sh doctor.

Run nix build .#yoi --no-link if feasible.

Completion report

Report:

  • worktree path / branch;
  • commit hash;
  • command syntax implemented;
  • how command execution calls the shared launcher;
  • how diagnostics are surfaced;
  • validation results;
  • unresolved risks/follow-ups;
  • whether ready for external review.

Review: approve

External review: tui-ticket-role-actions

1. Result: approve after blocker fix

Initial review requested changes because :ticket intake accepted missing context. Re-review of commit d288fa590188bb700257e3cfa386b168661d9613 confirms that blocker is resolved and no new blocker was introduced.

2. Summary of implementation

The commit adds a new :ticket <action> ... TUI command in crates/tui/src/command.rs, carries successful parses as a TUI-local CommandAction::TicketRole, stores the pending local action on App, and handles it from the single-Pod event loop in crates/tui/src/single_pod.rs.

Execution builds a TicketRoleLaunchContext with the current working directory, fixed TicketRole, optional TicketRef::slug(...), and optional freeform instruction, then calls client::launch_ticket_role_pod(...). The TUI does not construct SpawnConfig, profile selectors, workflow invocation segments, or prompt contents directly. crates/client/src/ticket_role.rs only reexports TicketRole for this TUI-facing use.

3. Requirement-by-requirement assessment

  • Command syntax: Met after d288fa590188bb700257e3cfa386b168661d9613. Implemented nested syntax close to the requested surface:
    • :ticket intake <context...> parses when context is present, and :ticket intake / whitespace-only context now reject with Invalid arguments. Usage: ticket intake <context...>.
    • :ticket route <ticket-id-or-slug> [instruction...], investigate, implement, and review require a first ticket reference and preserve remaining text as instruction.
  • Role mapping: Met. Mappings are intake -> Intake, route -> Orchestrator, investigate -> Investigator, implement -> Coder, review -> Reviewer.
  • Shared launcher use: Met. single_pod.rs builds only TicketRoleLaunchContext and calls launch_ticket_role_pod(...); no TUI-side SpawnConfig, profile semantics, workflow segments, or prompt construction were introduced.
  • Command action plumbing locality: Met. The new CommandAction path is local, and existing compact, rewind, peer, help, and completion behavior remains structurally unchanged. Full cargo test -p tui --lib also passed.
  • PodRuntimeCommand threading: Met. The value is passed narrowly into the single-Pod run loop and command-action handler so the shared launcher can spawn the role Pod.
  • Diagnostics: Met for the reviewed command requirements. Success and failure are surfaced through actionbar notices, UnsupportedInheritProfile gets a clear TUI-specific message, missing non-intake ticket references are diagnosed, and missing intake context is now diagnosed.
  • Unsupported inherit profile explanation: Met. The special-case message clearly tells the user to configure concrete role profiles in .yoi/ticket.config.toml for top-level TUI ticket launches.
  • Non-goals / scope control: Met. I did not find scheduler/automation, spawned-Pod panel, dashboard redesign, generic role UI, prompt resolution, worktree automation, or arbitrary Ticket filesystem edits.
  • Tests: Met for the blocker fix. Parsing and context construction tests exist, an inherit-profile diagnostic formatting test exists, and focused parser coverage now rejects missing/whitespace-only intake context. The launcher execution path is still covered indirectly by context construction rather than by a mocked launcher call/actionbar transition.
  • Validation: Met for the commands I reran; see section 6.

4. Blockers

No blockers remain after d288fa590188bb700257e3cfa386b168661d9613.

  • Resolved: :ticket intake previously accepted an empty context; it now rejects missing or whitespace-only context with Invalid arguments. Usage: ticket intake <context...>, and focused parser coverage was added.

5. Non-blockers / follow-ups

  • The Launching ticket ... Pod... actionbar notice is set immediately before awaiting launch_ticket_role_pod(...) (crates/tui/src/single_pod.rs:563-589). Because the event loop does not redraw between setting that notice and awaiting the launch, users may only see the final success/failure notice for slow launches. This is acceptable for this MVP, but a follow-up could force a draw or move launch work to an async task if start-progress visibility matters.
  • Help text for :ticket names the fixed actions but does not explain each role individually. The behavior is discoverable enough for MVP, but richer :help ticket text would better satisfy the acceptance criterion that command/action help makes clear what each role does.
  • Execution-path tests stop at context construction and error formatting. A future small seam around the launcher call would allow direct tests for actionbar success/failure plumbing without spawning real Pods.

6. Validation assessed or rerun

Reran from /home/hare/Projects/yoi/.worktree/tui-ticket-role-actions:

  • git diff --check — passed.
  • cargo test -p tui ticket --lib — passed, 5 tests.
  • cargo test -p client ticket — passed, 6 tests.
  • cargo fmt --check — passed.
  • cargo check --workspace --all-targets — passed.
  • ./tickets.sh doctor — passed (doctor: ok).
  • cargo test -p tui --lib — passed, 224 tests.
  • cargo test -p client — passed, 11 tests plus doc-tests.
  • nix build .#yoi — passed; Nix emitted a dirty-tree warning for the worktree. The transient result symlink created by Nix was removed afterward; git status --short showed no tracked changes.

7. Residual risk

After the intake-context diagnostic is fixed, residual risk is low. The implementation stays within the intended TUI-command surface and delegates launch semantics to the client launcher. The remaining risks are mostly UX/test-depth issues around live launch progress visibility and lack of a direct mocked launcher execution test.

8. Re-review of blocker fix (d288fa590188bb700257e3cfa386b168661d9613)

Result: approve

The blocker is resolved. The fix updates ticket_args so intake now requires at least one non-whitespace argument and returns Invalid arguments. Usage: ticket intake <context...> when context is missing. The existing ticket_command path then continues to pass the non-empty intake context as instruction, with no Ticket reference, preserving the intended Intake launch behavior.

Focused parser coverage was added for both :ticket intake and whitespace-only :ticket intake rejection. The change is limited to crates/tui/src/command.rs; I did not find any new blocker or source-scope expansion in this fix.

Validation rerun from /home/hare/Projects/yoi/.worktree/tui-ticket-role-actions:

  • cargo test -p tui ticket_intake --lib — passed.
  • cargo test -p tui ticket --lib — passed.

No additional full-build validation was rerun for this narrow parser-only fix.


Implementation report

Implementation report: tui-ticket-role-actions

Worktree / branch

  • Worktree: /home/hare/Projects/yoi/.worktree/tui-ticket-role-actions
  • Branch: work/tui-ticket-role-actions

Commits

  • e125ebb feat: add TUI ticket role commands
  • d288fa5 fix: require TUI ticket intake context

Summary

Added explicit TUI :ticket commands that launch fixed Ticket-role Pods through the shared client Ticket role launcher.

TUI now parses role actions, builds a TicketRoleLaunchContext, and calls client::launch_ticket_role_pod(...). TUI does not construct SpawnConfig, profile selector semantics, workflow invocation segments, or first-run prompt content directly.

Command syntax

Implemented commands:

:ticket intake <context...>
:ticket route <ticket-id-or-slug> [instruction...]
:ticket investigate <ticket-id-or-slug> [instruction...]
:ticket implement <ticket-id-or-slug> [instruction...]
:ticket review <ticket-id-or-slug> [instruction...]

Role mapping:

  • intake -> TicketRole::Intake
  • route -> TicketRole::Orchestrator
  • investigate -> TicketRole::Investigator
  • implement -> TicketRole::Coder
  • review -> TicketRole::Reviewer

intake requires non-empty context. Non-intake actions require a Ticket id/slug and preserve remaining text as the instruction.

Changed files

  • crates/client/src/ticket_role.rs
  • crates/tui/src/app.rs
  • crates/tui/src/command.rs
  • crates/tui/src/single_pod.rs

TUI plumbing

  • Added CommandAction::TicketRole(...) as a TUI-local command action.
  • CommandExecution can now carry either a Pod protocol method or local command action.
  • App stores a pending command action after command submission.
  • single_pod.rs handles the pending Ticket role action asynchronously and calls the shared client launcher.
  • PodRuntimeCommand is passed narrowly into the single-Pod run loop/command-action handler so the launcher can start the role Pod.

Diagnostics

  • Launch start/success/failure are surfaced through actionbar notices.
  • UnsupportedInheritProfile has a TUI-specific message explaining that top-level TUI Ticket launches require concrete role profiles in .yoi/ticket.config.toml until an inheritance-aware launch path exists.
  • Missing non-intake Ticket refs and missing intake context return command diagnostics.

Review status

External sibling review initially requested one blocker fix:

  • :ticket intake accepted missing/whitespace-only context.

The blocker was fixed in d288fa5, and re-review approved with no blockers.

Remaining non-blocker follow-ups:

  • Start-progress actionbar notice may be overwritten by final success/failure before a redraw during slow launches.
  • :help ticket could describe each role in more detail.
  • Execution-path tests stop at context construction/error formatting; a future launcher seam could test success/failure actionbar plumbing without spawning real Pods.

Validation

Coder-reported validation for the initial implementation passed:

  • cargo test -p tui ticket --lib
  • cargo test -p client ticket
  • cargo check --workspace --all-targets
  • cargo fmt --check
  • git diff --check
  • ./tickets.sh doctor
  • nix build .#yoi --no-link

Reviewer-rerun validation passed:

  • git diff --check
  • cargo test -p tui ticket --lib
  • cargo test -p client ticket
  • cargo fmt --check
  • cargo check --workspace --all-targets
  • ./tickets.sh doctor
  • cargo test -p tui --lib
  • cargo test -p client
  • nix build .#yoi

Coder-reported validation for blocker fix passed:

  • cargo test -p tui ticket --lib
  • cargo fmt --check
  • git diff --check
  • ./tickets.sh doctor

Reviewer re-ran focused blocker validation:

  • cargo test -p tui ticket_intake --lib
  • cargo test -p tui ticket --lib

Ready for merge

Yes.