---
path: /studio/aja/avatar-library
surface: studio
domain: aja
auth: signed-in + studio entitlement
source: apps/oshun/web/src/app/studio/aja/avatar-library/page.tsx
status: walked + e2e-covered
last_walked:
  '2026-07-02 avatar-lane console addendum — Playwright real-dev-infra coverage
  now proves signed-in render, breadcrumb and route-map contracts, capability
  card count, quick-action href order, ready form, 44 px submit target,
  malformed JSON client guard with no POST, real BFF duplicate-asset 400 detail,
  real dedup result rows/canonical selection/reclaimable bytes, fail-closed
  loading/unauthorized/error states, mobile no-overflow, and direct BFF
  401/403/400 gates. Spec:
  apps/oshun/web/e2e/studio-aja-avatar-lane-consoles.spec.ts.'
  '2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data
  (2xx), console/page-errors, expected content, screenshot verified; live
  screen-reader, touch, offline, and telemetry-delivery checks pending a manual
  AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; body
  re-derived 2026-06-03 from current source (lane-console architecture)'
---

# Aja Avatar Library

## Purpose

Admin lane console whose operations lane is a content-addressable dedup analyzer
wired via `/v1/admin/aja/avatar-library`: it groups assets by content hash,
designates a canonical per group, marks the rest as duplicates, and reports
unique-content / duplicate counts, total bytes, and reclaimable bytes.

## Entry points

- **Direct URL** — `/studio/aja/avatar-library` (signed-in + studio entitlement)
- **Breadcrumb** — Studio / Aja / Avatar Library
- **Sibling quick-actions from this page** — Avatar Integration, Avatar Preview,
  Inverse Kinematics, Back to Studio

## Layout regions

`page.tsx` mounts `ShellLayout` with `active="studio"` and renders four panels.

- **Breadcrumb panel** (`data-aja-avatar-library-breadcrumbs`):
  `nav aria-label="Aja Avatar Library breadcrumbs"` — Studio (link) / Aja /
  Avatar Library (`aria-current="page"`)
- **Workspace panel** (`data-aja-avatar-library-workspace`):
  - `<h1>` "Aja Avatar Library Workspace" (via `WorkspaceHeading`)
  - `<p data-aja-avatar-library-summary>` — "Dedicated Avatar Library route with
    typed operations, diagnostics, security controls, and canonical route map."
  - Capability Summary panel (`data-aja-avatar-library-capability-summary`,
    `<h2>` "Capability Summary" + `data-aja-avatar-library-capability` cards —
    static descriptive copy)
  - `<section data-aja-avatar-library-operations-lane>` `<h2>` "Avatar Library
    Operations Lane" embedding the `AssetDedupLane` (`section data-adp-lane`,
    `<h2 data-adp-heading>` "Live Content-Addressable Dedup")
- **Route Map panel** (`data-aja-avatar-library-route-map`): `<h2>` "Route
  Map" + one `<article>` per `STUDIO_AJA_AVATAR_LIBRARY_ROUTE_MAP` entry (6
  entries)
- **Quick actions panel**: `.quickAction` `<Link>`s — see Interactions

## States

- [x] **Loading** — `data-adp-loading` "Loading asset dedup analyzer…"
- [x] **Unauthorized** — on 401/403, `data-adp-unauthorized` (admin-scope
      reason, default "Aja workspace scope required to analyze the library.")
- [x] **Error** — non-OK / unreachable → `data-adp-error`
- [x] **Ready (form)** — `data-adp-form` with the JSON payload textarea
- [x] **Result** — `data-adp-result`: `data-adp-headline` (unique/total ·
      `data-adp-duplicates` · `data-adp-reclaimable`) and a `data-adp-assets`
      table (`data-adp-canonical`, `data-adp-state`)
- [x] **Validation error** — `data-adp-analyze-error` "Payload must be valid
      JSON."

## Interactions

### Capability Summary panel

- [x] Non-interactive `data-aja-avatar-library-capability` cards
      (catalog-control-plane, diagnostics-and-observability,
      security-permission-audit-controls, api-parity-and-contract-assurance)

### Asset dedup form (`data-adp-form`)

- [x] **Assets JSON** — `textarea data-adp-payload` (default `assets` array with
      assetId/contentHash/sizeBytes)
- [x] **Analyze library** — `button data-adp-submit`; submits parsed JSON to
      `POST /v1/admin/aja/avatar-library/analyze` and receives
      `{ result: AdpResult }`

### Route Map panel (`data-aja-avatar-library-route-map`)

Non-interactive `<article>` blocks from `STUDIO_AJA_AVATAR_LIBRARY_ROUTE_MAP` (6
entries): `/studio/aja/avatar-library` plus `…/scenes/[sceneId]`,
`…/exports/[exportId]`, `…/revisions/[revisionId]`, `…/parity/[parityId]`,
`…/governance/[policyId]`.

### Quick actions panel

- [x] **Open Aja Avatar Integration workspace** →
      `/studio/aja/avatar-integration`
- [x] **Open Aja Avatar Preview workspace** → `/studio/aja/avatar-preview`
- [x] **Open Aja Inverse Kinematics workspace** →
      `/studio/aja/inverse-kinematics`
- [x] **Back to Studio workspace index** → `/studio`

## E2E coverage

- [`apps/oshun/web/e2e/studio-aja-avatar-lane-consoles.spec.ts`](../../../../apps/oshun/web/e2e/studio-aja-avatar-lane-consoles.spec.ts)
  covers signed-in shell render, breadcrumb visibility, capability cards, route
  map shape, exact quick-action hrefs, ready form, 44 px submit target,
  malformed JSON client guard with no POST, real BFF duplicate-asset 400 detail,
  real dedup result rows and reclaimable byte summary,
  loading/unauthorized/error fail-closed states, mobile no-overflow, and direct
  BFF auth/schema gates.

## Data & contracts

- **Reads**: `GET /v1/admin/aja/avatar-library` on mount (response read but only
  used to gate the lane to ready) via `buildBffAuthHeaders()`,
  `cache: 'no-store'`
- **Writes**: `POST …/analyze` → `{ result: AdpResult }`
- **Realtime**: none
- **Caching**: client fetch on mount (no-store); SSR shell only
- **Auth**: BFF endpoints admin-scoped + fail-closed (401/403 → unauthorized
  render); the route is signed-in + studio (proxy gate)

## Cross-references

- Parent: [`../../studio-overview.md`](../../studio-overview.md)
- Component sources:
  - `apps/oshun/web/src/components/studio/StudioAjaAvatarLibraryWorkspace.tsx`
  - `apps/oshun/web/src/components/studio/StudioAjaAvatarLibraryRouteMap.ts`
- Siblings from quick-actions: `/studio/aja/avatar-integration`,
  `/studio/aja/avatar-preview`, `/studio/aja/inverse-kinematics`

## Known downstream boundaries

- The mount GET only gates readiness; the returned catalog body is not rendered
  by this leaf lane.
- Capability Summary cards are static descriptive copy; the live affordance is
  the content-addressable dedup analyzer.
- Route-map sub-routes are descriptive contracts; implementation status of those
  child pages is tracked separately from this leaf console.
- The signed-in/studio entitlement proxy gate is shared across `/studio/aja/*`
  and is verified outside this leaf-lane spec.
