Context. surface customer · domain lilith · route /lilith-studio · auth signed-in + role:v1_editorial_producer (default) · source apps/oshun/web/src/app/lilith-studio/page.tsx
Last walked. 2026-06-28 automated shell-contract walk (Playwright Chromium against real dev infra) — validated default/editorial and non-editorial access states, every V1 continuity lane link and entry id, every V3 authoring surface tab/route/provenance contract, provenance drawer open/close behavior, authoring-contract and release-check list presence, the full embedded provenance inspector, the V1 Studio entry link, and the now-built /lilith-studio/release route. Evidence: apps/oshun/web/e2e/lilith-studio-shell-smoke.spec.ts and apps/oshun/web/e2e/lilith-provenance-inspector-smoke.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; content re-verified 2026-06-03 against current source
Purpose#
V3 authoring shell for editorial users — operates Lilith V3 authoring surfaces
beside the V1 Studio editorial workflow, asset library, taxonomy, and
release/versioning lanes. Lets editorial work in Lilith without leaving the
Studio operating model. The page
(apps/oshun/web/src/app/lilith-studio/page.tsx) returns
<LilithStudioShell /> directly; the shell is supplied by the route's
layout.tsx via <ShellLayout active="studio">, which also enforces the
editorial scope gate (see Data & contracts).
Entry points#
- Direct URL / bookmark — yes (signed-in)
- From V1 Studio — verify navigation from
/studioto/lilith-studiofor editorial roles - From sub-surfaces — every sub-route under
/lilith-studio/*has a back-link / "Open V1 Studio" link to this shell
Layout regions#
LilithStudioShell
(apps/oshun/web/src/app/lilith-studio/LilithStudioShell.tsx) renders inside
<ShellLayout active="studio"> — the shell mounted by the route's layout.tsx,
not by the page — and has data-testid="lilith-studio-shell".
- Aside (left rail,
aria-label="Lilith Studio session"):- kicker "V3 authoring", title "Lilith Studio", summary copy
- role pill with
CheckCircle2icon — "Signed in as" (default "V1 editorial producer") - meta list: Tenant
tara-studio-editorial, Programproject-lilith-v3, Workspacelilith-authoring-main - "Open V1 Studio" link →
/studio(data-testid="lilith-v1-studio-link")
- Main:
- Header: eyebrow "V1 continuity with V3 surfaces", heading "Editorial can
work in Lilith without leaving the Studio operating model.", lede; two
header actions — "Review workflow" →
/studio/review-approval-workflowsand "Asset preview" →/studio/asset-preview-pipeline - Continuity lanes (
data-testid="lilith-studio-v1-continuity",LILITH_STUDIO_V1_CONTINUITY_LANES): four lanes, eachdata-testid="lilith-studio-v1-lane":- Editorial workflow (
ListChecks) — 3 entries (program bootstrap, cross-domain pipeline, approval submission) → opens/studio/review-approval-workflows - Asset library (
Boxes) — 3 entries (tara venue, avatar + costume, saraswati media) → opens/studio/yemaya/asset-library - Taxonomy (
Tags) — 3 entries (tara room, persona + surface, music rights) → opens/studio/hathor/journal-and-codex - Versioning (
GitBranch) — 3 entries (draft branch, editorial candidate, release edition) →/studio/hathor/entity-version-management
- Editorial workflow (
- V3 authoring surface grid:
- Surface tabs (
role="toolbar",data-testid="lilith-studio-surface-tab"): eight tabs fromLILITH_STUDIO_V3_AUTHORING_SURFACES— Scene authoring, Avatar and costume, Asana authoring, Persona dossiers, Music authoring, Concert authoring, Provenance inspector, Release bridge - Surface detail (
data-testid="lilith-studio-surface-detail") for the active tab — surface status "Shell ready", title, source- lane pill, description, route + provenance pills, "Open" link ( data-testid="lilith-studio-open-active-surface"), authoring contract list, provenance summary aside with "Open provenance" button (data-testid="lilith-studio-open-provenance"), release- checks list - Provenance drawer (
data-testid="lilith-studio-provenance-drawer") —role="dialog"; opens when "Open provenance" is clicked; shows Source lane, Route contract, Release branch chain; close button
- Surface tabs (
LilithProvenanceInspector(full surface) — surface IDlilith-studio-shell, asset list = all 8 V3 surfaces- Status strip — four KPI tiles: Workflow entries, Asset lanes, Taxonomy entries, V3 surfaces
- Header: eyebrow "V1 continuity with V3 surfaces", heading "Editorial can
work in Lilith without leaving the Studio operating model.", lede; two
header actions — "Review workflow" →
States#
- Loading — client component; hydrates immediately; shell DOM and provenance inspector hydration are asserted in browser coverage.
- Default role —
v1_editorial_producer(LILITH_STUDIO_DEFAULT_ROLE);canOpenLilithStudioShellreturns true for editorial roles. Covered bylilith-studio-shell-smoke.spec.ts. - Viewer role — signed-in non-editorial scope renders
<LilithStudioAccessDenied />withdata-v1-editorial-role="false"and no authoring shell. Covered bylilith-studio-shell-smoke.spec.ts. - Default active surface —
scene-authoring. Covered bylilith-studio-shell-smoke.spec.ts. - Surface tab switched —
activeSurfaceIdupdates; previously open provenance drawer closes. Covered for all eight tabs bylilith-studio-shell-smoke.spec.ts. - Provenance drawer open — drawer visible with
data-open-provenance-idset. Covered bylilith-studio-shell-smoke.spec.ts. - Provenance drawer closed — drawer absent; "Open provenance" button
visible. Covered by
lilith-studio-shell-smoke.spec.ts. - Offline — page is mostly static client JSX with internal links; no fetch; renders offline
Interactions#
Aside#
- "Open V1 Studio" link (
data-testid="lilith-v1-studio-link") — href/studio
Header actions#
- "Review workflow" link — href
/studio/review-approval-workflows - "Asset preview" link — href
/studio/asset-preview-pipeline
Continuity lanes (4 lanes)#
- Workflow lane link (icon button) — href
/studio/review-approval-workflows(aria-label "Open Editorial workflow") - Asset library lane link — href
/studio/yemaya/asset-library - Taxonomy lane link — href
/studio/hathor/journal-and-codex - Versioning lane link — href
/studio/hathor/entity-version-management - Lane entry rows — read-only items per lane, all 12 stable
data-lane-entry-idvalues asserted.
Surface tabs (8 tabs)#
- Scene authoring tab (
data-surface-id="scene-authoring",aria-pressed)- Function: sets
activeSurfaceId='scene-authoring'; closes any open provenance
- Function: sets
- Avatar and costume tab (
avatar-costume) - Asana authoring tab (
asana-authoring) - Persona dossiers tab (
persona-dossiers) - Music authoring tab (
music-authoring) - Concert authoring tab (
concert-authoring) - Provenance inspector tab (
provenance-inspector) - Release bridge tab (
release-bridge)
Surface detail panel#
- "Open
" link (data-testid="lilith-studio-open-active-surface") — hrefactiveSurface.routeContract(e.g.,/lilith-studio/scenes) - Authoring-contract list — read-only checklist with stable
data-contract-count - "Open provenance" button
(
data-testid="lilith-studio-open-provenance")- Function:
setOpenProvenanceId(activeSurface.provenanceId)
- Function:
- Release-checks list — read-only with stable
data-release-check-count
Provenance drawer (when open)#
- Drawer dialog (
role="dialog",aria-labelledby="lilith-studio-provenance-title") - Close button (icon,
X) — setsopenProvenanceId(null) - Audit list — three checks (Source lane, Route contract, Release branch chain)
Provenance inspector (full)#
-
LilithProvenanceInspector— surface-level provenance browser (read its own walkthrough; here it lists all 8 V3 assets)
Data & contracts#
- Reads: in-file constants
LILITH_STUDIO_V1_CONTINUITY_LANES,LILITH_STUDIO_V3_AUTHORING_SURFACES,LILITH_STUDIO_SHELL_PROVENANCE_ASSETS(derived) - Writes: none — client state only (
activeSurfaceId,openProvenanceId) - Realtime: none
- Caching: client bundle
- Auth/role check: signed-in is enforced upstream; the editorial-role gate
lives in
apps/oshun/web/src/app/lilith-studio/layout.tsx, which callshasLilithStudioAccess()(src/lib/customer-role.ts) requiring anadmin:*orstudio:editorialscope. With access it renders the<ShellLayout active="studio">+ children; without it the layout renders<LilithStudioAccessDenied />in place of the authoring shell. This layout gate covers/lilith-studioand every/lilith-studio/*sub-route, so the per-pagedata-v1-editorial-roleflag is now a display detail, not the enforcement point.
Cross-references#
- Sub-surfaces (one file per sub-route):
- Lilith design system index:
lilith.md - Component sources:
apps/oshun/web/src/app/lilith-studio/layout.tsx(shell mount + scope gate)apps/oshun/web/src/app/lilith-studio/LilithStudioShell.tsxapps/oshun/web/src/app/lilith-studio/LilithProvenanceInspector.tsxapps/oshun/web/src/app/lilith-studio/LilithStudioAccessDenied.tsxapps/oshun/web/src/app/lilith-studio/release/page.tsx
- E2E evidence:
apps/oshun/web/e2e/lilith-studio-shell-smoke.spec.tsapps/oshun/web/e2e/lilith-provenance-inspector-smoke.spec.ts
Open questions / known gaps#
- Resolved: non-editorial roles are blocked by
layout.tsx(hasLilithStudioAccess()→admin:*/studio:editorial), which renders<LilithStudioAccessDenied />instead of the shell for the whole/lilith-studio/*subtree - Resolved: the Release bridge surface (
/lilith-studio/release) now has a route, release-state page, provenance inspector, and E2E coverage. - Document how role can be changed from the default
v1_editorial_producer— the shell takesroleas a prop but the page wraps it without passing one