<!-- event: create author: "yoi ticket" at: 2026-06-07T09:51:42Z -->

## Created

Created by LocalTicketBackend create.

---

<!-- event: plan author: hare at: 2026-06-07T09:51:42Z -->

## Plan

## Background

`yoi panel` currently attempts to ensure the workspace Orchestrator on initial panel load. If Orchestrator spawn fails, the initial `Ensure` path can surface an `unavailable` diagnostic such as a scope conflict. A later panel reload runs in `Observe` mode and may replace the header/status with plain `orchestrator missing`, making the actual failure reason disappear within a few seconds.

This makes spawn failures look like a missing-state problem and prevents the user from reading the actionable error.

Observed example while dogfooding:

```text
error: failed to create pod: requested scope `/home/hare/Projects/yoi` conflicts with pod `yoi` rule `/home/hare/Projects/yoi`
```

The scope conflict itself is expected in this situation: the current Pod is being used as the Companion and already owns workspace write scope. The UI issue is that the panel loses the prior spawn failure diagnostic on refresh.

## Goal

Keep Orchestrator lifecycle diagnostics visible across panel refreshes until superseded by a successful Orchestrator state or a newer lifecycle diagnostic.

## Requirements

- Do not change Orchestrator scope policy in this ticket.
- Preserve the distinction between:
  - `Ensure` lifecycle attempts that can spawn/restore and produce actionable failure diagnostics;
  - `Observe` refreshes that should not retry spawn.
- When an `Ensure` spawn/restore fails, keep the failure reason visible after subsequent `Observe` reloads that only report `missing`.
- Do not let stale diagnostics remain after the Orchestrator becomes live/restored/spawned successfully.
- Prefer a bounded recent lifecycle diagnostic stored in the panel/app state over recomputing or retrying spawn on every refresh.
- Make the diagnostic readable enough that short-lived errors are not lost to periodic refresh.
- Ensure actionbar Ticket gate messages, such as `attention_required is set`, do not obscure the Orchestrator lifecycle failure reason.

## Acceptance criteria

- Reproduce by causing Orchestrator spawn failure, then waiting through at least one panel refresh: the actionable failure remains visible.
- When Orchestrator later becomes live/restorable/spawned, the stale failure diagnostic is cleared or superseded.
- Plain missing state still displays when no spawn has been attempted and no prior failure exists.
- No refresh path starts retrying Orchestrator spawn implicitly.
- Focused TUI model/lifecycle tests cover diagnostic persistence and clearing.
- `cargo test -p tui ... --lib`, `cargo fmt --check`, `git diff --check`, and `target/debug/yoi ticket doctor` pass.


---

<!-- event: plan author: hare at: 2026-06-07T10:00:33Z -->

## Plan

## Delegation intent

Implement `workspace-orchestrator-spawn-diagnostic-persistence` in a dedicated worktree.

Worktree:
- `.worktree/workspace-orchestrator-spawn-diagnostic-persistence`
- branch `work/workspace-orchestrator-spawn-diagnostic-persistence`

Coder Pod:
- `orchestrator-diagnostic-coder-20260607`

Scope and boundaries:
- Keep Orchestrator scope policy unchanged. The observed scope conflict with the current `yoi` Pod is expected for dogfooding and should remain a visible diagnostic, not be solved by loosening scope.
- Preserve the current `Ensure` vs `Observe` lifecycle distinction. `Observe` refresh must not retry spawn.
- Persist or carry forward the most recent actionable Orchestrator lifecycle failure from an `Ensure` attempt so a later `Observe` result of plain `missing` does not erase it.
- Clear/supersede stale lifecycle failures when Orchestrator becomes live/restored/spawned or when a newer lifecycle diagnostic is produced.
- Keep Ticket actionbar gate messages separate from Orchestrator lifecycle diagnostics.
- Prefer a small panel/app-state model change plus focused tests over broad UI restructuring.

Relevant code map:
- `crates/tui/src/multi_pod.rs`: panel load/reload, `OrchestratorLifecycleMode::{Ensure, Observe}`, `orchestrator_lifecycle`, `spawn_orchestrator_pod`, snapshot assembly.
- `crates/tui/src/workspace_panel.rs`: panel model/header diagnostics rendering and actionbar behavior.
- `crates/client/src/ticket_role.rs`: Ticket role Pod launch path; errors from spawn/connect/initial Run should remain available to the TUI lifecycle layer.

Requested validation:
- Focused TUI tests covering diagnostic persistence and clearing.
- `cargo test -p tui ... --lib` for affected tests.
- `cargo fmt --check`.
- `git diff --check`.
- `target/debug/yoi ticket doctor`.


---

<!-- event: implementation_report author: hare at: 2026-06-07T10:10:37Z -->

## Implementation report

## Implementation report

Coder Pod `orchestrator-diagnostic-coder-20260607` completed implementation in `.worktree/workspace-orchestrator-spawn-diagnostic-persistence`.

Commit:
- `e15e9b7 fix: persist orchestrator lifecycle diagnostics`

Reported summary:
- Added `MultiPodApp` state to remember the latest actionable workspace Orchestrator lifecycle failure.
- Later `Observe` refreshes that only report plain `missing` / `stopped` keep the prior actionable diagnostic visible.
- Stored diagnostic is cleared when the Orchestrator becomes `live`, `spawned`, or `restored`.
- A newer `Unavailable` lifecycle diagnostic supersedes the older one.
- Actionbar behavior and Ticket gate messages were not changed.

Reported validation:
- `cargo test -p tui multi_orchestrator --lib`
- `cargo test -p tui --lib`
- `cargo fmt --check`
- `git diff --check`
- `nix build .#yoi`
- `./result/bin/yoi ticket doctor`

Caveat:
- `target/debug/yoi ticket doctor` was not available inside the child worktree; coder used the Nix-built binary after `nix build .#yoi`.

External review will be delegated before merge.


---

<!-- event: review author: hare at: 2026-06-07T10:15:40Z status: approve -->

## Review: approve

Approved by `orchestrator-diagnostic-reviewer-20260607`.

No blocking findings. The implementation matches the ticket intent and is merge-ready.

Evidence:
- `Ensure` vs `Observe` is preserved. Initial load uses `Ensure`; refresh paths use `Observe`; observe does not restore/spawn.
- Prior actionable failure is retained across plain observe `missing` / `stopped` for the same Pod name.
- Plain missing without prior failure remains plain missing.
- Stale failures are cleared when Orchestrator becomes `live`, `spawned`, or `restored`.
- New `Unavailable` diagnostics supersede older ones.
- Ticket actionbar gating remains separate; lifecycle diagnostics remain in `panel.header.diagnostics`.
- Worktree is clean and merge-tree against current `develop` reports no conflict.

Reviewer validation:
- `CARGO_TARGET_DIR=/tmp/yoi-review-target cargo test -p tui multi_orchestrator --lib`
- `CARGO_TARGET_DIR=/tmp/yoi-review-target cargo test -p tui --lib`
- `cargo fmt --check`
- `git diff --check develop...HEAD`
- `nix build .#yoi --no-link`
- `CARGO_TARGET_DIR=/tmp/yoi-review-target cargo run -p yoi -- ticket doctor`


---

<!-- event: state_changed author: hare at: 2026-06-07T10:16:08Z from: intake to: done reason: closed field: workflow_state -->

## State changed

Ticket closed; workflow_state set to done.


---

<!-- event: close author: hare at: 2026-06-07T10:16:08Z status: closed -->

## Closed

Implemented, reviewed, merged, and validated.

Summary:
- Added panel/app state to retain the latest actionable workspace Orchestrator lifecycle failure.
- Subsequent `Observe` refreshes that only report plain `missing` / `stopped` keep the prior actionable diagnostic visible.
- Stale diagnostics are cleared when Orchestrator becomes `live`, `spawned`, or `restored`.
- New `Unavailable` lifecycle diagnostics supersede older failures.
- Orchestrator scope policy was unchanged.
- `Observe` refresh still does not retry spawn.
- Ticket actionbar gate messages remain separate from Orchestrator lifecycle diagnostics.

Implementation:
- Child commit: `e15e9b7 fix: persist orchestrator lifecycle diagnostics`
- Merge commit: `merge: orchestrator diagnostic persistence`

Review:
- External reviewer `orchestrator-diagnostic-reviewer-20260607` approved with no blockers.

Validation after merge:
- `cargo test -p tui multi_orchestrator --lib`
- `cargo test -p tui --lib`
- `cargo fmt --check`
- `git diff --check`
- `target/debug/yoi ticket doctor`


---
