# Journey: Persona / voice / avatar lifecycle — author, govern, release, select

Oshun ships substantial persona tooling, but it currently exposes several
parallel records rather than one automatically connected release pipeline. The
Saraswati dossier editor and avatar-costume authoring page validate and publish
in component state. The admin publication route mutates a coarse persona
workspace record after governance and calibration gates. `/operator/personas`
drives a durable, audited lifecycle state machine. `/personas` browses a static
launch catalogue and persists an eligible member's active choice. A successful
action in one seam does not promote, remove, or update the others.

## Personas

- **Editorial producer** — authors the Saraswati dossier, voice build, hand-off
  rules, and avatar costume specimen.
- **Governance operator** — supplies actor signoffs and rollback evidence in the
  lifecycle console.
- **Safety/release reviewer** — completes the roles required by the pure
  lifecycle validator and separate admin publication gates.
- **Consumer** — browses eligible launch personas, grants voice/avatar consent,
  selects an active guide, and reads that choice back.

## Pre-conditions

- The producer needs the Lilith Studio customer-role gate for
  `/lilith-studio/personas` and `/lilith-studio/avatar-costume`.
- The lifecycle operator needs `admin:workspace:persona`, `admin:studio`, or
  `admin:*` for `/operator/personas` and the lifecycle routes.
- The lifecycle store is seeded with `persona-zen-guide`, `persona-stoic-guide`,
  and `persona-sufi-guide` and is wired to the durable snapshot store at server
  startup.
- A consumer needs an authenticated session; tier, locale, surface, and real
  voice/avatar consent are resolved server-side.
- Treat persona ids across the editor, admin workspace, lifecycle store, and
  launch catalogue as separate namespaces unless code proves a join.

## Steps

### 1. Author and validate the dossier

In `/lilith-studio/personas`, edit the Saraswati seed, citations, policy,
voice/avatar references, and operator hand-off rules. The editor validates
required fields, blocks the public-figure probe and excessive voice false-
positive rate, and can build a structured voice receipt. **Publish persona
dossier** calls `publishSaraswatiPersonaDossier` and renders its receipt in
component state. It does not call the BFF or seed the lifecycle store.

### 2. Author an avatar costume slot

In `/lilith-studio/avatar-costume`, select a slot, garment, palette, and safety
variant, then advance the local round trip from draft through preview,
editorial, approved, and released. The manifest includes policy and provenance
fields. The page does not persist a pack or connect the released slot to the
dossier, admin workspace, or consumer catalogue.

### 3. Drive the real lifecycle state machine

Open `/operator/personas`. The console reads `GET /v1/admin/personas/lifecycle`,
lists only currently legal events, and posts signoffs to
`/v1/admin/personas/:id/lifecycle`. The BFF stamps emission time, checks
optimistic `currentStatus`, calls `transitionPersonaLifecycle`, appends the
returned audit event, and writes a snapshot.

The preferred release chain is:

`drafted → in-review → rehearsal → approved-for-test → approved-for-release → released`

via `submit-for-review`, `enter-rehearsal`, `pass-rehearsal-for-test`,
`approve-for-release`, and `release-to-customers`. The legacy `approve` and
`publish` aliases remain legal in defined states. Live-exposure events require a
rollback plan; deprecate, retire, unretire, depublish, return-to-draft, and
emergency-retire use their own actor/justification gates.

### 4. Keep rehearsal and admin publication distinct

The real admin rehearsal and tone-calibration subsystems have their own records
and routes. Completing those records does not itself fire a lifecycle event.
Likewise, `POST /v1/admin/personas/:personaId/publish` changes the coarse admin
workspace status to `published` only after governance and fresh calibration
checks. It does not advance `personaLifecycleStore` and does not add an entry to
the consumer launch catalogue.

### 5. Browse and select a consumer persona

`/personas` calls the real `/v1/personas` and `/v1/personas/active` routes.
Browse and selection are derived from the static `LAUNCH_PERSONA_CONFIGS`,
multimodal assignments, launch roster, member tier/surface/locale, and real
voice/avatar consent. A successful selection is owner scoped and persisted by
the active-persona snapshot store; it also reads back through `/profile/persona`
for eligible voice personas.

The consumer routes never read the admin lifecycle store or coarse admin
publication record. Deprecating or retiring a seeded admin persona therefore
does not automatically remove a launch-catalogue card, and publishing a new
editor id does not automatically create one.

### 6. Record deprecation and retirement honestly

The lifecycle console can apply `deprecate`, `retire`, `unretire`, and
`emergency-retire` with validated actors and audit history. Library-artifact
migration, successor rendering, consent-revocation cascade, and removal from
consumer selection are not connected front-door outcomes in this journey.

## Post-conditions

- Every real lifecycle transition has durable status, an append-only lifecycle
  audit entry, and a shared operator audit event.
- Admin publication, rehearsal/calibration, dossier/avatar receipts, and active
  customer selection are reported as separate records.
- Consumer voice/avatar eligibility is verified through the real consent store.
- Active selection is read back for the same member and can be cleared.
- No automatic editor → lifecycle → admin publish → consumer catalogue chain is
  claimed.

## Failure modes

- **Editor validation failure** — required dossier fields, a public-figure
  match, voice FPR, or hand-off rule prevents the local receipt.
- **Static authoring state lost** — page reload clears dossier/avatar component
  state because no persistence request was made.
- **Lifecycle scope missing** — the BFF returns 401/403 before exposing or
  mutating persona status.
- **Stale status or illegal event** — optimistic conflict or lifecycle
  validation returns 409 without appending an audit entry.
- **Bad signoff envelope** — missing/duplicate actors, future-dated signoffs,
  absent justification, or an invalid rollback plan fails closed.
- **Admin publication blocked** — incomplete governance or tone/style
  calibration returns a structured 409.
- **Consumer ineligible** — tier, surface, locale, modality, or voice/avatar
  consent blocks selection.
- **False cascade assumption** — retirement is recorded in the lifecycle store
  while an unrelated static consumer card remains unchanged.

## E2E coverage

- [`apps/oshun/web/e2e/lilith-saraswati-persona-dossier-smoke.spec.ts`](../../apps/oshun/web/e2e/lilith-saraswati-persona-dossier-smoke.spec.ts)
  and
  [`apps/oshun/web/e2e/lilith-avatar-costume-smoke.spec.ts`](../../apps/oshun/web/e2e/lilith-avatar-costume-smoke.spec.ts)
  cover the two in-component authoring specimens.
- [`apps/oshun/web/e2e/persona-lifecycle-bff.spec.ts`](../../apps/oshun/web/e2e/persona-lifecycle-bff.spec.ts)
  and
  [`apps/oshun/web/e2e/operator-personas-console.spec.ts`](../../apps/oshun/web/e2e/operator-personas-console.spec.ts)
  cover the real state machine and operator UI.
- [`apps/oshun/web/e2e/persona-rehearsal-bff.spec.ts`](../../apps/oshun/web/e2e/persona-rehearsal-bff.spec.ts)
  and
  [`apps/oshun/web/e2e/persona-governance.spec.ts`](../../apps/oshun/web/e2e/persona-governance.spec.ts)
  prove the separate rehearsal/calibration and admin publication gates.
- [`apps/oshun/web/e2e/persona-session-picker.spec.ts`](../../apps/oshun/web/e2e/persona-session-picker.spec.ts),
  [`apps/oshun/web/e2e/personas-picker.spec.ts`](../../apps/oshun/web/e2e/personas-picker.spec.ts),
  and
  [`apps/oshun/web/e2e/profile-persona-readback.spec.ts`](../../apps/oshun/web/e2e/profile-persona-readback.spec.ts)
  cover consent, selection, persistence, clear, and profile read-back.
- Coverage is **deep for each seam and partial for the cross-seam release
  narrative** because no orchestrator joins them.

## Per-view files touched

- [`customer/10-lilith/lilith-studio-personas.md`](../customer/10-lilith/lilith-studio-personas.md)
  — dossier and voice authoring.
- [`customer/10-lilith/lilith-studio-avatar-costume.md`](../customer/10-lilith/lilith-studio-avatar-costume.md)
  — costume authoring.
- [`operator/operator-personas.md`](../operator/operator-personas.md) — durable
  lifecycle console.
- [`customer/10-lilith/personas.md`](../customer/10-lilith/personas.md) —
  consumer picker.
- [`customer/09-account/profile-persona.md`](../customer/09-account/profile-persona.md)
  — active voice projection.

## Cross-references

- [`editorial-review-approval.md`](./editorial-review-approval.md) — separate
  editorial queue/release-stream seam.
- [`first-tara-sit.md`](./first-tara-sit.md) — downstream session behavior.
- Feature contract: [`V1/features.md`](../../V1/features.md).
- Code: `libs/oshun/persona-registry/src/lifecycle.ts`,
  `apps/oshun/bff/src/admin/persona-lifecycle-store.ts`,
  `apps/oshun/bff/src/routes/personas-consumer.ts`, and
  `libs/oshun/persona-registry/src/customer-persona-browse.ts`.

## Open questions

- Which service should orchestrate dossier/avatar publication, calibration,
  lifecycle release, and launch-catalogue deployment as one auditable change?
- Should consumer browse evaluate the live lifecycle snapshot before exposing a
  card?
- How should deprecation, emergency retirement, consent revocation, and kept-
  artifact migration propagate across stores?
- Should the editor load/save durable dossiers and avatar packs instead of
  generating local receipts?
- Which catalogue owns preview media URLs and the immutable released version
  shown to consumers?
