V1 Web PWA · Surface walkthrough

Lilith Studio · Saraswati persona dossier editor

A per-surface walkthrough of the V1 Web PWA customer surface: layout, states, interactions, data, and cross-references.

walked
8sections5 minread

On this page

Context. surface customer · domain lilith · route /lilith-studio/personas · auth signed-in + role:v1_editorial_producer (default) · source apps/oshun/web/src/app/lilith-studio/personas/page.tsx

Last walked. 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 2026-06-28 focused automated Playwright + component walk — route hydration, seeded draft, validation acknowledgement, all identity inputs, genre guardrails, catalog controls, clear/public-figure voice build branches, matched and no-match hand-off runtime states, add/edit/remove hand-off rule rows, publish-ready/blocked/published states, manifest readouts, provenance inspector, shell entry, and mobile no-horizontal-overflow check verified. Evidence: apps/oshun/web/e2e/lilith-saraswati-persona-dossier-smoke.spec.ts; apps/oshun/web/src/app/lilith-studio/personas/SaraswatiPersonaDossierEditor.test.tsx

Purpose#

Publish a complete Saraswati artist persona only when backstory, voice signature, avatar, genre cell, catalog policy, and operator hand-off rules all pass validation. Backed by @oshun/tenant-saraswati-stage (createSaraswatiPersonaDossierEditorState, voice-signature build / review, operator hand-off enforcement, dossier publish). The page (apps/oshun/web/src/app/lilith-studio/personas/page.tsx) returns <SaraswatiPersonaDossierEditor /> directly; the <ShellLayout active="studio"> wrapper and the editorial scope gate are supplied by the route's apps/oshun/web/src/app/lilith-studio/layout.tsx.

Entry points#

  • Lilith Studio shell (/lilith-studio) — "Persona dossiers" surface tab → "Open Persona dossiers" link
  • Direct URL / bookmark — yes (signed-in)

Layout regions#

SaraswatiPersonaDossierEditor (apps/oshun/web/src/app/lilith-studio/personas/SaraswatiPersonaDossierEditor.tsx):

  • Header: eyebrow "Saraswati editorial", title "Persona dossier editor", lede, two header actions — "Studio shell" → /lilith-studio and "Validate dossier" button (data-saraswati-persona-validate)
  • Multi-panel grid:
    • Identity panel (aria-labelledby="persona-identity-title"):
      • Persona id input (data-saraswati-persona-id)
      • Display name input (data-saraswati-persona-display-name)
      • Backstory summary textarea (data-saraswati-persona-backstory)
      • Sophia citation ids input (comma-separated; data-saraswati-persona-citations)
      • Cultural review ref (data-saraswati-persona-cultural-review)
      • Rights review ref (data-saraswati-persona-rights-review)
      • Voice signature ref (data-saraswati-persona-voice-signature)
      • Avatar ref (data-saraswati-persona-avatar-ref)
      • Genre cell select (data-saraswati-persona-genre-cell); options from SARASWATI_PERSONA_GENRE_CELLS
      • Genre guardrail list (aria-label="Genre guardrails") — read-only per cell.id
    • Catalog policy panel:
      • Release cadence select (data-saraswati-persona-release-cadence) — options: Single monthly / EP quarterly / Album at GA
      • Track count input (data-saraswati-persona-track-count)
      • Remix rights mode select (data-saraswati-persona-remix-rights) — Editorial only / Licensed community remix / Blocked remix
      • Distribution mode select (data-saraswati-persona-distribution-mode) — In-world only / In-world plus DSP / Concert exclusive window
      • Provenance required toggle (data-saraswati-persona-provenance-required)
      • Explicit content toggle (data-saraswati-persona-explicit-content)
    • Voice signature build panel — voice probe controls and receipt textarea (aria-label="Voice signature build receipt"); public-figure match probe option vs "clear" build
    • Voice ownership clauses list (aria-label="Voice ownership contract clauses")
    • Operator hand-off rules panel:
      • "Add rule" button (data-saraswati-persona-handoff-add)
      • Runtime prompt input (data-saraswati-persona-handoff-runtime-prompt); default copy "A fan asks for medical advice in persona voice before the listening room opens."
      • Runtime decision result block (data-saraswati-persona-handoff-runtime-result)
      • Rule grid (data-saraswati-persona-handoff-rule-list); per rule: Remove icon (aria-label="Remove <label>"), Rule ID, Label, Trigger, Scope select, Severity select (Routine / Priority / Urgent), SLA input, Queue input
    • Validation panel: empty state (data-saraswati-persona-no-issues) or issue list (data-saraswati-persona-issue-list)
    • Publish controls:
      • "Publish dossier" button (data-saraswati-persona-publish)
      • Publish receipt textarea (data-saraswati-persona-publish-manifest, aria-label="Persona dossier publish receipt")
  • LilithProvenanceInspector — surface ID persona-dossier-editor

States#

  • Hydrated route — client component reaches data-hydrated="true" after mount in the real browser
  • Seeded draftSARASWATI_PERSONA_DOSSIER_SEED populates fields including persona id persona-saraswati-anaya-veil
  • Validation pendingvalidationAcknowledged === false
  • Validation acknowledged — pressing "Validate dossier" sets the flag (consumed by other UI sections)
  • Voice build clearvoiceProbeMode='clear'
  • Voice build public-figure matchvoiceProbeMode='public-figure-match'; probe rejection appears
  • Hand-off rule matcheddata-handoff-runtime-state reflects match; primaryMatch.scope populates data-handoff-runtime-scope
  • Hand-off rule not matcheddata-handoff-runtime-state="no-match"; data-handoff-runtime-scope="none"
  • Publish blockededitorState reports issues; publish button disabled
  • Publish ready — all required fields valid
  • PublishedpublishReceipt set; manifest textarea populated
  • Offline — client-only; works offline

Interactions#

  • "Studio shell" link — href /lilith-studio
  • "Validate dossier" button (data-saraswati-persona-validate)
    • Function: setValidationAcknowledged(true)

Identity panel#

  • Persona id input
  • Display name input
  • Backstory summary textarea
  • Sophia citation ids input (comma-separated → list)
  • Cultural review ref input
  • Rights review ref input
  • Voice signature ref input
  • Avatar ref input
  • Genre cell select
  • Genre guardrail list — read-only per genre cell

Catalog policy panel#

  • Release cadence select
  • Track count input
  • Remix rights mode select
  • Distribution mode select
  • Provenance required toggle
  • Explicit content toggle

Voice signature build#

  • Voice probe mode toggle (Clear / Public-figure match)
  • Build voice signature button — submits voiceBuildInput to buildSaraswatiVoiceSignature
  • Voice receipt textarea (read-only, aria-label="Voice signature build receipt")

Operator hand-off rules#

  • "Add rule" button (data-saraswati-persona-handoff-add)
  • Runtime prompt input (textarea / input)
  • Runtime decision result block
  • Each rule row:
    • Remove icon button (aria-label="Remove <label>")
    • Rule ID, Label, Trigger, Scope, Severity, SLA, Queue editable fields

Validation#

  • No-issues empty state (data-saraswati-persona-no-issues)
  • Issue list (data-saraswati-persona-issue-list) — per-issue detail rows

Publish#

  • "Publish dossier" button (data-saraswati-persona-publish, release button)
    • Function: publishSaraswatiPersonaDossier(...)
    • Disabled when validation reports issues
  • Publish receipt textarea (read-only)

Provenance inspector#

  • LilithProvenanceInspector — read its own walkthrough

Data & contracts#

  • Reads / writes: in-process via @oshun/tenant-saraswati-stage: SARASWATI_PERSONA_DOSSIER_REQUIRED_FIELDS, SARASWATI_PERSONA_DOSSIER_SEED, SARASWATI_PERSONA_GENRE_CELLS, SARASWATI_VOICE_RIGHTS_OWNERSHIP_SUMMARY, SARASWATI_VOICE_SIGNATURE_BUILD_SEED, SARASWATI_VOICE_SIGNATURE_PUBLIC_FIGURE_MATCH_PROBE, plus the family of *Saraswati* mutators/getters
  • Realtime: none
  • Caching: client bundle
  • Auth/role check: inherited from lilith-studio/layout.tsx, requiring admin:* or studio:editorial
  • Validation rules:
    • Persona id must match persona-saraswati-*
    • Display name needs at least two words
    • Backstory needs at least 35 words, at least two sophia:saraswati:* citations, and cultural/rights review refs
    • Voice signature must point to voice-sig:consent-ledger:*; avatar must point to avatar:saraswati:*
    • Catalog policy requires a valid cadence, remix-rights mode, distribution mode, at least 12 debut tracks, and required provenance bundle
    • At least two operator hand-off rules are required; each rule needs valid handoff-* id, two-word label, specific trigger, supported scope/severity, lilith-* queue, and 1-60 minute SLA

Cross-references#

Open questions / known gaps#

  • Document current publish persistence — publishSaraswatiPersonaDossier returns an in-process receipt and does not write to a back-end in the current V3 tenant package
  • Document the full validation rules (which inputs gate publish)
  • Verify the voice-signature public-figure match probe — it rejects impersonation by policy; cross-reference Lilith voice-quality policy (V1/features.md#lilith-persona-policy)
  • Cold offline behavior for /lilith-studio/personas remains unproven beyond client-only implementation review