# S02 Research: Pipeline Page — Head/Tail Log View + Token Count

## Summary

Straightforward frontend+backend slice. The pipeline page (`AdminPipeline.tsx`) already has a fully working event log with per-event token display, per-video token totals, and offset-based pagination. What's missing is a Head/Tail toggle to quickly switch between viewing the oldest events (pipeline start) and newest events (latest activity), replacing the generic prev/next pager as the primary navigation.

Token counts are already visible — no new work needed there. The slice demo text says "Token counts visible per event and per video" which is already implemented.

## Recommendation

**Light scope. One backend param, one frontend component change, minor CSS.**

Add an `order` query param (`asc`/`desc`, default `desc`) to the `GET /admin/pipeline/events/{video_id}` endpoint. Change the `EventLog` component to show Head/Tail toggle buttons instead of (or alongside) the existing prev/next pager. Head = ascending order (first N events), Tail = descending order (last N events, current default).

## Implementation Landscape

### Files to Change

| File | Location | What changes |
|------|----------|-------------|
| `backend/routers/pipeline.py` | ub01: `/vmPool/r/repos/xpltdco/chrysopedia/backend/routers/pipeline.py` | Add `order` query param to `list_pipeline_events` endpoint (line ~170). Values: `asc`/`desc`, default `desc`. Changes the `order_by` clause. |
| `frontend/src/api/public-client.ts` | Local: `frontend/src/api/public-client.ts` (line ~440) | Add `order` param to `fetchPipelineEvents` params type and URL builder. |
| `frontend/src/pages/AdminPipeline.tsx` | Local: `frontend/src/pages/AdminPipeline.tsx` | Replace the `EventLog` component's pager with Head/Tail toggle buttons. Add `viewMode` state (`"head"` / `"tail"`). Pass `order` param to `fetchPipelineEvents`. Reset offset to 0 on mode switch. |
| `frontend/src/App.css` | Local: `frontend/src/App.css` (~line 2712) | Add `.pipeline-events__view-toggle` segmented button styles. ~15 lines of CSS. |

### Backend Endpoint (current state)

```
GET /admin/pipeline/events/{video_id}
  Query: offset (int, ≥0), limit (int, 1-200), stage (str?), event_type (str?)
  Response: { items: PipelineEvent[], total: int, offset: int, limit: int }
  Order: created_at DESC (hardcoded)
```

**Change needed:** Add `order: Annotated[str | None, Query()] = "desc"` param. Validate values are `asc`/`desc`. Apply `PipelineEvent.created_at.asc()` or `.desc()` accordingly.

### Frontend EventLog Component (current state)

- State: `events`, `total`, `loading`, `error`, `offset` (starts at 0)
- Renders: header with count + refresh button, event list, prev/next pager
- Each event row shows: icon, stage name, event_type badge, model name, token count (with prompt/completion tooltip), duration, timestamp
- Pagination: offset-based, 50 per page, prev/next buttons

**Change needed:**
- Add `viewMode` state: `"tail"` (default, desc order — most recent first) or `"head"` (asc order — chronological from start)
- Add toggle button pair in `.pipeline-events__header` between count and refresh
- Pass `order: viewMode === "head" ? "asc" : "desc"` to `fetchPipelineEvents`
- Reset `offset` to 0 when switching modes
- Keep existing prev/next pager for navigating within head or tail view

### CSS Pattern

Use a segmented button pair similar to the existing `.filter-tab` pattern but compact. Two adjacent buttons with shared border-radius, active state uses `var(--color-accent)` background with `var(--color-bg-page)` text. Inactive uses `var(--color-bg-input)` background.

```
.pipeline-events__view-toggle {
  display: inline-flex;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--color-border);
}
.pipeline-events__view-btn { ... }
.pipeline-events__view-btn--active { ... }
```

### Existing Patterns to Follow

- **Button styles:** `.btn`, `.btn--small`, `.btn--secondary` — use for pager, but the toggle needs custom segmented style
- **Active state colors:** `var(--color-text-active)`, `var(--color-border-active)`, `var(--color-accent)`
- **Filter tabs in ReviewQueue.tsx:** Similar toggle pattern using `.filter-tab--active`
- **Token formatting:** `formatTokens()` helper already exists — handles K/M suffixes
- **API client pattern:** `URLSearchParams` builder in `fetchPipelineEvents` — add `order` param

### Token Count Display (already done)

Per-event: `{formatTokens(evt.total_tokens)} tok` with hover tooltip showing `prompt: N / completion: N`
Per-video: `{formatTokens(video.total_tokens_used)} tokens` in the video row meta section

No changes needed for token display — the roadmap demo text confirms existing behavior.

### Natural Task Decomposition

1. **Backend: Add `order` param** — modify one endpoint in `pipeline.py`, validate input, change ORDER BY. ~10 lines. Can be verified with curl.
2. **Frontend: Head/Tail toggle + CSS** — modify `EventLog` component in `AdminPipeline.tsx`, add API param in `public-client.ts`, add CSS. ~40 lines total. Verify in browser.

These two tasks can be done as one (small) or two (safer, independent verification). The backend change is a prerequisite for the frontend change.

### Verification

- Backend: `curl 'http://ub01:8096/api/v1/admin/pipeline/events/{video_id}?order=asc&limit=5'` should return events in ascending chronological order
- Frontend: Load pipeline page, expand a video, see Head/Tail toggles, click Head to see oldest events first, click Tail to see newest first. Token counts remain visible on each event row and video summary row.
- Build: `cd frontend && npm run build` must succeed with zero TypeScript errors
