Lilith Metaverse · Features

Governance, Safety & Recording-Consent

A focused page within the Lilith Metaverse Features documentation. The full map and every sibling page live in the Features hub.

6sections13 minread1diagram

On this page
stateDiagram-v2 [*] --> Private Private --> ConsentRequested: recording or broadcast proposed ConsentRequested --> Recording: every required participant grants current scope ConsentRequested --> Declined: any participant refuses or cannot consent Recording --> Paused: consent changes participant joins or policy signal Paused --> Recording: consent set revalidated Recording --> Stopped: host end rights safety or incident Stopped --> Processing: governed retention redaction and provenance Processing --> Published: audience rights and safety review pass Processing --> Withheld: consent rights safety or minor policy fails Published --> TakenDown: withdrawal claim or policy decision

Consent is scoped, revocable, participant-aware, and versioned. A room-level toggle cannot silently authorize a newly joined member, a different audience, voice cloning, or later reuse.

V3 ("Lilith") is the first Oshun product where a member has a body in a room full of strangers — and three of the platform's oldest promises have to be re-answered at body resolution and in real time. Children must be protected when a 13-year-old and an adult can share a yoga commons. Harassment must have an instant, self-serve answer and an accountable operator trail, because a shove or a slur in an embodied room is gone the moment it happens unless someone captures it. And no one is recorded without a real choice, even when the "room" is a 4,096-seat stadium concert whose master capture is the artist's catalog. V3's stance is the same one it takes everywhere: it does not fork the trust spine. Embodiment is a thin, server-authoritative layer of computed decisions over V1's audit ledger, persona policy, and DSAR pipeline — the library decides, the world server and tenant services persist and enforce. This page covers the operator-and-policy side of that promise: minor-protection mode, harassment and abuse response, and the recording-consent flow, end to end. The companion that owns the at-the-body evaluators (tone, crisis, costume, persona) is Identity, Embodied Safety & Provenance Foundations; the section hub is ../V3_features.md.

What ships, honestly#

This layer scores high on the implemented-vs-spec axis because its hard parts are pure decision logic, not art or engine plugins. Two real TypeScript modules carry it, each backed by an automation suite.

  • The in-world governance engine is real, computed code. The minor-protection defaults, the point-at-avatar reporting pipeline with its 60-second replay evidence buffer, the operator-review SLA dashboard, the progressive-sanction state machine, and the minor-cohort background-check gate are all implemented as pure functions in @oshun/tenant-lilith-commons (libs/v3/lilith-commons/src/index.ts). Each capability is declared in the package descriptor with an operational metric (in-world-reporting, operator-review-sla, progressive-sanctions, minor-protection-defaults, minor-operator-alerts, minor-instructor-background-checks) and exercised by src/__tests__/index.spec.ts.
  • The recording-consent policy is real, computed code. libs/v3/lilith-identity-bridge/src/recording-consent.ts resolves every class and concert capture decision — full/observer/decline, the free privacy seat, the front-row visibility exception, the publication gate, DSAR coverage, and post-publication withdrawal — as discriminated-union functions, tested by src/__tests__/recording-consent.spec.ts.
  • The evidence trail is the genuine V1 audit platform. Every decision below publishes a canonical event (v3.lilith.in_world_report.submitted, v3.lilith.progressive_sanction.transitioned, recording_consent.*, …) into V1's @oshun/audit-platform — the same hash-chained, tamper-evident ledger V1 ships, with investigation export and retention tooling. V3 produces evidence; Oshun retains it.

Three honest qualifications. First, these libraries are pure decision kernels: no database, no socket. The report-submission function returns a typed operator-queue entry and an audit event; the world server is what actually files the report and the tenant service is what runs the 30-minute mute clock. Second, two spec-level product behaviors in V3features.md are not in this code and are labeled as such below: the one-tap "step back" (personal-space expansion + per-avatar self-mute) and the automatic "report-and-remove → quiet cell" routing are documented UX flows; what is _coded is the report → evidence → operator-queue pipeline and the operator-applied mute sanction level. (The solo-quiet-cell venue itself is a real Commons capability — privacyMode: 'solo-quiet-cell' — it just isn't auto-triggered from a report here.) Third, the platform-level trust-safety domains @themis and @kuanyin are not imported by V3's in-world governance: those operate at the V1/V2 layer (e.g. @v2/themis-privacy-dsr-routing joins @themis/privacy for data-subject requests, per V2 Security, Compliance & Sister-Monorepo Integration). V3 reuses V1's spine instead. The one real Themis touchpoint for V3 is rights adjudication in saraswati-stage/themis-rights-adjudication.ts, which belongs to Commerce, Rights & Takedown, not to in-world moderation.

Minor-protection mode#

V3 admits minors aged 13+, with realm-level age gates (Tara and Commons admit 13+; Saraswati Stage is 16+ at the realm boundary). The protection that travels with a minor account is enforced as computed defaults that cannot be toggled off, plus two structural gates around them.

Defaults that fail closed — and prove they can't be bypassed#

evaluateV3MinorProtectionDefaults treats any account under V3_MINOR_PROTECTION_ADULT_AGE_YEARS (18) as protected and resolves four locked surfaces (V3_MINOR_PROTECTION_LOCKED_SURFACES): voice-chat → off, presence-outside-cohort → hidden, signed-edition-purchase → blocked, and remix-licensing → blocked. Presence is the nuanced one: a minor's "online in Lilith" presence is visible only to themselves, an operator, or a viewer who shares a cohort (hasCohortOverlap) — a non-cohort stranger sees nothing. The function does not merely set these states; it derives a bypassProofPassed flag that is true only when every requested bypass was denied. runV3MinorProtectionThirteenYearOldBypassFixture drives exactly the adversarial case — a 13-year-old (V3_MINOR_PROTECTION_TEST_ACCOUNT_AGE_YEARS) who requests voice chat on, presence exposed, purchases unlocked, and remix licensing enabled, observed by a non-cohort viewer — and asserts all four locks hold. The capability's operational metric is literally minor-protection:13yo-locked-no-bypass. This is a fail-closed default a child cannot click their way out of, not a settings page with a recommended toggle.

Any flagged minor interaction pages an operator within 30 seconds#

createV3MinorFlaggedInteractionOperatorAlert is deliberately one-sided: it returns null for an adult-only flag, but for any interaction with at least one participant under 18 it emits a P0-minor-safety alert to the v3-lilith-minor-safety-alerts queue, console-visible, with the minor avatar/ account ids attached and an audit event v3.lilith.minor_flagged_interaction.operator_alerted. The delivery SLA is a hard 30 seconds (V3_MINOR_INTERACTION_OPERATOR_ALERT_SLA_MS = 30_000), and deliveredWithinSla is computed against it. runV3MinorFlaggedInteractionOperatorAlertFixture asserts that adult-only flags are ignored, every minor flag produces a console-visible alert, and every alert lands inside the 30-second window — so a flagged minor interaction can never sink quietly into the normal queue.

The background-check gate runs at scheduling time, not at the door#

The strongest minor protection is the one a child never sees, because it fires before the room exists. evaluateV3MinorCohortClassScheduling blocks an adult instructor from being scheduled against a minor cohort unless their background check is cleared and valid through at least V3_MINOR_COHORT_BACKGROUND_CHECK_MIN_VALIDITY_MS (24 h) past the scheduled start. Every other status — missing, pending, failed, expired — produces a blocked decision with a precise reason (minor-cohort-background-check-missing, …-not-cleared, …-expired) and an audit event. runV3MinorCohortBackgroundCheckEnforcementFixture proves all four failure modes block, a cleared instructor is allowed, and an adult-only cohort does not require the check (background-check-not-required) — so a non-cleared adult never reaches a room with minors in the first place. Minors in recordings are handled by the recording-consent flow below: observer-by-default for classes, an auto-assigned, un-disable-able privacy seat for concerts.

Harassment and abuse response#

Harassment in an embodied room is ephemeral — the durable artifact is whatever the platform chooses to keep. V3's answer pairs an immediate report with a 60-second replay buffer so the operator sees what happened, routes it through a measured SLA, and escalates repeat offenders through an audited, appealable sanction ladder.

Point-at-avatar reporting, built as a short interaction#

The report is a few seconds of pointing, not a form you leave the world to fill out. createV3InWorldReportDraftpointV3InWorldReportAtAvatarselectV3InWorldReportCategory advance a draft through target → category → comment → submitted, and renderV3InWorldReportUiModel drives the in-world panel (category options unlock only once an avatar is targeted). The six categories (V3_IN_WORLD_REPORT_CATEGORIES) are harassment, impersonation, unsafe-conduct, voice-abuse, minor-safety, and other — and minor-safety is special: submitV3InWorldReport stamps it P0-immediate on the operator queue while everything else is P1-same-day.

The 60-second evidence buffer, and why voice transcripts stay ephemeral#

A report is only as good as its evidence. validateV3InWorldReportReplayBuffer requires a full 60-second window (V3_IN_WORLD_REPORT_REPLAY_WINDOW_MS) of both voice and target-avatar motion coverage, and submitV3InWorldReport throws if the buffer is incomplete — the report cannot be filed on a partial record. The submission's evidenceKinds are ['voice-replay-buffer', 'avatar-motion-replay-buffer'], and every object is written under a tenant-resident partition (tenant:<tenantId>:<REGION>:safety-reports:<reportId>) so evidence never leaves the user's residency zone.

The privacy design here is the interesting part. Voice transcript is normally ephemeral: createV3VoiceTranscriptRollingBuffer keeps only the trailing 60 seconds of the current session and sets durablePersistence: 'none'. Transcript becomes durable only when attachV3VoiceTranscriptBufferToReport binds it to a specific report (persistenceScope: 'attached-report-only'). auditV3Voice TranscriptRetention then proves the invariant, flagging unattached-voice-content-persisted, voice-content-beyond-60s-buffer, or window drift, and passed is true only with zero violations. In plain terms: the platform keeps a rolling buffer to make reports possible, but it cannot retain your voice beyond 60 seconds unless you filed a report about it — the evidence trail and the privacy ceiling are the same mechanism.

The operator review SLA is a release gate, not an aspiration#

Reports land on v3-lilith-safety-report-review, and evaluateV3OperatorReviewSlaDashboard scores every review against a 30-minute SLA during programmed hours and a 2-hour SLA off-hours (V3_OPERATOR_REVIEW_PROGRAMMED_HOURS_SLA_MS / ..._OFF_HOURS_SLA_MS). It buckets events into daily windows and exposes releaseGateGreen — true only when the most recent 7 consecutive UTC days each clear 95% compliance (V3_OPERATOR_REVIEW_SLA_MIN_COMPLIANCE = 0.95, ..._CONSECUTIVE_DAYS = 7). The gate is strict on both axes: it checks the days are genuinely consecutive (areConsecutiveUtcDays) and the fixture refuses fewer than 20 reviews/day, so a green light means a real, sustained queue, not one quiet afternoon. This is the follow-the-sun staffing promise made measurable.

Progressive sanctions, every step audited and appealable#

Repeat offenders escalate through a four-step ladder (V3_PROGRESSIVE_SANCTION_LEVELS): warning → mute → realm-ban → account-ban. advanceV3ProgressiveSanctionState is the transition function — a mute stamps muteUntilMs 30 minutes out (V3_PROGRESSIVE_SANCTION_MUTE_DURATION_MS), a realm-ban/account-ban flips the corresponding flag, and every transition carries both an appeal route to v3-lilith-appeals-review (7-day window) and an audit event v3.lilith.progressive_sanction.transitioned, appended to the state's transitions and auditLog. runV3ProgressiveSanctionsIntegrationTest drives the full sequence and passes only when the final level is account-ban, the exercised order equals the canonical ladder, all transitions are audit-logged, and all appeals are routed — so "recorded and appealable" is a coded invariant, not a policy paragraph. The operator-applied mute here is distinct from the self-serve, in-the-moment controls below.

Self-serve "step back" and the quiet cell — honestly labeled#

V3features.md describes two immediate, self-serve controls: a one-tap "step back" that expands the target's personal-space radius and mutes the chosen avatar with no operator in the loop, and a one-tap "report and remove" that files the report _and routes the reporter out into a quiet cell. These are real product commitments, but in the libraries on this page they are spec-level: lilith-commons implements the report draft → evidence → submit → operator-queue pipeline and the operator-side sanction ladder, while the personal-space expansion, the per-avatar self-mute, and the automatic reporter-to-quiet-cell hop are world-server behaviors not present in this module. The destination is real — the solo-quiet-cell venue is a coded Commons capability (privacyMode: 'solo-quiet-cell', reflection-scope-bound) — but the report-triggered routing into it is documented, not yet computed here. Crisis routing (a non-dismissible in-world soft prompt, a V1 crisis-pipeline handoff, and an on-call page, gated at recall ≥ 0.95 / FPR ≤ 0.02) lives in @oshun/lilith-body-policy and is detailed on Identity, Embodied Safety & Provenance Foundations.

Class and concert capture have different scales and customs, so they use two different consent models — but both resolve to a concrete avatar/voice/chat treatment, both audit into @oshun/audit-platform, and both route DSAR and withdrawal through the same V1 pipeline. The whole flow is real code in recording-consent.ts.

resolveV3ClassRecordingConsent maps a participant's choice to a treatment. Consent in fullvisible / master-mix / included. Observer modegeneric-silhouette / excluded-from-master-mix / redacted, stamped redactionStatus: 'observer-redaction'. Decline and leave → routed to the lobby (route: 'lobby') with the ticket retained and nothing recorded. The load-bearing branch is the minor one: a minor choosing full triggers guardianConfirmationRequired, and absent a guardianConfirmedAtIso the decision downgrades to observer automatically rather than recording the child in the master mix — fail-closed, by computation, not by reviewer diligence. A mid-class change of heart is honored by resolveV3ClassMidSessionOptOut, which downgrades to observer and sets retroactiveFromMs to the opt-out instant, so the recording is redacted from that point forward.

Concert recording — blanket terms with a free, un-removable privacy seat#

Per-attendee dialogs at 4,096 seats are impractical, so concerts use blanket ticket-terms consent plus a non-recorded option. resolveV3ConcertTicketRecording throws if ticketTermsAffirmed is false — you cannot hold a concert ticket without acknowledging the recording. From there it branches by tier: a minor is auto-assigned a privacy-seat with privacySeatLocked: true (the toggle cannot be turned off); a crowd-band LL-HLS spectator is spectator-aggregate-only (not in the master recording, chat counted only in aggregate); a front-256 named seat throws unless the buyer both affirms full visibility and was offered an alternate tier, and throws again if they try to request a privacy seat (front-row is inherently visible); any other attendee may opt into a privacy seat. Crucially, privacySeatCostDeltaCents is the literal type 0 — privacy is free by construction. Two server-enforced guards back this: validateV3AudienceCamCue refuses to publish any cue whose targetSection is privacy (the audience camera can never sweep the privacy section), and resolveV3ConcertMidShowPrivacySwitch lets an attendee switch mid-show, excluding them from audience-cam sweeps thereafter and forcing retroactiveRedaction with an operator review gate.

Publication gate, DSAR, and post-publication withdrawal#

Consent is enforced again at the moment of release. evaluateV3RecordingPublicationGate sets publishAllowed only when the consent ledger is valid, the privacy-seat ledger is valid, and redaction has actually been applied — otherwise it returns precise blockedReasons (consent-ledger-invalid, privacy-seat-ledger-invalid, redaction-not-applied). DSAR coverage is a gate, not best-effort: buildV3RecordingDsarCoverage throws if the export is missing the consent ledger, the privacy-seat decisions, or the list of recordings the user appears in — the three exportSections are all required. And consent is revocable after the fact: resolveV3PostPublicationWithdrawal returns rerenderRequired, redactionReapplied, and v1TakedownCascade, all true, with a 48-hour deadline — a withdrawal forces a re-render, re-redaction, and a hand-off into the V1 takedown pipeline. "Published" is never the end of the consent story.

How it connects#

This page is the operator-and-policy face of a trust foundation owned elsewhere. The at-the-body evaluators it leans on — tone scoring, the measured crisis gate, costume rules, avatar-swap impersonation blocking, and AI-persona enforcement — are Identity, Embodied Safety & Provenance Foundations, and the rights side of a recording — the Isis provenance bundle, the C2PA signature, and the Themis 24-hour adjudication a takedown rides on — is Commerce, Rights & Takedown. The internal mechanics this page summarizes (the rolling-window math, the crisis thresholds, the consent-ledger shape, and the audit hash-chain) are dissected in Persona Policy, Provenance & Rights (architecture). The honest line throughout: the minor-protection defaults, the reporting and evidence pipeline, the SLA and sanction gates, and the recording-consent policy are real, computed, and tested; the personal-space "step back," the report-triggered quiet-cell routing, and the operator-console UI are the runtime and surfaces these decisions drive.