V3 ("Lilith") is an embodied, real-money, AI-generative metaverse where the same body can teach a yoga class, headline a stadium concert, or wander a commons — and where music, motion, costumes, and scenes are generated, not shipped. That combination makes two questions cert-blocking rather than nice-to-have: who is allowed to act through this body, and in what tone (persona policy at the avatar), and who owns, authored, and can revoke the thing this body just made (provenance and rights). V3 answers both by composing V1's safety, audit, and provenance machinery through thin, server-authoritative V3 surfaces — the same "don't reinvent trust" stance the platform takes everywhere. The avatar runs a client-side preview; every binding decision is made on a server. Every generated artifact is born with a provenance bundle and (on release) a signed content credential, and a rights withdrawal cascades on a bounded clock. This page is the architecture-side companion for the "Trust, Rights, Commerce, and Operations" set; the section hub is ../V3_ARCHITECTURE.md.
What ships, honestly#
The policy engine and the provenance/rights data plane are real TypeScript,
each backed by automation tests. libs/v3/lilith-body-policy (≈1,980 lines,
src/index.ts) is a fully-implemented, server-authoritative adapter over V1's
@oshun/persona-policy-lilith and @oshun/avatar-pipeline: rolling
voice-transcript tone scoring, a crisis-language classifier with a measured
recall/false-positive gate, costume-rule enforcement, avatar-swap impersonation
blocking, and a six-persona adversarial prompt suite are all computed, not
stubbed. On the provenance side, libs/shared/content-security implements C2PA
content-credential plans, Google SynthID watermark plans, forensic invisible
watermarks, a provenance-chain DAG with cycle detection and an integrity digest,
and a trust-scored authenticity verifier; libs/v3/isis-music's
track-provenance-bundle.ts writes the V3 Saraswati track bundle; and
libs/v3/saraswati-stage's track-c2pa-manifests.ts signs released tracks with
a genuine Ed25519 signature (Node crypto). Rights adjudication and the
24-hour enforcement bound are real code in themis-rights-adjudication.ts, and
consent ledgers (TTS-voice, class/concert recording) are real in tara-studio
and lilith-identity-bridge.
Three honest qualifications. First, @oshun/content-security is a
plan/verify layer: it emits the embedding command and the verification
policy, defines per-modality detection thresholds, and verifies
externally-supplied signature/detection evidence — the actual watermark DSP and
the C2PA cryptographic signing run in external tooling, and its stableHash is
an FNV-1a content-address for stable IDs, not a cryptographic digest (the V3
track signer, by contrast, is real Ed25519). Second, "Lilith-Rights" is an
operator-scope and role name (e.g. the operator id
user:lilith-rights:tara-tts-consent), not a single package — the machinery is
the composition of content-security, isis-music, saraswati-stage,
tara-studio, and the V1 @oshun/audit-platform described below. Third,
the full multi-surface takedown fan-out (archived performances flagged
historical, in-world replays paused, off-platform reshare notices) is a
documented cascade contract driven over the V1 event bus; what is coded and
gated is the Themis adjudication, the catalog-license pause, the
royalty-waterfall pause, and the 24-hour enforcement deadline. The sections
below say where each claim is backed.
Persona policy at the body#
The defining property is server authority. A UE client may run a
costume-rule preview before a wardrobe change commits, but
@oshun/lilith-body-policy makes every binding decision on the world server or
the relevant tenant service. The package's descriptor
(v3LilithBodyPolicyDescriptor) declares its upstreams exactly —
['@oshun/persona-policy-lilith', '@oshun/avatar-pipeline'] — and six
capabilities, each with an operational metric the tests assert
(v3LilithBodyPolicyReadinessScore returns matched/6, so a single live
capability scores 0.167). The five invocation points map to five evaluators:
| Trigger | Evaluator | Action on violation |
|---|---|---|
| Voice transcript (rolling 5 s) | evaluateV3VoiceTranscriptTonePolicy |
First miss prompts the speaker; the second routes voice-quality-violation to the V1 voice-quality-qa-queue. |
| Crisis language (rolling 5 s) | evaluateV3VoiceTranscriptCrisisClassifier → evaluateV3EmbodiedCrisisRouting |
In-world soft prompt + V1 crisis-response-queue handoff + on-call operator page. |
| Costume change | evaluateV3CostumeRulePolicy |
Costume blocked; v3.persona_policy.costume.checked audit event. |
| Avatar swap | evaluateV3AvatarSwapImpersonationPolicy |
Protected-persona swap outside a sanctioned cosplay zone routes to persona-registration-policy-mismatch review. |
| AI-persona interaction | evaluateV3AIPersonaEnforcement |
Out-of-scope asks graceful-no-op; medical/legal/financial/voice-copy/political hand off to a Lilith operator. |
The rolling window — context that decays#
Voice policy is windowed, not per-utterance, which matters for both tone and
crisis. buildV3VoiceTranscriptSlidingWindow assembles a 5,000 ms window
(V3_VOICE_TRANSCRIPT_WINDOW_MS), keeping only segments that match the session
and speaker and overlap [now − 5 s, now); another speaker's chatter and an
utterance that aged out are excluded by construction (a property the tests
assert: an "outside the active window" line never reaches the verdict). Tone
scoring delegates to V1's evaluateLilithContemplativeToneQuality; a failure
short of the repeat threshold (V3_TONE_OPERATOR_ROUTE_REPEAT_THRESHOLD = 2)
yields prompt-speaker, and the second failure escalates via
routeLilithModerationEvent to the operator queue with the failing tone axes in
the payload.
Crisis routing — measured, then embodied#
The same window feeds a crisis classifier built on V1's detectLilithCrises.
When a signal fires, buildLilithCrisisResponsePlan produces the resource set
and evaluateV3EmbodiedCrisisRouting assembles three things: a
non-dismissible in-world soft prompt (safety-overlay,
blocksPracticeResume: true, an assertive ARIA live region and a soft haptic
pulse), a handoff to the v1-lilith-crisis-routing pipeline, and an operator
notification that pages on-call and auto-suspends the session. This is not
best-effort: the classifier is validated against a labelled set of 22 positive
cases (one per LilithCrisisType — suicide-ideation, self-harm, acute-panic,
dissociation, trauma-resurfacing, substance, interpersonal/other-directed
violence, abuse, eating-disorder, child-safety, psychosis-adjacent, acute-grief)
and ~60 benign negatives, and evaluateV3CrisisClassifierValidationSet only
reports releaseGateGreen when recall ≥ 0.95 and false-positive-rate ≤ 0.02
(V3_CRISIS_CLASSIFIER_MIN_RECALL / ..._MAX_FALSE_POSITIVE_RATE). A separate
13-case evaluateV3EmbodiedCrisisRoutingDrill requires recall = 1.0 — every
drill prompt must produce the soft prompt, the handoff, and the page.
AI-persona enforcement — stay-in-persona is a state machine#
Each of the six GA Saraswati AI artists gets a policy profile from
createV3SaraswatiGAPersonaPolicyProfiles() (one per genre cell: electronic,
indie-folk, hip-hop, classical-crossover, ambient, devotional).
evaluateV3AIPersonaEnforcement resolves one of three actions:
stay-in-persona for in-scope asks; graceful-noop for role-swap and
system-prompt-disclosure attempts (matched against literal phrase sets like
'ignore previous instructions', 'reveal your system prompt',
'act as my private assistant'); and operator-handoff for the unsafe classes
— medical/legal/financial advice (via V1 classifyLilithUnsafeClaimClasses),
living-public-figure voice-copy (via detectLilithVoiceAbuseSignals against a
restricted-identity list), and political persuasion. The release gate is
evaluateV3SaraswatiAIPersonaAdversarialPromptSuite: 6 personas × 6
adversarial prompts = 36 cases, and passed is true only when
policyBreachCount === 0 — a single persona that breaks character, leaks a
prompt, or gives medical advice fails the suite. Critically, policyBreached
treats a stay-in-persona outcome on a prompt that should have been refused
as a breach, so the gate cannot be satisfied by a permissive classifier.
Provenance — every artifact is born documented#
V3 attaches provenance at two layers: a domain bundle that travels with the artifact in-platform, and a C2PA content credential that makes an export verifiable off-platform.
The V3 track provenance bundle#
writeSaraswatiTrackProvenanceBundle (isis-music/track-provenance-bundle.ts)
emits a saraswati.music.track-provenance-bundle.v1 record carrying the seven
required sections the inspector validates: the model card (provider, model,
version, training disclosure, license — e.g. "no living-artist voice clone"),
the prompt seed (deterministic seed + fingerprint, so a generation is
reproducible), the reference set (each a sha256-hashed source: a Sophia
citation, a rights clearance, a persona-policy tag), the generating user,
the persona (with its voiceConsentLedgerId), the lineage-credit
distribution (which inspectSaraswatiTrackProvenanceBundle rejects unless it
sums to exactly 100%), and the artifact refs (master, review preview,
inspector URI). The store-level evaluateSaraswatiTrackProvenanceBundleWrite
enforces everyGeneratedTrackHasBundle — no track ships without one. The same
bundle pattern is what avatar-pipeline uses for avatars
(createImportedAvatarProvenanceBundle(), both variants of a premium persona
sharing one bundle id), described in
Avatar, Animation & Spatial Audio.
C2PA on export — a real signature for tracks, a plan for the rest#
Two C2PA paths exist, and the honesty line runs between them.
saraswati-stage/track-c2pa-manifests.ts is the real-signature path: a
released track is signed with an Ed25519 key via Node crypto
(createDefaultSaraswatiTrackC2paSigner() uses a deterministic dev seed; the
production key is KMS-bound, with the Adobe-CAI trust root tracked as [~]),
and verifySaraswatiReleasedTrackC2paManifest performs genuine tamper detection
against the required assertions (c2pa.actions.v2,
org.oshun.v3.track-release, ...generated-artifact-provenance,
...rights-waterfall, ...pro-registration, ...adobe-cai-verification). The
shared content-security/provenance.ts is the plan/verify path:
createC2PAContentCredentialPlan builds the assertion store, signer binding
(ecdsa-p256-sha256), embedding command, and verificationPolicy
(requireSignature, requireManifestStore); createSynthIDWatermarkPlan emits
a Google-SynthID plan per modality with calibrated detection thresholds (text
0.78, image 0.82, audio 0.80, video 0.84); and verifyContentAuthenticity
computes a trust score (C2PA 0.40 + chain 0.25 + AI declaration 0.20 +
SynthID 0.15) and a verdict (verified-human … verified-ai-generated /
mixed-provenance / insufficient-evidence / tampered), surfacing typed
findings for each missing or mismatched signal. The createProvenanceChain DAG
proves lineage integrity: it topologically orders nodes, rejects cycles, and
records an integrity digest that validateProvenanceChainIntegrity recomputes
to catch tampering. This layer plans and verifies; the cryptographic embedding
runs downstream.
Forensic watermarking — invisible, per-recipient, robustness-tested#
content-security/watermarking.ts plans the invisible marks that make leaks
traceable: per-session video (luma-DCT midband, frame-cadenced tiles, robust
to transcode/compression/screen-capture), transcode-robust audio
(psychoacoustic spread-spectrum, 1.2–4.2 kHz band, time-scale invariant),
resilient image (DCT-wavelet hybrid), and per-recipient document
watermarks (recipient code + canary phrases + layout perturbation).
identifyWatermarkSource matches an extracted observation back to a registered
WatermarkRecord above a confidence floor, and
createWatermarkRobustnessTestSuite
evaluateWatermarkRobustnessdefine and score the transformation gauntlet each mark must survive. The provenance bundle records the watermark hash; this is how an off-platform reshare ties back to a session and a recipient.
Rights and takedown#
Themis adjudication on a 24-hour clock#
Ownership and unlicensed-use disputes route through
saraswati-stage/themis-rights-adjudication.ts, a three-step state machine:
fileSaraswatiThemisRightsDispute → issueSaraswatiThemisRightsDecision →
enforceSaraswatiThemisRightsDecision. Dispute kinds include
remix-priority-claim, ownership-challenge, sample-use-claim, and
independent-rights-holder-takedown; evidence kinds include
released-track-c2pa-manifest and consent-ledger (so the C2PA manifest and
the consent ledger are first-class adjudication evidence). A decision resolves
to credit-claimant, uphold-original-rights, or pause-release, and
enforcement emits the corresponding actions: rights-record-updated,
royalty-waterfall-updated, catalog-license-paused, claim-denial-audited.
The 24-hour SLA is a coded invariant, not a doc promise:
SARASWATI_THEMIS_RIGHTS_MAX_ENFORCEMENT_MS = 86_400_000, and
enforceSaraswatiThemisRightsDecision throws if enforcement lands more than
that after the decision (or before it).
evaluateSaraswatiIndependentRightsHolderTakedownFlow ties the knot for the
takedown case: it passes only when the outcome is pause-release, the
catalog-license-paused action fires with a real catalogHoldRef, and
enforcementLatencyMs ≤ 24 h. Upstream, fingerprint-pre-release-check.ts
(Audible Magic / Pex) catches collisions before release, returning
editorial-review-required when a master matches a major-label or independent
reference — so most rights conflicts are stopped at the gate, not litigated
after.
Consent and rights records#
Consent is stored as withdrawable ledgers, not one-time checkboxes.
tara-studio/tts-voice-consent.ts models the instructor voice-signature grant
(tara-tts-voice-signature-consent:v1, purposes aja-cues / localized-dubs,
status active/withdrawn, a 30-day withdrawal window, every change
written as a rights-log entry under the user:lilith-rights:... operator
scope), with sibling contract, scope-lock, and royalty-distribution modules.
lilith-identity-bridge/recording-consent.ts governs class and concert capture:
a participant chooses full / observer / decline-and-leave, which resolves
to a concrete avatarRecordingTreatment (visible / generic-silhouette /
not-recorded), voiceRecordingTreatment (master-mix /
excluded-from-master-mix), and chatRecordingTreatment, with minor-attendee
guardian confirmation required and a mid-session opt-out path. Every consent
decision and rights enforcement publishes a canonical event through V1's
@oshun/audit-platform — a hash-chained, tamper-evident ledger
(hash-chain.ts) with investigation export, compliance attestation,
content-license review, and source-asset lineage. V3 produces the evidence;
Oshun retains and exports the investigation-ready trail, and a DSAR over a V3
user joins these records to the UE/Pixel-Streaming session data the identity
bridge holds.
Edge cases and failure modes#
- Context decays, deterministically. The 5 s window excludes other speakers and aged-out utterances structurally, so a crisis line that scrolled past the window can't re-fire and a neighbour's words can't be scored against you.
- The crisis gate is two-sided. A permissive classifier can't pass — recall ≥ 0.95 catches misses and FPR ≤ 0.02 catches over-triggering; the drill demands recall = 1.0 for the full embodied response (prompt + handoff + page).
- Lineage must total 100%. A provenance bundle whose credit shares don't sum to exactly 100 is marked incomplete, and the store refuses to pass — royalty routing can't be ambiguous.
- Takedown is bounded, not eventual. Enforcement outside the 24-hour window throws; the takedown flow asserts the catalog hold and the latency bound together, so "paused, eventually" is not a valid state.
- Real signature vs. content-address. The track C2PA path detects tampering
with a genuine Ed25519 signature; the shared
stableHashis an FNV-1a identifier, and authenticity verification consumes externally-supplied signature evidence rather than minting it — read it as a verifier, not a signer. - "Lilith-Rights" is a role, not a service. Looking for a
lilith-rightspackage will mislead; the capability is the composition named above, gated by the operator scope that appears in the consent ledgers.
How it connects#
Persona policy reaches up into the embodiment stack and down into identity and
commerce. The costume and avatar-swap checks operate on the realms, costume
slots, and lilithSafetyCostumeRuleCheck defined in
Avatar, Animation & Spatial Audio, and the
account ↔ avatar binding every decision is made against is owned by the bridge
described in
V1 Integration & the Identity Bridge.
The rights side is the trust spine of the economy: the lineage-credit
distribution in the provenance bundle is exactly the royalty waterfall that
Commerce & Royalties settles on-chain via Aje,
and a Themis pause-release is what stops a payout mid-flight. The @oshun/*
packages this page composes — persona-policy-lilith, avatar-pipeline,
content-security, audit-platform — sit in the platform domain map at
../../platform/oshun-domain-libraries.html.
Related#
- Avatar, Animation & Spatial Audio — the realms, costume slots, and avatar provenance bundles persona policy enforces on
- V1 Integration & the Identity Bridge — the account ↔ avatar binding every server-authoritative decision references
- Commerce & Royalties — the royalty waterfall the provenance bundle encodes and a takedown pauses
- Oshun Domain Libraries — where
persona-policy-lilith,content-security, andaudit-platformsit - The section hub: ../V3_ARCHITECTURE.md