# Video Corpus — UX brief for Codex (Direction 2 gaps)

**Scope:** `apps/flow-builder/app/(app)/admin/ai-videos/corpus/**` and `apps/flow-builder/src/components/admin/promptVideoCorpus/**` on branch `codex/unified-video-corpus-evidence` (PR #9982, ARC-14826 → ARC-14830).
**Design of record:** Figma `diuqgvMQoln85uhlJgSwWi`, page "03 — Selected direction", frame 25:3 "Selected direction — implementation spec". Node IDs below refer to that file.
**Audience for the page:** teammates who are not engineers. They should be able to open the page cold and answer three questions in ten seconds: *Where am I? How far along is this batch? What do I do next?*
**Prototype of the target state:** `.tmp/corpus-ux/site/index.html` (deployed copy linked in the PR thread). Treat it as the visual spec for layout, hierarchy and copy. Treat the Figma frames as the source of truth where the two disagree.

Screenshots of today's build (1440×854, preview `codex-unified-video-corpus-evidence.preview.arcade.software`) are in `.tmp/corpus-ux/live-*.png`. Figma frames are in `.tmp/corpus-ux/fig-*.png`.

---

## 0. What is structurally missing (read this first)

Today's page is functionally complete and the disclosure protocol is correct. What is missing is *shape*. Five things, in priority order:

1. **There is no spine.** The Figma page has a header with the mode switch as the primary control, then one progress strip ("4 of 5 evaluated ——— 1 pending"), then the work. Today the mode switch is a text-xs toggle inside a "Video navigation" toolbar next to a search box and Prev/Next. In Blind review three more bars stack under it (Queue/Labeled, "Showing 7 loaded videos", Filters). With Filters open, the video starts 690px down on an 854px viewport. See `live-blind-filters.png`.
2. **Two products are stitched together.** Evidence mode renders `EvidenceCutCard`; Blind review renders `CorpusCard` with a different header, a different player component, different chrome, and a different type scale. After a reviewer submits, the whole card is swapped for `EvidenceCutCard` (the `renderDisclosedEvidence` bridge), so the header, the player and the layout all jump. Figma uses one workbench shell for both modes; only the right-hand inspector and a banner change.
3. **The hero is buried.** In Evidence mode the thing the team cares about is *where the problems are*. Figma shows one "Moments" strip under the video with the findings as the only marks. Today it is a five-track analysis rail (Visual / Voice / Music / Gaps / Lulls) with 8px labels and S01–S05 chips; the findings are the thinnest marks on it. It is also below the fold at 854px. See `live-evidence-viewport.png`.
4. **The vocabulary is ours, not theirs.** "Council ready", "Signals ready", "Judgment unavailable", "cross-modal lull candidate", "measured render", "Turn signals", "Save label", "cited evidence", full generation IDs in headers, ticket numbers in empty states. The copy table in §4 replaces every instance.
5. **The queue is not the queue.** Search, Prev/Next and Load more live in a separate toolbar; Queue/Labeled and Filters are separate bars; the queue itself is hidden below 1280px, which is why the combobox exists at all. Figma puts search, filter, paging and the count inside the queue panel, and collapses the queue into a compact selector on short viewports instead of removing it.

Everything below is the detailed version of these five.

---

## 1. Non-negotiables (do not regress while restyling)

These are the Figma "trust boundary" bullets (frame 6:7) and they are already implemented. Keep every one:

- One route, one stable identity for the selected exact render. Selection is generation + exact render URL and survives mode switches.
- Blind review mounts **no** machine judgment, severity counts, cited moments, or derived evidence before commit. Not hidden with CSS — not in the DOM, not in the RSC payload (`page.tsx` only loads receipts in Evidence mode).
- Reveal is deliberate, session-sticky, and marks the label non-blind (`evidenceExposedGenerationIds`, `wasBlind`).
- Customer sentiment (vote, reasons, note) and safe source context stay visible before commit.
- Partial / unavailable / processing / stale / no-evidence states stay honest and first-class.
- URL-backed mode (`?mode=`), filters, pagination and browser back/forward keep working.

If a change below would require moving machine data into the Blind payload or DOM before commit, the change loses.

---

## 2. Layout changes (P0)

### 2.1 Page header owns the mode switch — Figma 27:2, 27:7
- Left: eyebrow `VIDEO CORPUS · REVIEW WORKSPACE`, title, one-line subtitle. Right: the segmented control `Evidence | Blind review`, ~34px tall, full-weight labels.
- Title and subtitle change with the mode:
  - Evidence: **Inspect what we found** — "See what we found, when it happened, and where it came from — without leaving the corpus."
  - Blind review: **Give your own verdict first** — "Watch the video and say whether you would send it. We show what the machines said only after you answer."
- Delete the "Video navigation" `<section>` (`PromptVideoCorpusPageClient.tsx` ~1046–1136). Its three jobs move: mode → header; search → queue; Prev/Next → queue footer and workbench header (§2.3).
- Fix the tab title while here: `page.tsx` metadata still says `Admin | Prompt Video Corpus`; the page says Video Corpus.

### 2.2 One progress strip under the header — Figma 27:12
- Evidence: `4 of 5 evaluated` ——— bar ——— `1 pending`. Counts = receipts with council status ready / total receipts in the cohort.
- Blind review: `1 of 5 reviewed` ——— bar ——— `4 remaining`. Counts = labeled / labelable in the loaded set (`labeledCount`, `labelableCount` already exist).
- This replaces: the `Queue · N pending | Labeled · N` toggle bar, the "Showing N loaded videos · N pending" text, and the `N` / `50/120` count in the aside header. The Pending/Reviewed split becomes a filter chip inside the queue (§2.3).

### 2.3 The queue owns navigation — Figma 33:3, 33:7, 33:37
- Panel header: `Corpus queue` + count.
- Row 2: search field (the existing `CorpusVideoPicker` filtering logic, restyled as a plain search input that filters the list in place) + a filter icon button that opens the existing Filters as a popover. Active filter count shows as a badge on the icon.
- Blind review adds a two-state chip row under search: `Pending (7) · Reviewed (0)` (today's `reviewMode`).
- Footer: `1–7 of 7` and `‹ ›` Prev/Next. `Load more` stays as the last row when `hasMore`.
- Items: thumbnail 56×32, title (12px semibold, one line), second line context (12px): Evidence = workspace · one lifecycle word (§4); Blind = owner · workspace · time ago. Vote as a small ▲/▼ glyph + word, 11px. Drop the 9px chips and the "◆ 1 major ● 5 minor" line from Evidence rows — severity belongs to the selected card, not the list. Keep a 4px violet left bar + tint for the selected row.
- Below `xl` and on short viewports (§5) the queue does not disappear. It collapses to a `Queue ▾ (7)` button in the workbench header that opens the same list as a dropdown/drawer. Delete the combobox once that exists.

### 2.4 One workbench shell for both modes — Figma 27:17 / 30:17 / 31:17, seam map 38:2
Build `ReviewWorkspaceShell` (new) that renders, in both modes and in all three states:
- **Header (28:2):** title (18–20px semibold) · vote chip · one lifecycle chip · [Evidence only / revealed only: severity summary right-aligned `! 1 major` `◆ 5 minor`] · line 2: owner · email · workspace · line 3 (muted, 12px): `Exact render dUpK…f02a` with a copy button. No full IDs. No position circle. No "Blind review" pill — the mode is already in the header; the header chip shows *state* instead (§3.3).
- **Media stack (44:2):** the same player component in both modes (use `RenderedPromptVideoPlayer` with the standard controls; `PromptVideoCorpusPlayback`'s fallback chain stays underneath it as the source resolver). Below it the Moments strip (§2.5) in Evidence / revealed; in Blind-before the strip is simply not mounted (it is machine data).
- **Inspector column (292px):** mode/state specific — `EvidenceInspector` (review summary, selected moment, Findings, Details) or `BlindReviewInspector` (form, then committed review + the evidence inspector after reveal).
- **Footer (28:53):** related surfaces + quick facts (i). Blind-before shows the safe subset plus the gated pill (§3.4).
- After Submit or Reveal the header gains the severity summary and the strip mounts under the video; nothing else moves. Delete the `renderDisclosedEvidence` card swap and the `inspectorLead` slot once the shell exists; `CorpusCard` becomes `BlindReviewInspector` + the shell.
- Player behaviour: never autoplay with sound on selection (today `autoPlay` in `PromptVideoCorpusPlayback.tsx` ~414 starts audio the moment you land in Blind review). Remove the top-left "Measured render" overlay and the "Unload preview" ✕ from the video; the source name moves into Details / Source details. Keep fullscreen.

### 2.5 Moments strip replaces the analysis rail by default — Figma 28:33–28:46
- Label row: `MOMENTS · CLICK TO SEEK` left, `LIVE 00:18.40 / 00:56.00` right (existing playhead state).
- One rail, ~56px tall, findings only: major = red pill, minor = amber pill, point citations = 10px dot. Minimum hit target 24×24. Hover shows `00:14–00:21 · first sentence of the claim`. Click = select moment + seek (existing `selectMoment`). The selected range gets the violet outline; the live playhead keeps moving independently (already true).
- Legend: `● Major  ● Minor` only.
- The five-track rail (Visual / Voice / Music / Gaps / Lulls, scene boundaries, S01 chips) moves behind a `Show detected layers` toggle at the right of the label row, off by default, remembered per session. Keep its keyboard seeking. Raise its labels to 11px when shown.
- Empty state on the rail itself: `No problems were found in this video.` / `This video has not been evaluated yet.`

---

## 3. Inspector, states and copy (P0/P1)

### 3.1 Evidence inspector — Figma 28:29
- `REVIEW SUMMARY` → one or two sentences (today: first sentence of the council verdict — keep).
- `SELECTED MOMENT · 00:18–00:24` panel: severity word + claim + `▶ Play segment`. Empty copy: `Click a mark on the strip, or a finding below, to jump to it.`
- `Findings` disclosure shows a count: `6 findings ⌄`. Row = time (mono 12px) · severity pill · claim (13px) · recommendation (12px muted). Drop `attention · measured` (category · basis) from the row; keep it in the row's tooltip.
- `Details` disclosure shows a count: `10 checks ⌄`, and lists facts in words: `Length 0:34 · Audio present · 5 scenes · 7 narration segments · 1 narration gap (7.4s) · 1 cut · Reviewers 3 of 3 · Frames sampled 5 of 5 · Exact render dUpK…f02a ⧉ · Analysis version 1.3 ⧉`. Content hashes and config strings live here, never in the header.

### 3.2 Blind review form — Figma 30:47
- Eyebrow `YOUR READ`; question `Would you send this to a customer?`; helper `Nothing from the review panel is shown until you answer.`
- Five equal choice cards: Ship / Ship with notes / Needs work / Broken / **Can't assess** (today Can't assess is a text button under the grid — make it the fifth card, full width).
- `Add a note ⌄` as a row, not a `+` text button.
- Actions row: `Reveal evidence` (secondary, left) · `Submit review` (primary, right, disabled until a verdict). Delete the separate "Stuck? Reveal the evidence (marks this label non-blind)" button under the card.
- One line under the actions, 12px muted: `Revealing evidence marks this review non-blind.`
- Keep Q2 (What's actually wrong?) and Q3 (the vote questions) exactly as they are — the labels are already plain. Keep `What they told us` above the form.

### 3.3 State chip and banner — Figma 30:33, 31:18, 31:72
- Blind-before: header chip `● Evidence hidden` (violet outline).
- After Submit (blind kept): header chip `✓ Reviewed`; inspector shows the `YOUR REVIEW · SHIP WITH NOTES` card (verdict, note, `Saved 2:41 PM`) above the evidence inspector; "How your read compares" stays inside that card.
- After Reveal or after Submit-then-edit: full-width violet banner across the workbench top: `Evidence revealed · this review is no longer blind`. The amber `role=status` box inside the column goes away.
- `Change my review` replaces `Change my label`.

### 3.4 Related surfaces — Figma 28:53, 30:78, 30:86
- Chips are text + ↗ only: `Conversation ↗` `Brand Kit ↗` `Braintrust ↗` `Provenance ↗`. Remove the emoji and the "bt" mark.
- Blind-before shows `Conversation` `Brand Kit` `Source details` and, right-aligned, a muted pill: `Braintrust + evaluation receipt unlock after submit or reveal`.
- The (i) quick facts button stays; its tooltip title becomes `Quick facts` and lists `Reviewers 3 of 3 · Frames 5 of 5 · Scenes 5 · Audio present`.

### 3.5 Empty and error states
- Evidence, no receipt: `We haven't evaluated this video yet.` (+ `Evaluations run on new exports automatically.`)
- Evidence, receipt for a different render: `This evaluation is for an earlier export of this video.` (ARC-14830 stale state)
- Blind, nothing playable: `None of these videos can be played right now.`
- Blind, nothing loaded: `No videos match these filters.` (keep)
- Remove ticket IDs and CLI names from all user-facing copy (`EvidenceRails.tsx` ~41–46 and ~193–198).

---

## 4. Vocabulary — say this, not that

| Today | Say | Where |
|---|---|---|
| Council ready · Signals ready · Judgment unavailable | one lifecycle chip: **Ready** / **Partial** / **Processing** / **Not evaluated** | header, queue |
| Reviewed (queue chip, Evidence) | Ready | queue |
| Evaluated videos / Review queue / Labeled videos | Corpus queue (+ Pending / Reviewed chips in Blind) | queue header |
| Save label / Update label / Change my label / Labeled · 2d ago | Submit review / Update review / Change my review / Reviewed · 2d ago | form, header |
| Queue · 7 pending / Labeled · 0 | progress strip `0 of 7 reviewed` + queue chips | strip |
| Evidence timeline | Moments · click to seek | strip label |
| Visual / Voice / Music / Gaps / Lulls (visible by default) | Detected layers (toggle, off) | strip |
| Cross-modal lull candidate | Narration gap | layers, tooltips |
| S01 … S05 | Scene 1 … Scene 5 | layers |
| Select a finding moment to inspect its cited evidence. | Click a mark on the strip, or a finding below, to jump to it. | selected moment |
| Findings · 6 returned | Findings · 6 findings | disclosure |
| Details (no count) | Details · 10 checks | disclosure |
| attention · measured (finding row) | (tooltip only) | finding row |
| Measured render / HLS render / Current composition (overlay) | Source: Exact export / Streaming copy / Live preview — inside Details | details |
| Exact render + 40-char hash · full generation ID in header | `Exact render dUpK…f02a ⧉` (short, copyable) | header line 3 |
| Stuck? Reveal the evidence (marks this label non-blind) | Reveal evidence (button) + `Revealing evidence marks this review non-blind.` | form actions |
| Evidence revealed · this review will be recorded as non-blind. (amber box) | banner: Evidence revealed · this review is no longer blind | banner |
| Technical evidence / Automated diagnosis / Judge verdict / Measured temporal facts / Turn signals | What the machines said: Diagnosis · Judge · Playback facts · Chat signals | post-review panel |
| Not judged yet — new exports grade automatically (ARC-12441); older … via the judge CLI | Not judged yet. New exports are judged automatically. | rails |
| Not measured yet — … (video node pending ARC-13365) | Not measured yet. | rails |
| Video A0G5JgvR… (title fallback) | Untitled video (fallback), with the ID only in Details | everywhere |
| 🧙‍♂️ Conversation · 🎨 Brand Kit · 🧾 Provenance · bt Braintrust | Conversation ↗ · Brand Kit ↗ · Provenance ↗ · Braintrust ↗ | footer |

Rule of thumb: a word a teammate would have to ask you about goes into Details or a tooltip, never into a header, a chip, or a button.

---

## 5. Type scale, density, responsive (P1)

- **Type floor is 11px.** Nothing renders below it. Today: 8px (timeline labels, `EvidenceCutCard.tsx` ~273/307/365), 9px (queue chips, `ReviewWorkspaceQueue.tsx` ~153), 10px (most labels). Target: eyebrows/labels 11px, meta 12px, body 13–14px, workbench title 18–20px, page title 24px.
- **Cards, not nested cards.** Inside the workbench use dividers and spacing; reserve bordered boxes for the selected-moment panel and the two disclosures.
- **Width:** the workbench fills the remaining width (Figma 930/1220). Remove `max-w-[960px]` on the workbench wrapper.
- **Short viewports (Figma 25:8, height ≤ 780px):**
  1. Pin the product nav, page header (with mode switch), progress strip and the workbench identity header. No tall page summary.
  2. The workbench body (player + strip + inspector) is the only thing that scrolls. The player never shrinks to a thumbnail.
  3. The queue collapses to the `Queue ▾` selector in the workbench header. Prev/Next stay reachable there.
- **Below `xl` (1280px):** same collapse as above instead of hiding the queue.

---

## 6. Verification (what "done" looks like)

Take these screenshots at 1440×854 and 1440×760, and attach them to the PR:
1. Evidence · ready · nothing selected — the strip and the inspector are visible without scrolling.
2. Evidence · a moment selected — selected range outlined, panel filled, playhead elsewhere.
3. Blind · before — no severity, no strip, no machine text anywhere in the DOM (`document.body.innerText` contains none of: major, minor, Findings, Judge, Council, Provenance, Braintrust).
4. Blind · after Submit — chip `Reviewed`, `YOUR REVIEW` card, strip mounted, same header and player as before.
5. Blind · after Reveal — banner present, `wasBlind === false` on save.
6. 1440×760 — header + strip + identity pinned, body scrolls, queue collapsed to the selector.
7. Every string in §4 "Today" column returns zero matches in `apps/flow-builder` UI code (test files excepted).

Existing tests to keep green: `PromptVideoCorpusPageClient.test.tsx` (mode/selection/disclosure), `EvidenceCutCard.test.tsx` (timeline seek), `CorpusCard.test.tsx`, `LabelPass` coherence rules, `page.test.tsx` (redirect + lazy receipts).
