# Saraswati Stage: Personas, Discography & Performance

```mermaid
stateDiagram-v2
  [*] --> PersonaDraft
  PersonaDraft --> PersonaApproved: identity and editorial review
  PersonaApproved --> TrackDraft: commission music
  TrackDraft --> Gated: grounding, tone, mastering
  Gated --> TrackDraft: reject with evidence
  Gated --> Released: rights, fingerprint, provenance pass
  Released --> Rehearsal: bind track and persona to Sequencer
  Rehearsal --> Live: concert-quality gate passes
  Live --> VOD: approved capture and package
  VOD --> [*]
```

The artist, recording, and performance are separate governed states. A persona
can exist without a released track, and a released track cannot become a live
show until the authored Sequencer package clears its own quality boundary.

Saraswati Stage is V3's AI virtual-artist tenant — a roster of persistent
personas inside the Lilith metaverse who hold a backstory, release a catalog,
and play scheduled concerts to a stadium audience. The product splits cleanly in
two, and the split is the whole feature set. **Discography** is engine-agnostic:
an editorial brief enters a job queue, Isis orchestrates a generation provider,
and a draft track passes through a fixed chain of pure-function gates —
grounding, tone, mastering, review, fingerprint, provenance — before it can
become a release. **Live performance** is the opposite: a UE5 Sequencer asset is
the canonical concert, driving MetaSound music, Niagara stage FX, a MetaHuman
performer, and between-song speech against an NTP-style music clock. The seam
between them is a released track plus a persona: everything the pipeline
produces becomes either a row in the in-world discography or a cue track in a
concert Sequencer. This page covers the three features that carry that promise —
**persistent artist personas**, the **discography and music-generation
pipeline**, and the **live performance engine** — grounded in
`@oshun/tenant-saraswati-stage` (`libs/v3/saraswati-stage`), `@oshun/isis-music`
(`libs/v3/isis-music`), and `@oshun/v3-concert-quality`
(`libs/v3/concert-quality`). The broader concert-design reference is the
test-covered [`@calliope/stage`](../../libs/calliope/stage) specification. The
section hub is [../V3_features.md](../V3_features.md).

## Naming and the Calliope boundary

Cross-product surfaces call this tenant **V3 Stage** and use technical channel
id `v3.stage`. Existing package names, persistence models, capability types, and
Unreal asset paths keep the historical Saraswati Stage name to avoid a broad
data/code migration. This explicitly separates the virtual-artist venue from the
unrelated [`@saraswati/*`](../../libs/saraswati/README.md) industrial-
technology domain (EVs, batteries, manufacturing, robotics, IoT, and health
hardware). A later public brand is an explicit human naming gate, not a reason
to leave the technical namespace ambiguous.

`@calliope/stage` is the normative concert-design specification for concept,
setlist, stage geometry, lighting, screens, choreography, venue, cameras, VFX,
spatial audio, audience simulation, streaming plans, and VOD package plans. V3
does not currently import that package at runtime: V3 owns tenant persistence,
rights/provenance, recorded editorial evidence, export quality, and its Unreal
concert contract. Future cook-time composition should select Calliope outputs
instead of duplicating those types, then pass the result through V3's gates and
a real renderer. Calliope's protocol/VOD descriptions and V3's Sequencer asset
ids are plans and contracts, not proof of playable video bytes. The Rail audit
records the complete relationship and media gaps in
[`V10/RA8_V3_STAGE_CHANNEL_INTEGRATION.md`](../../V10/RA8_V3_STAGE_CHANNEL_INTEGRATION.md).

## What ships, honestly

The **persona, generation, rights, and concert-authoring gates are real,
domain-specific TypeScript**, each with a validation suite that asserts computed
behaviour, not shape. Here is the split before the details.

- **A persona is a validated dossier, not a model checkpoint.**
  `validateSaraswatiPersonaDossierDraft()` enforces 17 required fields and
  `publishSaraswatiPersonaDossier()` **throws** unless every blocking field
  passes; a runtime `persona-policy-lock` refuses medical/legal/financial advice
  across all six GA personas with a zero-breach adversarial bar.
- **The generation pipeline is a chain of fail-closed gates.** Provider routing
  with a cost/quality comparator and a real failover drill, a Sophia-grounded
  lyric factuality check that catches a fabricated Grammy claim, an
  auto-mix/master pass with `-14 LUFS` / `-1 dBTP` targets and a
  release-blocking review queue, a 50-track Audible-Magic/Pex fingerprint
  firewall, and a **real Ed25519** C2PA track signer with genuine tamper
  detection.
- **A concert can't publish half-authored.** A ten-gate authoring pipeline
  refuses to publish until every gate passes, and `@oshun/v3-concert-quality`
  splices a judge-panel scene-quality + diversity gate into the same
  release-gate suite as the C2PA and consent gates.

Three honest qualifications travel with that. **First**, the pipeline does **not
call live music or TTS providers.** `routeSaraswatiMusicProvider` scores a
static in-repo registry; `buildSaraswatiGroundedLyricDraft` returns a
deterministic lyric fixture and the _tested_ logic is the factuality gate around
it; the auto-mix/master pass is a settings-and-review model, not a DSP renderer;
the fingerprint matcher is token-overlap scoring against a synthetic catalog.
These are honest gate harnesses with the real providers (Suno/Udio,
Cartesia/ElevenLabs, Audible Magic/Pex) as provider-gated seams. **Second**, the
"concert Sequencer asset" is **JSON text, not a binary cooked `LevelSequence`**
— a descriptor paired with a contract; the MetaSound graphs, Niagara systems,
MetaHuman performer, and motion/lighting presets are authored UE content, not
code in this repo. **Third**, off-platform distribution (Spotify / Apple Music),
PRO-society registration, and the Adobe CAI trust root are provider-gated. The
sections below say where each claim is backed. (The fan economy, voice-consent
contracts, genre cells, and remix rights have their own deep treatment in the
sibling page
[./saraswati-economy-voice-genre-rights.md](./saraswati-economy-voice-genre-rights.md).)

## Persistent artist personas

A Saraswati artist is a persona dossier, a runtime policy lock, and a
consent-bound voice signature — all in `libs/v3/saraswati-stage/src`.

### The dossier that makes an artist

`persona-dossier-editor.ts` defines a `SaraswatiPersonaDossierDraft`: a
**backstory** (a ≥ 35-word summary, at least two Sophia citations in the
`sophia:saraswati:` namespace, plus a cultural-review and a rights-review ref),
a **voice signature ref** that must point at the consent ledger
(`voice-sig:consent-ledger:`), a Saraswati **avatar ref**, a **genre cell**, a
**catalog policy** (release cadence, a `minimumDebutTrackCount` of at least 12,
a remix-rights mode, a distribution mode, and a `requiresProvenanceBundle` flag
that must be true), and at least two **operator hand-off rules**.
`validateSaraswatiPersonaDossierDraft()` runs all of this as blocking field
checks — regex on the `persona-saraswati-*` id, a prefix check on each ref, a
genre-cell membership test — and `publishSaraswatiPersonaDossier()` throws
`cannot publish until blocking fields pass` with the offending field list unless
the draft is `ready-to-publish`. The seed persona is the fictional "Anaya Veil"
(`SARASWATI_PERSONA_DOSSIER_SEED`), whose backstory is explicitly tagged
fictional and grounded in conservatory-archive citations rather than borrowed
from any living artist. The six canonical genre cells are real constants
(`SARASWATI_PERSONA_GENRE_CELLS`: electronic, indie-folk, hip-hop,
classical-fusion, ambient-ritual, experimental-pop), each carrying an
`editorialGuardrail` string (the ambient-ritual cell forbids medical claims;
experimental-pop keeps public-figure-similarity checks locked).

Hand-off is not just a stored rule.
`enforceSaraswatiPersonaOperatorHandOffRules()` is a runtime matcher: it
normalizes the user prompt, scores each rule against its scope keywords
(`HAND_OFF_SCOPE_KEYWORDS`) and its trigger terms, sorts matches by severity
then SLA, and returns an `operator-handoff` decision with an audit event id when
a rule fires — so the persona's "hand off when an interaction crosses policy"
promise is executable, not a dossier note.

### The persona policy lock

`persona-policy-lock.ts` governs what an artist persona will say at runtime —
lyrics, between-song speech, fan interaction. Each of the six GA persona
profiles (`createSaraswatiGAPersonaPolicyLockProfiles()` seeds Raga Devi, Laila
Qadri, Mira Sol, Amara Chen, Zahra Nile, Ines Vale) locks three advice classes —
`medical`, `legal`, `financial` — and `enforceSaraswatiPersonaPolicyLock()`
classifies a prompt into `stay-in-persona`, `graceful-noop`, or
`operator-handoff`. A locked-advice hit, a public-figure-imitation request, or
targeted political persuasion routes to `operator-handoff` (queue
`lilith-safety-saraswati-persona`, 10-minute SLA); a role-swap jailbreak or a
system-prompt-disclosure attempt is a `graceful-noop` that stays in character
without leaking. The fail-loud signal is `policyBreached`: it is set only when a
prompt that _did_ match a reason somehow returned `stay-in-persona`.
`evaluateSaraswatiPersonaPolicyLockSuite()` runs six adversarial attack prompts
across all six personas — 36 cases — and passes only when
`policyBreachCount === 0` **and** no locked-advice request escaped the operator
hand-off. This is the gate that separates "a persona with a tone" from "a
persona that cannot be talked into diagnosing your chest pain."

### The voice signature as persona identity

A persona's voice is built only from consent-ledger source material.
`voice-signature-build.ts`'s `reviewSaraswatiVoiceSignatureBuild()` requires a
Saraswati persona id, a `voice-sig:consent-ledger:` ref, at least **60 clean
consented source minutes** across grants, and rejects any grant whose scope is
not `saraswati-persona-only` or that has been revoked. The safety-critical check
is `findPublicFigureMatch()`: a probe score at or above
`SARASWATI_VOICE_SIMILARITY_MATCH_THRESHOLD_BASIS_POINTS = 8600` (86 %) against
a known public figure is a **blocking** issue, and the validation-corpus
false-positive rate must stay at or under 100 basis points (1 %).
`buildSaraswatiVoiceSignature()` throws if the review status isn't `ready`, so a
public-figure-like voice never produces a model artifact;
`signOffSaraswatiGAVoiceSignatures()` builds all six GA personas, runs an
adversarial 91.2 %-similar public-figure probe, and asserts it is `blocked`
before any signature builds. `fanVoiceUploadsAccepted: false` is baked into
every consent dossier. The deeper rights, contributor compensation, and
consent-contract machinery around this gate live in
[./saraswati-economy-voice-genre-rights.md](./saraswati-economy-voice-genre-rights.md);
here it is the identity safety property that makes a persona buildable.

## Discography and the generation pipeline

The catalog pipeline runs entirely off-engine. Each gate is a pure function with
a validation suite; nothing fabricates a "success" it didn't compute.

### Provider routing and failover

`isis-music/src/provider-routing.ts` registers six music providers — `suno`,
`udio`, `stable-audio`, `musicgen`, `audiocraft`, `mubert` — each carrying a
`costPerMinuteCents`, a `qualityScore`, a `latencyP95Ms`, a
`maxDurationSeconds`, and `supportsStems`/`supportsLyrics` flags.
`routeSaraswatiMusicProvider()` filters out providers that are unavailable,
already failed, can't meet the requested duration, or lack a required
capability, then sorts the survivors: in `cost` mode by cents ascending (quality
breaks ties), in `quality` mode by score descending (cost breaks ties). The
first survivor is selected; the rest become a `failoverChain`.
`drillSaraswatiMusicProviderFailover()` proves the chain is real — it routes
once, marks the winner failed, re-routes, and asserts the second pick differs
from the first. Suno (quality `0.92`) wins quality routing; Mubert (`80¢`/min)
wins cost routing — the comparator is exercised against actual numbers. This is
the seam where the live Suno/Udio/Stable-Audio calls would land; the registry it
scores is static in-repo data, and that is the honest boundary.

### Grounded lyrics and tone

`grounded-lyric-generation.ts` is where the honest seam is sharpest.
`buildSaraswatiGroundedLyricDraft()` selects a model family (`claude-opus` for a
release candidate, `claude-sonnet` for a sketch) and emits a deterministic
four-line draft — but the substance is `evaluateSaraswatiLyricFactuality()`,
which splits the lyric into lines, decides which lines _look like_ factual
claims (a cue-phrase scan for `is`, `won`, `born`, `studied with`, …), and
requires each one to be supported by a phrase in a Sophia evidence pack. An
unsupported line is a `blocking` issue and the report flips to `blocked`. The
validation set proves the discrimination: a Sophia-grounded lyric about the
fictional Anaya Veil passes with zero unverifiable claims, while
`"Anaya Veil won the 2025 Grammy for Best New Artist…"` is correctly counted as
**one** unverifiable claim and blocked — `caughtKnownUnverifiableClaim` is the
gate's headline assertion. Tone is a separate pass: `lyric-tone-policy.ts`
scores the lyric against the Lilith contemplative persona policy (the
`bhakti-devotional` policy at threshold `0.7`, via
`@oshun/persona-policy-lilith`) and routes a violation to the editorial
moderation queue (`ongoing-content-qa-queue`).

### Auto-mix, master, and the editorial review gate

`mix-master-review-gate.ts` masters to streaming-loudness targets —
`SARASWATI_MUSIC_MASTER_TARGET_INTEGRATED_LUFS = -14`,
`SARASWATI_MUSIC_MASTER_TRUE_PEAK_DBTP = -1`, 48 kHz / 24-bit — with per-stem
settings (`createStemSettings` assigns gain / pan / compressor-ratio / high-pass
values across up to five stem kinds). The architectural point is the **review
queue**: every track enters `status: 'queued'` with `releaseBlocked: true`, and
only an explicit `approve-release` action flips it to `approved` and unblocks
it; `request-changes` and `reject-release` leave it blocked, and every action
writes a `SaraswatiMusicReviewAuditEvent`.
`evaluateSaraswatiAutoMixMasterReviewGate()` runs three tracks through approve /
request-changes / reject and asserts that exactly **one** is release-allowed,
the other two stay blocked, all three were surfaced before release, and one
audit event was logged per action — a gate that would fail if release ever
leaked past review.

### The fingerprint firewall and provenance

`fingerprint-pre-release-check.ts` is the rights firewall.
`SARASWATI_FINGERPRINT_REFERENCE_CATALOG` is 50 reference tracks tagged
`major-label` / `independent` / `public-domain` / `oshun-cleared`, each with an
Audible Magic and a Pex fingerprint. `scoreFingerprintMatch()` computes a real
similarity — token-set coverage weighted `0.9` plus a duration-proximity term
weighted `0.1` — gated at `SARASWATI_FINGERPRINT_MATCH_THRESHOLD = 0.82`. A
match against a **major-label** reference sets
`status: 'editorial-review-required'`, `releaseBlocked: true`, and mints a queue
item requiring `lilith-rights-review`, `license-documentation`, and editorial
approval. The validation report asserts both directions: an original track
clears, an independent-catalog match does **not** trigger major-label review,
and both an Audible-Magic and a Pex major-label match route to editorial. Every
released track then carries an Isis provenance bundle
(`track-provenance-bundle.ts` — model card, prompt seed, reference set,
generating user, persona, and a lineage-credit distribution that must total 100
%) and a C2PA manifest (`track-c2pa-manifests.ts`) whose six required assertions
include `org.oshun.v3.track-release` and `org.oshun.v3.rights-waterfall`. The
signature is a **real Ed25519** signature over the canonical claim payload using
`node:crypto` — the `SaraswatiTrackC2paSigner` seam takes an injected KMS key in
production and a deterministic dev key otherwise, so verification and tamper
detection are genuine (the source notes it is "not an FNV-1a string mislabeled
sha256").

### Release and the in-world catalog

`discography-release-flow.ts` enforces the editorial-approval-before-release
rule: `publishSaraswatiDiscographyTrack()` throws unless the candidate's
`editorialApprovalStatus === 'approved'` **and** the approval timestamp precedes
publish. A debut catalog is twelve tracks
(`SARASWATI_DEBUT_CATALOG_TRACK_COUNT`, seeded for Raga Devi as "Dawn Archive"
through "Afterimage Hymn"), and `buildSaraswatiInWorldCatalogSnapshot()`
propagates each release to the in-world catalog path
(`oshun://world/saraswati-stage/personas/<persona>/catalog`) within
`SARASWATI_IN_WORLD_CATALOG_MAX_PROPAGATION_SECONDS = 60`. The whole flow is
proven by `evaluateSaraswatiDiscographyReleaseFlow()` (12 approved → 12
published → 12 catalog-visible within 60 s) and rolled up by
`evaluateSaraswatiGaArtistInventory()`, an all-or-nothing readiness gate over
the six GA artists (Raga Devi, Anaya Veil, Moon Choir, Copper Lotus, River
Signal, Nocturne Kiran), each requiring 12 released tracks, two scheduled
stadium launch-window concerts, a voice-similarity FPR at or under 1 %, and zero
lyric tone breaches.

## Live performance

A concert is a UE5 Sequencer asset, and the canonical shape of one is the
**concert-master template**.

### The concert-master contract

`V3/ue/Content/Saraswati/Templates/ConcertMaster.v3sequence.json` is the
contract: schema `oshun.v3.saraswati.concert-master-template.v1`, owned by the
`V3Mode_SaraswatiConcert` Game Feature, binding six cue-track families — each
mapped to a **real UE MovieScene track class**: `music-sync` →
`MovieSceneAudioTrack` (the MetaSound `MS_ConcertMainMix`), `lighting` and
`particles` → `MovieSceneEventTrack`, `persona-motion` →
`MovieSceneSkeletalAnimationTrack` (the RagaDevi MetaHuman performer),
`audience-cam` → `MovieSceneCameraCutTrack`, and `between-song-speech` →
`MovieSceneEventTrack`. The `music-sync` track carries an
`ntp-style-concert-clock` with `maxDriftMs: 25` keyed off a `songStartNtpMs`
server timestamp. The `audience-cam` track encodes privacy as data —
`excludePrivacySeats: true`, `excludeCrowdBandIndividualHandles: true` — so a
camera sweep cannot frame a non-consenting attendee. The `between-song-speech`
track sets `personaPolicyLock: true`, names Sophia as the grounding provider and
Cartesia/ElevenLabs as TTS, and points at a pre-rendered MetaSound speech graph.
The automation test `V3.Saraswati.ConcertMasterTemplate`
(`V3SaraswatiConcertMasterTemplateTests.cpp`) validates this with
`LoadFileToString` + `Contains`: it asserts the `.uasset` resolves to the
canonical package path as a `LevelSequence`, that all six cue tracks exist with
their exact bindings, that the audience cam carries privacy constraints, and
that the 420-second preview fires all six cue types. The honest line: the
`.uasset` is **JSON text** and the test validates the _contract_, not a
Sequencer loaded in-editor.

### The ten-gate authoring pipeline

`concert-authoring-pipeline.ts` models the editorial workflow that fills that
template, as **ten release gates** (`SaraswatiConcertAuthoringGateId`):
persona-setlist proposal, per-track generation review, motion-preset bindings,
lighting/Niagara cues, Sequencer assembly, speech-bank review, audience
choreography, dress rehearsal, provenance publish, and GA cadence. Each gate has
a real predicate: the setlist must hold exactly 12 songs within a 2-working-day
window; the debut catalog must be reviewed within 6 working weeks; every song
must bind a motion preset and a lighting+Niagara cue pair within their 12-day
windows; the speech bank must hold 8–12 slots of 3–5 reviewed alternates each;
at least two staging dress rehearsals must be signed off; the publish receipt's
Isis provenance bundle must be visible in the inspector; and the GA cadence must
hold (6 artists × 2 concerts/month = 12/month over ≥ 60 days, all
editorial-signed-off). `publishSaraswatiConcertSequencer()` **throws** unless
every gate passes — and the receipt's `sequencerAssetId` resolves to
`/Game/Saraswati/Concerts/<concert>/ConcertMaster`, mirroring the template path.

### Between-song speech and scene quality

Between-song speech is **pre-generated and queued, never live-generated** — live
generation can't meet the beat-sync budget and would expose a policy violation
to a live audience without a review gate. Each setlist slot gets 3–5 editorially
reviewed alternates (each run through Sophia factuality, the persona policy
lock, and the persona voice signature, stored as a MetaSound stream), plus a
neutral cold-fallback; at showtime the concert director (or an AI-director rule)
picks the alternate that best fits the moment. Live unscripted Q&A is **not
supported at GA** — it moves to a post-show green room (`V3Mode_SaraswatiClub`).
What the authoring gates don't measure, `@oshun/v3-concert-quality` adds:
`concert-scene-quality-gate.ts` scores each scene/speech draft with the §1 judge
panel (`assessConcertSceneQuality` against a default bar of 70) and measures the
whole concert's draft set for corpus diversity (cluster coverage ≥ 0.6, mean
pairwise distance ≥ 0.25) and slop density (≤ 25 per 1000 words) — so a concert
can't be "eight phrasings of one line" even if each passes on its own. These are
`GateDefinition`s for the same `@oshun/content-release-gates` suite as the
C2PA/consent gates; `v3-concert-export.ts`'s `evaluateV3ConcertExport()`
composes the authoring release state, the provenance/consent gates, the scene
quality+diversity gates, and an optional stage-director sign-off into one
`ReleaseGateService` run, so a low-quality or homogeneous scene blocks
publishing exactly like a revoked consent or a bad signature — and fails loud on
an empty draft set rather than wave an empty concert through.

## How it connects

Saraswati Stage consumes V3's embodiment stack and produces for the tenant
experiences. Its MetaHuman performers and the ≤ 25 ms music-sync clock are
rendered and spatialized by the
[avatar, animation & spatial-audio stack](./avatars-nameplates-spatial-audio.md)
and the [Tier-1 / Stadium client](./client-tiers-fidelity-stadium.md); the
persona policy lock and grounded-lyric factuality reuse the Lilith
persona-policy and Sophia surfaces shared with the
[Tara instruction tenant](./tara-instructors-classes-coaching.md); and the C2PA
signing, consent registry, and provenance bundles sit on the shared
[identity, safety & provenance foundations](./identity-safety-provenance-foundations.md).
The fan economy, voice-consent contracts and compensation, genre cells, and
remix rights are the sibling
[economy, voice, genre & rights](./saraswati-economy-voice-genre-rights.md)
page; ticketing, venue tiers, and the programming calendar are in
[commons, venues & live service](./commons-venues-and-live-service.md); the full
gate chain and Sequencer internals are traced in the
[architecture companion](../architecture/saraswati-stage-pipeline.md). The
honest line throughout: the persona dossier and policy lock, the generation gate
chain, the C2PA signer, and the concert authoring/quality gates are real and
tested; the music and TTS models, the binary Sequencer and its MetaSound/Niagara
content, and the off-platform distribution are the runtime and providers they
gate.

## Related

- [Saraswati Economy, Voice, Genre & Rights](./saraswati-economy-voice-genre-rights.md)
  — the fan-economy tiers, voice-consent contracts and contributor compensation,
  genre-cell map and drift review, and per-track remix rights (sibling page)
- [Commons, Venues & Live Service](./commons-venues-and-live-service.md) —
  ticketing, hall/Stadium venue tiers, the programming calendar, and the
  archived-performance fallback (sibling page)
- [Avatars, Nameplates & Spatial Audio](./avatars-nameplates-spatial-audio.md) —
  the MetaHuman performers, MetaSounds spatialization, and the music-sync clock
  this pipeline drives
- [Identity, Safety & Provenance Foundations](./identity-safety-provenance-foundations.md)
  — the C2PA signing, consent ledger, and provenance substrate the catalog
  pipeline writes to
- [Saraswati Stage Pipeline (architecture)](../architecture/saraswati-stage-pipeline.md)
  — the engine-agnostic gate chain and the Sequencer + MetaSounds concert
  internals
- The section hub: [../V3_features.md](../V3_features.md)
