<!-- STATUS: DRAFT -->

# UA Testing: Phase 17 — TUI Screens and Interaction Flows

## Review Findings (Code Review Pass)

These issues were found during the independent code review. Flag during UA testing if any surface.

### RF-01 · BUG (High) — `call_later` used for timed exit — app may hang after "Case Closed"

**Location:** `src/unfamiliar/tui/app.py:487`

```python
self.call_later(3.0, self.exit)
```

**Issue:** In Textual, `call_later(callback)` schedules for the next event loop iteration — it does **not** accept a delay parameter. The first argument is treated as the callback, so `3.0` (a float) becomes the callable. This will either raise `TypeError: 'float' object is not callable` or silently no-op, preventing the app from exiting after "Case Closed."

**Expected fix:** `self.set_timer(3.0, self.exit)`

**How to trigger:** Run `end campaign`, confirm. Watch whether the app exits after ~3 seconds.

---

### RF-02 · Style (Medium) — Deferred imports in `confirm.py`

**Location:** `src/unfamiliar/tui/screens/confirm.py:73-74` and `98-99`

`Container`, `Horizontal`, and `Key` are imported inside methods rather than at the top of the file. No circular import risk justifies this. Should be moved to top-level imports per project standards.

Not a functional bug — style issue for the next cleanup pass.

---

### RF-03 · Note — Dead null guards in `app.py`

**Location:** `app.py:174` and `app.py:434`

`if self.router is None: return` — `self.router` is set unconditionally in `__init__` and never reassigned to None. These guards are dead code. Minor — note for cleanup.

---

### RF-04 · Structural note — `end campaign` unreachable via canonical lookup

**Location:** `src/unfamiliar/tui/commands.py:152-155`

The canonical name lookup only matches on the first word. `end campaign` (two-word canonical) can only be reached via a theme alias. This works because the Film Noir theme has an alias, but it's an implicit dependency. Document or fix for robustness.

---

## Quick Smoke Tests (2–5 min)

These verify the app launches and basic navigation works. Run first.

### S1: App launches with seeded data
```bash
cd /path/to/repo
python3 -m unfamiliar investigate /path/to/seeded/campaign
```
- [x] TUI launches without error
- [x] Header shows investigation name and progress counts
- [x] Welcome message appears in content area

### S2: Welcome message variants
Re-launch after each state to verify contextual welcome:
- [ ] **Has in-progress mission**: "Welcome back, Detective. You were investigating: {title}. Type 'mission' to review..."
- [x] **No in-progress, has available**: "Welcome back, Detective. You have N leads waiting. Type 'next' to see them."
- [ ] **All closed/locked**: "Welcome back, Detective. All leads are closed or locked. Type 'status'..."

### S3: Quit without active mission
- [x] Press `q` → exits immediately, no confirmation dialog
- [x] Type `quit` → exits immediately

---

## Priority 1 Tests (15–20 min)

### P1-A: Mission listing and selection

**Test: `next` shows numbered mission list**
1. Launch TUI on a seeded campaign
2. Type `next`
- [x] Content area shows "Available Leads" with numbered entries `[1]`, `[2]`, etc.
- [x] Each entry shows category, difficulty, time
- [x] Hint text says "Type 'next <N>' to start a lead, or 'mission <N>' to peek."

**Test: `mission <N>` peeks without starting**
1. Type `next` to populate list
2. Type `mission 1`
- [x] Mission detail appears in content area
- [x] Mission status is still "Available" (not In Progress)
- [x] Header progress counts unchanged

**Test: `next <N>` starts a mission**
1. Type `next` to see list
2. Note the title of mission #1
3. Type `next 1`
- [x] Mission detail appears (with narrative intro if present)
- [x] Toast notification: "On the case — Lead started: {title}"
- [x] Header "completed/total" unchanged, but in-progress count reflects it
- [x] Mission status in content area shows "In Progress"

**Test: Out-of-range and no-cache errors**
- [x] Type `next 99` before typing `next` → error "Run 'next' first to see available leads."
- [x] Type `next` then `next 99` → error "Number 99 out of range. Valid range: 1–N"
- [x] Type `next hello` → error "Invalid number: hello."

---

### P1-B: Mission completion

**Test: Complete the current mission**
1. Start a mission (via `next 1`)
2. Type `complete`
- [x] Content area shows "Lead Closed" with mission title, narrative outro (if any)
- [x] If missions were unlocked: "New leads unlocked:" list appears
- [x] If unlocked count > 0: toast "Lock picked — N new lead(s) unlocked"
- [x] Header progress: completed count incremented
- [x] `current_mission_id` cleared — typing `mission` now shows "No active lead"

**Test: Complete with no active mission**
1. Don't start any mission
2. Type `complete`
- [x] Error: "No mission in progress. Use 'next' to pick a lead."

---

### P1-C: Session resume

**Test: TUI remembers in-progress missions across launches**
1. Type `next 1` to start a mission
2. Press `q` and confirm quit (mission is active, so confirmation modal appears — see P1-E)
3. Re-launch TUI on the same campaign
- [x] Welcome message mentions the in-progress mission by title
- [x] `current_mission_id` is pre-set (typing `mission` shows the in-progress mission without re-selecting)
- [x] `complete` works immediately without needing to re-run `next`

---

### P1-D: End campaign

**Test: End campaign confirmation modal**
1. Type `end campaign` (or Film Noir alias)
- [ ] ConfirmModal appears over the screen (not replacing it)
- [ ] Modal shows message "Close the case? This ends the investigation."
- [ ] Two buttons visible: "Cancel" and "Close Case"

**Test: Cancel end campaign**
1. Open modal
2. Press Cancel (or Escape)
- [ ] Modal dismisses, returns to main screen
- [ ] Toast: "Case remains open."
- [ ] Campaign still open (can run `status`, etc.)

**Test: Confirm end campaign**
1. Open modal
2. Press "Close Case"
- [ ] Modal dismisses
- [ ] Content area shows "Case Closed" summary with completed/total count
- [ ] App exits after ~3 seconds (⚠️ WATCH FOR RF-01: may crash or hang)

---

### P1-E: Quit confirmation

**Test: Quit with active mission**
1. Start a mission (`next 1`)
2. Press `q`
- [ ] ConfirmModal appears: "You have an active lead. Quit anyway? Your progress is saved."
- [ ] Two buttons: "Cancel" and "Quit"

**Test: Cancel quit**
1. Press Cancel
- [ ] Modal dismisses, returns to app
- [ ] Toast: "Staying on the case."
- [ ] App still running

**Test: Confirm quit**
1. Press Quit
- [ ] App exits cleanly

**Test: Quit via `quit` command (same as q)**
1. Start a mission
2. Type `quit`
- [ ] Same confirmation modal appears

---

### P1-F: Force unlock

**Test: Unlock a locked mission**
1. Find a locked mission ID (from `status` or `next` list)
2. Type `unlock <ID>`
- [x] Toast: "Lock picked — Unlocked: {title}"
- [ ] Header available count incremented
- [x] Cache invalidated: running `next` shows updated list

**Test: Unlock errors**
- [x] `unlock` with no args → error "Usage: unlock <mission_id>"
- [x] `unlock abc` → error "Invalid mission ID: abc"
- [x] `unlock 9999` (non-existent) → error from `MissionStatusError`

---

## Priority 2 Tests (if time permits)

### P2-A: Status and briefing

**Test: `status` shows case board**
- [x] Displays overall progress, category breakdown with bar charts
- [x] Chains section (if any) shows chain completion

**Test: `briefing` shows case file**
- [x] If pipeline was run: shows summary, tech stack, security assessment
- [x] If no briefing: shows "No briefing generated yet."

### P2-B: `help` command
- [x] Lists all 10 commands with Film Noir aliases
- [ ] Accessible via `?` key and `help` command

### P2-C: Modal CSS rendering (RF-02 related)
- [ ] When ConfirmModal appears, does it have Film Noir styling (dark background, amber border)?
- [ ] Or does it appear with default/unstyled colors?
  - Note: This tests whether `DEFAULT_CSS` resolves `$noir-*` variables

---

## User Testing Notes

### Issues Found
1.Instead of prompting user to type "next", prompt them to use the themed words (in this case, investigate). The static always-available commands should work, but the prompts and notes to the user should stay on theme
2.For polish phase: on the "commands" header, don't use the always available commands. Use the thematic commands and a short description of what they do. Help will show the always available commands in a man page.
~~3. There is no "available" count in the header. Only completed/total~~
~~3. From mission list, typing "investigate 1" correctly starts the mission, but the toast notification shows the title_plain rather than the themed title.~~
~~3. STILL AN ISSUE: The "esc" key does not defocus the input, only a mouse click does. This isn't accessible behavior.~~
3. STILL AN ISSUE: it isn't MORE missions available (which would be expected if unlocks were replacing completed missions.) It's FEWER. Started with 17 missions available. Closed 1. 17 were still available in the mission list (perhaps one was unlocked, but there was no notification about it.) Closed a second mission. Now there are only 13 missions available on the list.
4. Should indicate which missions on the list are in progress when typing "investigate" without a number
~~6. STILL AN ISSUE when quitting, FIXED for ending campaign: When ending campaign, TUI crashes to this error. Same error for quitting while a lead is active:~~


### Error Messages / Logs

```
(paste any errors here)
```

### Questions
1.

### General Feedback

### Result
- [x] All good — approved for phase close
- [x] Issues found — see above

<!-- STATUS: COMPLETE -->
