---
path: /operator
surface: operator
domain:
  operator (review, safety, support, persona/model/rights/provenance, incidents,
  launch)
auth: signed-in
source: apps/oshun/web/src/app/operator/page.tsx
status: walked
last_walked: >
  2026-06-25 operator-index route-state addendum — Playwright real-dev-infra
  coverage now proves the top operator bar product/section/breadcrumb are
  non-interactive, the page count/title/rule/eyebrow anchors, every surface
  code/title/description/open label and stable href, focused-link affordance,
  and the mobile one-column grid with no horizontal overflow. Evidence:
  WALKTHROUGH/results/v1-real-infra-run-2026-06-22.md §101; spec:
  apps/oshun/web/e2e/operator-surfaces.spec.ts. Previous: 2026-06-25
  operator-surfaces direct-route addendum — Playwright real-dev-infra coverage
  for signed-in /operator render, anonymous proxy redirect, all four shipped
  surface links/codes/hrefs, 44 px link targets, and keyboard Enter activation
  into /operator/tenant. Evidence:
  WALKTHROUGH/results/v1-real-infra-run-2026-06-22.md §81; spec:
  apps/oshun/web/e2e/operator-surfaces.spec.ts.
---

# Operator · index

## Purpose

The operator product's index page — "Plate of record. Four operator surfaces."
Surfaces the four distinct operator products (Studio, Tenant, Admin, etc.) as
cards routed from `getOperatorIndex()`. Robots-noindex (`metadata.robots`). See
[`V1/features.md`](../../V1/features.md) and `V1/ARCHITECTURE.md`'s Operator
surfaces section.

## Entry points

- **Profile menu → Operator** — primary entry
- **Direct URL** — session-gated only (`proxy.ts` redirects sessionless →
  `/welcome?redirect=`); no operator-role gate in the proxy
- **Operator deep link** from internal docs / runbooks
- **Cross-product link** when an admin needs to switch operator surfaces

Not entered from public/discovery surfaces.
`robots: { index: false, follow: false }` ensures it never appears in external
SEO.

## Layout regions

The page uses Lilith design-system primitives directly (`LGraphPaper`,
`LOperatorBar`, `L`, `SERIF_L`) rather than `ShellLayout`. Visually it adopts
the "plate of record" cream-paper-with-rules look.

- **Top**: `LOperatorBar` — product="OSHUN", section="Operator",
  breadcrumb="Index"
- **Eyebrow**: "Plate of record" (accent color)
- **H1-like title**: "Four operator surfaces." (Garamond 36 px)
- **Main grid** (max-width 960, centered):
  - Auto-fit/minmax grid of operator surface entries, drawn from
    `data.surfaces`; desktop presents as a ledger grid and mobile collapses to
    one column without horizontal document overflow
  - Each surface is `{ href, code, title, desc }`; the cell renders an `LCode`
    `code` badge, the `title`, an italic `desc`, and an "Open ↗" eyebrow
    (operator/page.tsx:53-95; operator-depth.ts:30-59)

## States

- [x] **Loading** — no route `loading.tsx`; `getOperatorIndex()` is a
      server-side static fixture and the page blocks until it renders
- [x] **Anonymous user** — redirected to `/welcome?redirect=` (`proxy.ts`);
      never sees this
- [x] **Signed-in user** — full index renders (session-gated only; no
      operator-role gate in the proxy)
- [ ] **`getOperatorIndex()` fails** — no route `error.tsx` exists under
      `apps/oshun/web/src/app/operator`; a render crash falls through to the
      nearest parent/global boundary
- [ ] **Offline** — operator work is write-heavy and audit-stamped; offline mode
      disables most actions with a clear banner
- [ ] **Different operator persona** (e.g., safety operator vs. persona ops) —
      surfaces filtered to the role's permissions

## Interactions

### `LOperatorBar`

The shared operator bar at the top. Walk it as part of operator chrome:

- [x] **Product label** — `OSHUN`; non-interactive
- [x] **Section label** — `Operator`; non-interactive
- [x] **Breadcrumb** — `Index`; non-interactive on the index
- [x] **No back/up affordance on the index** — the bar exposes no link or button
      target

### Surface grid

For each cell in `data.surfaces`:

- [x] **`code` badge** (`LCode`) — short code label (`STUDIO`, `TENANT`,
      `ADMIN`, `METIS`)
- [x] **Surface title** — Garamond display text
- [x] **Surface `desc`** — italic concise line from the index fixture
- [x] **Surface link** (whole cell is the `Link`)
  - Function: navigates to the operator sub-surface
  - Keyboard: Enter activates
  - SR: announces surface name
  - Touch ≥ 44×44 px
- [ ] **Surface click telemetry** — `operator_index_surface_clicked`,
      surface=<name>
- [ ] **Hover state** — pulses or underlines per Lilith design
- [x] **Focus state** — keyboard focus lands on the whole-cell link and keeps a
      visible focus affordance; no `outline: none`/shadowless regression

### Page chrome

- [x] **Eyebrow** — color is set from `L.accent`; Playwright verifies the stable
      eyebrow text/region
- [x] **Title border** — 1 px bottom border `L.ink`; spacing correct at all
      widths
- [x] **Grid** — `auto-fit`/`minmax(min(100%, 360px), 1fr)`; Playwright proves
      one-column stacking and no horizontal overflow at 390 px width

## E2E coverage

- [`apps/oshun/web/e2e/operator-surfaces.spec.ts`](../../apps/oshun/web/e2e/operator-surfaces.spec.ts)
  — signed-in `/operator` render, top operator bar non-interactivity, index
  surface count/title/rule/eyebrow anchors, all four shipped surface
  links/codes/hrefs/descriptions/open labels, 44 px link target floor, visible
  focus affordance, keyboard Enter activation into `/operator/tenant`, mobile
  one-column/no-overflow grid behavior, click navigation into `/operator/admin`,
  incident-queue smoke, tenant directory/console detail checks, and anonymous
  redirect-before-render for `/operator`.

## Data & contracts

- **Reads**: `getOperatorIndex()` from `@/lib/lilith-data/operator-depth` —
  returns `{ surfaces: Array<{...}> }`. NOTE: this is a static in-process
  fixture (returns `getOperatorIndexFixture()` directly), **not** a BFF call —
  the module is headed "fixture today, BFF tomorrow"
- **Writes**: none on the index
- **Realtime**: none on the index
- **Caching**: server-rendered; cache headers from BFF; SW excludes operator
  surfaces from runtime cache (verify)
- **Auth/role check**: session-gated only (`proxy.ts` redirects sessionless →
  `/welcome?redirect=`); no operator-role gate in the proxy, and `surfaces[]` is
  not role-filtered

## Cross-references

- Shell: [`shell/04-auth-session.md`](../shell/04-auth-session.md) — role gates
- Operator sub-routes (one file per route in this folder):
  - (list grows as files are authored)
- Feature spec: [`V1/features.md`](../../V1/features.md)
- Architecture:
  [`V1/ARCHITECTURE.md`](../../V1/ARCHITECTURE.md#operator-surfaces)

## Open questions / known gaps

- [x] Enumerate the shipped `/operator/*` routes and author walkthrough files
      for each — current route files cover admin, audit, incidents, lms, metis,
      personas, sso, studio, tenant, tenants, and admin/isis/provenance
- [ ] Confirm the `surfaces[]` returned by `getOperatorIndex()` at each operator
      role and snapshot expected counts
- [ ] Determine whether `apps/oshun/admin` and `apps/oshun/admin-mobile` are
      also "operator" — if so, they need their own WALKTHROUGH branches
- [ ] Document audit log behavior: every operator click should leave a trail
- [ ] An operator-role gate appears absent — `proxy.ts` only redirects
      sessionless users to `/welcome`; no role check in the proxy, operator
      `layout.tsx` (none exists), or the page components (possible gap vs
      intended scope)
