@ttt-productions/ttt-core 0.78.21 → 0.78.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants/admin-labels.d.ts +1 -1
- package/dist/constants/admin-labels.js +2 -2
- package/dist/constants/admin-labels.js.map +1 -1
- package/dist/constants/center-stage-rooms.js +1 -1
- package/dist/constants/center-stage-rooms.js.map +1 -1
- package/dist/constants/company-mascots.js +1 -1
- package/dist/constants/company-mascots.js.map +1 -1
- package/dist/constants/publish-attestations.js +1 -1
- package/dist/constants/publish-attestations.js.map +1 -1
- package/dist/constants/safety-confirmation-phrases.js +1 -1
- package/dist/constants/safety-confirmation-phrases.js.map +1 -1
- package/dist/doc-schemas/account-deletion.js +1 -1
- package/dist/doc-schemas/account-deletion.js.map +1 -1
- package/dist/doc-schemas/registry.js +1 -1
- package/dist/doc-schemas/registry.js.map +1 -1
- package/dist/doc-schemas/safety/age.js +1 -1
- package/dist/doc-schemas/safety/age.js.map +1 -1
- package/dist/doc-schemas/safety/evidence.js +1 -1
- package/dist/doc-schemas/safety/evidence.js.map +1 -1
- package/dist/doc-schemas/safety/foundation.d.ts +3 -3
- package/dist/doc-schemas/safety/foundation.d.ts.map +1 -1
- package/dist/doc-schemas/safety/foundation.js +3 -3
- package/dist/doc-schemas/safety/foundation.js.map +1 -1
- package/dist/doc-schemas/square-announcement-jobs.d.ts +1 -1
- package/dist/doc-schemas/square-announcement-jobs.js +2 -2
- package/dist/doc-schemas/square-announcement-jobs.js.map +1 -1
- package/dist/media/target-info.js +1 -1
- package/dist/media/target-info.js.map +1 -1
- package/dist/paths/collections.js +2 -2
- package/dist/paths/collections.js.map +1 -1
- package/dist/paths/path-builders.js +1 -1
- package/dist/paths/path-builders.js.map +1 -1
- package/dist/paths/related-ids.js +1 -1
- package/dist/paths/related-ids.js.map +1 -1
- package/dist/safety/active-safety-case-alert.js +1 -1
- package/dist/safety/active-safety-case-alert.js.map +1 -1
- package/dist/safety/ncii-intake-derivations.js +1 -1
- package/dist/safety/ncii-intake-derivations.js.map +1 -1
- package/dist/safety/resource-keys.js +1 -1
- package/dist/safety/resource-keys.js.map +1 -1
- package/dist/schemas/chat.js +1 -1
- package/dist/schemas/chat.js.map +1 -1
- package/dist/schemas/craft-skills.js +1 -1
- package/dist/schemas/craft-skills.js.map +1 -1
- package/dist/schemas/hall-library.js +1 -1
- package/dist/schemas/hall-library.js.map +1 -1
- package/dist/schemas/notification.js +1 -1
- package/dist/schemas/notification.js.map +1 -1
- package/dist/schemas/safety.d.ts +1 -1
- package/dist/schemas/safety.js +1 -1
- package/dist/schemas/safety.js.map +1 -1
- package/dist/types/admin-ops.d.ts +1 -1
- package/dist/types/admin-ops.d.ts.map +1 -1
- package/dist/types/admin-ops.js +1 -1
- package/dist/types/admin-ops.js.map +1 -1
- package/dist/types/admin-users.js +1 -1
- package/dist/types/admin-users.js.map +1 -1
- package/dist/types/social.d.ts +1 -1
- package/dist/types/social.js.map +1 -1
- package/dist/upload-variables/create-admin-audition-variables.js +1 -1
- package/dist/upload-variables/create-admin-audition-variables.js.map +1 -1
- package/dist/upload-variables/create-work-project-audition-variables.js +1 -1
- package/dist/upload-variables/create-work-project-audition-variables.js.map +1 -1
- package/package.json +1 -1
|
@@ -22,7 +22,7 @@ export interface UserFacingReasonOption {
|
|
|
22
22
|
description: string;
|
|
23
23
|
}
|
|
24
24
|
/** User-facing reason picklist for the guided case-resolution flow — the affected user sees the
|
|
25
|
-
* label for any user-affecting action. Canonical home (
|
|
25
|
+
* label for any user-affecting action. Canonical home (ARCH-102): the codes ARE this list's own
|
|
26
26
|
* enumeration, so every client (web, phone, TV, admin app) renders the same options + labels by
|
|
27
27
|
* importing from here. Final user-/legal-facing wording is subject to lawyer review; these are
|
|
28
28
|
* functional defaults. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// ADMIN-SURFACE DISPLAY LABELS — the ONE home for business display copy keyed
|
|
3
|
-
// by canonical ttt-core enums (
|
|
3
|
+
// by canonical ttt-core enums (ARCH-102, extended 2026-07-13). Consolidated from
|
|
4
4
|
// the former component-local maps in ttt-prod (admin-user-management-view,
|
|
5
5
|
// admin-announcements-view, guided-resolution-flow). Any client (web, phone,
|
|
6
6
|
// TV, admin app) renders the same labels by importing these.
|
|
@@ -55,7 +55,7 @@ export const REPORT_DISPOSITION_OPTIONS = [
|
|
|
55
55
|
},
|
|
56
56
|
];
|
|
57
57
|
/** User-facing reason picklist for the guided case-resolution flow — the affected user sees the
|
|
58
|
-
* label for any user-affecting action. Canonical home (
|
|
58
|
+
* label for any user-affecting action. Canonical home (ARCH-102): the codes ARE this list's own
|
|
59
59
|
* enumeration, so every client (web, phone, TV, admin app) renders the same options + labels by
|
|
60
60
|
* importing from here. Final user-/legal-facing wording is subject to lawyer review; these are
|
|
61
61
|
* functional defaults. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-labels.js","sourceRoot":"","sources":["../../src/constants/admin-labels.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"admin-labels.js","sourceRoot":"","sources":["../../src/constants/admin-labels.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// ADMIN-SURFACE DISPLAY LABELS — the ONE home for business display copy keyed\n// by canonical ttt-core enums (ARCH-102, extended 2026-07-13). Consolidated from\n// the former component-local maps in ttt-prod (admin-user-management-view,\n// admin-announcements-view, guided-resolution-flow). Any client (web, phone,\n// TV, admin app) renders the same labels by importing these.\n// ============================================================================\n\nimport type { UserAccountStatus } from '../doc-schemas/user.js';\nimport type { ReportDisposition } from '../doc-schemas/safety/foundation.js';\nimport type { BroadcastAudienceSelector } from '../schemas/notification.js';\nimport type { DeadLetterCollection } from '../schemas/admin.js';\n\n/** Moderation status labels (user-management view, status badges). */\nexport const USER_ACCOUNT_STATUS_LABELS: Record<UserAccountStatus, string> = {\n active: 'Active',\n suspended: 'Suspended',\n banned: 'Banned',\n};\n\n/** Broadcast audience selector labels (announcement composer). */\nexport const BROADCAST_AUDIENCE_KIND_LABELS: Record<BroadcastAudienceSelector['kind'], string> = {\n allActiveUsers: 'All active users',\n allArtisans: 'All artisan creators',\n explicitUids: 'Specific users (paste uids)',\n workMembers: \"A Work's guild members\",\n realmMembers: \"A Realm's members\",\n};\n\n/** Human labels for the dead-letter replay ledgers (Ops Repairs dead-letter table). */\nexport const DEAD_LETTER_COLLECTION_LABELS: Record<DeadLetterCollection, string> = {\n chatSyncEvents: 'Chat sync event',\n chatAdminActionCommands: 'Chat moderation command',\n notificationDeliveries: 'Notification delivery',\n chatMessageOutbox: 'Chat message publish',\n squareAnnouncementJobs: 'Square announcement',\n chatSyncFanoutJobs: 'Chat access fanout',\n mediaAssets: 'Media authority sync',\n quarantineSagaJobs: 'Quarantine saga',\n nciiRemovalJobs: 'NCII removal',\n safetyEvidenceJobs: 'Safety evidence job',\n accountActionCommands: 'Account safety action',\n activeReportGroups: 'Report edge sync',\n hallSubItemEdgeSync: 'Hall sub-item edge sync',\n};\n\n/** Operator-settable report dispositions with their console copy. 'undetermined' is the\n * initial state, never a settable target, so it carries no option entry. */\nexport const REPORT_DISPOSITION_OPTIONS: readonly {\n value: Exclude<ReportDisposition, 'undetermined'>;\n label: string;\n description: string;\n}[] = [\n {\n value: 'reportRequired',\n label: 'Report required (NCMEC)',\n description:\n 'Apparent CSAM — a report is legally required. Establishes actual knowledge + arms the clock.',\n },\n {\n value: 'notRequired',\n label: 'No report required',\n description: 'No reporting obligation ever arose. Disallowed once there is a validated match.',\n },\n {\n value: 'correctedNoApparentViolation',\n label: 'False positive — correct it',\n description: 'There was a triggering signal but on review it is a false positive.',\n },\n];\n\n/** One user-facing reason option (shown to the affected user for any user-affecting action). */\nexport interface UserFacingReasonOption {\n code: string;\n label: string;\n description: string;\n}\n\n/** User-facing reason picklist for the guided case-resolution flow — the affected user sees the\n * label for any user-affecting action. Canonical home (ARCH-102): the codes ARE this list's own\n * enumeration, so every client (web, phone, TV, admin app) renders the same options + labels by\n * importing from here. Final user-/legal-facing wording is subject to lawyer review; these are\n * functional defaults. */\nexport const USER_FACING_REASON_OPTIONS: readonly UserFacingReasonOption[] = [\n { code: 'harassment', label: 'Harassment or bullying', description: 'Targeted abuse, threats, or sustained harassment of a person.' },\n { code: 'hate', label: 'Hate speech', description: 'Attacks on people based on a protected characteristic.' },\n { code: 'adult-content', label: 'Explicit / adult content', description: 'Sexual or graphic content not allowed on the platform.' },\n { code: 'violence', label: 'Violence or threats', description: 'Threats of violence, or content glorifying or inciting it.' },\n { code: 'spam', label: 'Spam or scam', description: 'Unsolicited bulk content, deceptive links, or fraud.' },\n { code: 'impersonation', label: 'Impersonation', description: 'Pretending to be another person, brand, or entity.' },\n { code: 'ip', label: 'Intellectual property', description: 'Use of someone else’s work without the right to do so.' },\n { code: 'nonconsensual', label: 'Nonconsensual intimate imagery', description: 'Intimate or sexual imagery shared without the subject’s consent.' },\n { code: 'safety', label: 'Safety violation', description: 'A serious safety violation handled under our safety policies.' },\n { code: 'other', label: 'Other (explain)', description: 'A policy violation not covered above — describe it in the detail box.' },\n] as const;\n\n/** The user-facing label for a reason code (undefined when the code is unknown/absent). */\nexport function userFacingReasonLabel(code: string | undefined): string | undefined {\n return USER_FACING_REASON_OPTIONS.find((o) => o.code === code)?.label;\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// CENTER STAGE ROOMS — the pure, durable definitions of the three revolving
|
|
3
|
-
// landing/registration-tour rooms (
|
|
3
|
+
// landing/registration-tour rooms (ARCH-102). Moved here VERBATIM from the app's
|
|
4
4
|
// `center-stage.tsx`. Pure data only: the emblems (`ROOM_EMBLEMS`), React
|
|
5
5
|
// components, engraving, and stage layout stay app-owned. Each room's `href` is
|
|
6
6
|
// the app route the spotlit poster navigates to.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"center-stage-rooms.js","sourceRoot":"","sources":["../../src/constants/center-stage-rooms.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,4EAA4E;AAC5E,
|
|
1
|
+
{"version":3,"file":"center-stage-rooms.js","sourceRoot":"","sources":["../../src/constants/center-stage-rooms.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AACjF,0EAA0E;AAC1E,gFAAgF;AAChF,iDAAiD;AACjD,+EAA+E;AAa/E,oFAAoF;AACpF,MAAM,CAAC,MAAM,kBAAkB,GAA+B;IAC5D;QACE,GAAG,EAAE,MAAM;QACX,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,sBAAsB;QAC5B,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,kJAAkJ;KACrJ;IACD;QACE,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,sBAAsB;QAC5B,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,4IAA4I;KAC/I;IACD;QACE,GAAG,EAAE,UAAU;QACf,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,gBAAgB;QACtB,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,wIAAwI;KAC3I;CACF,CAAC","sourcesContent":["// ============================================================================\n// CENTER STAGE ROOMS — the pure, durable definitions of the three revolving\n// landing/registration-tour rooms (ARCH-102). Moved here VERBATIM from the app's\n// `center-stage.tsx`. Pure data only: the emblems (`ROOM_EMBLEMS`), React\n// components, engraving, and stage layout stay app-owned. Each room's `href` is\n// the app route the spotlit poster navigates to.\n// ============================================================================\n\nexport type CenterStageRoomKey = 'hall' | 'square' | 'audition';\n\nexport interface CenterStageRoom {\n readonly key: CenterStageRoomKey;\n readonly name: string;\n readonly verb: string;\n readonly href: string;\n /** One-breath description shown on the audience placard (same words the tour uses). */\n readonly description: string;\n}\n\n/** The three rooms, in revolve order. Index 0 (The Hall) opens in the spotlight. */\nexport const CENTER_STAGE_ROOMS: readonly CenterStageRoom[] = [\n {\n key: 'hall',\n name: 'The Hall',\n verb: 'Watch, read & listen',\n href: '/hall-library',\n description:\n 'Home to the finished works — read original Tales, listen to Tunes, and watch Television, all made by real people and reviewed before it goes up.',\n },\n {\n key: 'square',\n name: 'The Square',\n verb: \"See what's happening\",\n href: '/square-streetz',\n description:\n 'The community feed. Post your news, follow artisans you admire, and watch the Town Crier announce what’s happening across TTT Productions.',\n },\n {\n key: 'audition',\n name: 'The Audition Stage',\n verb: 'Cast your vote',\n href: '/audition-board',\n description:\n 'Artisans post auditions for their works, and the community votes on the entries. Cast your vote — one per audition, switch it anytime.',\n },\n];\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
|
-
// THE COMPANY — canonical Green Room mascot contract + content (
|
|
2
|
+
// THE COMPANY — canonical Green Room mascot contract + content (ARCH-102).
|
|
3
3
|
//
|
|
4
4
|
// The ONE home for the pure, server-safe Company business truths (id unions,
|
|
5
5
|
// billing kinds, performance intents, selectability, roster order) AND the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"company-mascots.js","sourceRoot":"","sources":["../../src/constants/company-mascots.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// THE COMPANY — canonical Green Room mascot contract + content (Rule 36).\n//\n// The ONE home for the pure, server-safe Company business truths (id unions,\n// billing kinds, performance intents, selectability, roster order) AND the\n// DJ-approved VERBATIM character content (studies, click lines, footers,\n// companion-switch exchanges, Yorick block lines, signed-out dock lines,\n// onboarding cameos). Moved here losslessly from the app's staging modules\n// (`src/lib/company-contract` + `src/lib/company-mascots.tsx`).\n//\n// This module is pure data: NO React, NO JSX, NO Next links, NO CSS, NO SVG,\n// NO functions inside the data. Rich copy is modelled as discriminated\n// `CompanyCopySegment`s so a web renderer, a phone app, or an AI voice can each\n// present the exact approved words without importing a UI framework. The app\n// owns the puppets, rig, choreography, and the adapter that turns these\n// segments into `<p>`, `<em>`, and route-aware links.\n//\n// Canonical dialogue stays a versioned code constant here (never Firestore):\n// it is the personality source, the safe AI-unavailable fallback, and the\n// voice-regression fixture. Never reword — curly quotes/apostrophes are\n// authored exactly as they render.\n// ============================================================================\n\n// ── Contract: id unions, billing, intents, selectability ─────────────────────\n\n/** Every member of the Company, in roster order. */\nexport type CompanyCharacterId = 'bill' | 'kit' | 'yorick';\n\n/** The roster, in billing order (Bill → Kit → Yorick). */\nexport const COMPANY_CHARACTER_IDS: readonly CompanyCharacterId[] = ['bill', 'kit', 'yorick'];\n\n/** Billing tiers: the founding Player, permanent Players, and Stand-Ins\n * (Limited Engagement — never selectable as the companion). */\nexport type CompanyBillingKind = 'foundingPlayer' | 'player' | 'standIn';\n\n/** Demoable move intents — keyed by intent from day one so future event\n * performances (page-grabs, standing ovations) land as content, not code. */\nexport type CompanyPerformanceIntent = 'bow' | 'hop' | 'wave';\n\n/** The performance intents, in demo-button order. The app previously\n * hand-mirrored this union in two places; consumers derive from this array. */\nexport const COMPANY_PERFORMANCE_INTENTS: readonly CompanyPerformanceIntent[] = ['bow', 'hop', 'wave'];\n\n/** The characters a user may cast as their dock companion (never a Stand-In). */\nexport type SelectableCompanionId = 'bill' | 'kit';\n\n/** The castable dock companions, in order. */\nexport const SELECTABLE_COMPANION_IDS: readonly SelectableCompanionId[] = ['bill', 'kit'];\n\n// ── Rich-copy pure-data model ────────────────────────────────────────────────\n\n/** Semantic destinations the copy can link to. Each client maps these to its\n * own route/navigation — the package never carries an href in mascot copy. */\nexport type CompanyNavigationTarget = 'greenRoom' | 'futurePlans';\n\n/** A single run of copy. `link` carries a semantic target, not a URL. */\nexport type CompanyCopySegment =\n | { readonly kind: 'text'; readonly text: string }\n | { readonly kind: 'emphasis'; readonly text: string }\n | { readonly kind: 'link'; readonly label: string; readonly target: CompanyNavigationTarget };\n\n/** A block of copy — a paragraph or a set-aside aside. */\nexport type CompanyCopyBlockKind = 'paragraph' | 'aside';\n\nexport interface CompanyCopyBlock {\n readonly kind: CompanyCopyBlockKind;\n readonly segments: readonly CompanyCopySegment[];\n}\n\n// ── Registry shapes ──────────────────────────────────────────────────────────\n\nexport interface CompanyPerformance {\n readonly id: string;\n readonly label: string;\n readonly intent: CompanyPerformanceIntent;\n /** Community \"Choreography by\" credit — null until an audition stages it. */\n readonly creditUid: string | null;\n}\n\nexport interface CompanyMascot {\n readonly id: CompanyCharacterId;\n /** Full stage name shown on nameplates + the playbill (\"Bill the Understudy\"). */\n readonly name: string;\n /** The ironic-understatement epithet (the Company tradition). */\n readonly title: string;\n readonly billingKind: CompanyBillingKind;\n /** Billing line rendered beside the name (\"Founding Player\"). */\n readonly billingLabel: string;\n /** One-line structural descriptor (not character voice). */\n readonly shortBio: string;\n /** Playbill character study (human-written; the future AI personality source). */\n readonly characterStudy: readonly CompanyCopyBlock[];\n /** \"Role originated by\" — resolves live via the app when set. */\n readonly originatedByUid: string | null;\n /** Text shown after \"Role originated by — \" when originatedByUid is null. */\n readonly originatedByFallback: string;\n /** Whether the origination frame invites the reader (\"→ your name here?\"). */\n readonly invitesOrigination: boolean;\n /** The performances credit caption under the demo buttons. */\n readonly choreographyCaption: string;\n readonly performances: readonly CompanyPerformance[];\n /** Rotating click lines (dock companion bubble + on-stage line pop). Each\n * line is a segment run — most are a single text segment. */\n readonly lines: readonly (readonly CompanyCopySegment[])[];\n /** Dock speech-bubble footer segments. The character's short name is a\n * `greenRoom` link segment; the app renders it as a link when signed in and\n * as plain text when signed out. \"one day\" always links to `futurePlans`.\n * Absent for Stand-Ins (Yorick — never the dock companion). */\n readonly footer?: readonly CompanyCopySegment[];\n /** False for Stand-Ins (Yorick) — never storable as the dock companion. */\n readonly selectable: boolean;\n}\n\n/** Companion-switch snark exchange, keyed (in COMPANION_SWITCH_EXCHANGES) by the\n * character switched TO. Outgoing line first (the departing companion), then the\n * incoming retort. Plain strings. */\nexport interface CompanionSwitchExchange {\n readonly outgoing: { readonly id: SelectableCompanionId; readonly line: string };\n readonly incoming: { readonly id: SelectableCompanionId; readonly line: string };\n}\n\n/** Onboarding cameo lines — Company members crashing the registration tour. */\nexport interface OnboardingCameos {\n /** Kit crashes The Audition Stage step. */\n readonly kitAuditionStage: string;\n /** Yorick cameos on The Hall step. */\n readonly yorickHall: string;\n /** The send-off curtain call — all three bow. */\n readonly curtainCall: Readonly<Record<CompanyCharacterId, string>>;\n}\n\n// ── Segment construction helpers (module-private; output is pure data) ────────\n\n/** A line/footer that is a single plain-text run. */\nconst textRun = (text: string): readonly CompanyCopySegment[] => [{ kind: 'text', text }];\n\n/** A character's dock footer, built from the one verbatim sentence. The name is\n * a `greenRoom` link segment (the app renders it plain when signed out); \"one\n * day\" always links to `futurePlans`; `tail` is the character-specific close. */\nconst dockFooter = (name: string, tail: string): readonly CompanyCopySegment[] => [\n { kind: 'link', label: name, target: 'greenRoom' },\n { kind: 'text', text: ' is a basic version for now — ' },\n { kind: 'link', label: 'one day', target: 'futurePlans' },\n { kind: 'text', text: ` ${tail}` },\n];\n\nconst SHARED_PERFORMANCES: readonly CompanyPerformance[] = [\n { id: 'bow', label: 'Bow', intent: 'bow', creditUid: null },\n { id: 'hop', label: 'Hop', intent: 'hop', creditUid: null },\n { id: 'wave', label: 'Wave', intent: 'wave', creditUid: null },\n];\n\n// The dock-footer close sentences, VERBATIM (the pre-Company Bill wording; Kit's\n// from the settled spec). Curly apostrophes authored exactly as rendered.\nconst BILL_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide who helps you navigate the site. He’ll never make content, just help.';\nconst KIT_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide with this exact attitude. He’ll never make content. He does have opinions about yours.';\n\n// ── Bill the Understudy — Founding Player ────────────────────────────────────\n// The 14 approved lines are VERBATIM (incl. the italic emphasis in line 11).\nconst BILL: CompanyMascot = {\n id: 'bill',\n name: 'Bill the Understudy',\n title: 'The Understudy',\n billingKind: 'foundingPlayer',\n billingLabel: 'Founding Player',\n shortBio: \"TTT's founding player and your first guide.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'The most enthusiastic understudy in show business, and TTT Productions’ founding player. Bill has read the whole script of this town — well, skimmed it — and rehearses every day for the role of your guide to everything here. He insists the ‘Bill’ is short for William, and that he once wrote plays in a town called Stratford. We have chosen to let him believe it. Someday he’ll answer anything you ask about this place. Today, he mostly waves.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"One day I'll help you find your perfect collaborator. Today, I mostly wave.\"),\n textRun(\"I'm just an understudy for now — but someday I'll know every corner of this town.\"),\n textRun('Rehearsing my big role: your guide to everything TTT. No spoilers.'),\n textRun(\"They say one day I'll have real personalities. Plural. I'm excited too.\"),\n textRun(\"I'll never make the art — that's your job. I'll just help you find your people.\"),\n textRun(\"Every great production starts with somebody standing in the wings. That's me. Literally.\"),\n textRun(\"Someday you'll ask me anything about this place and I'll actually answer. Bold, I know.\"),\n textRun('The Town Crier gets to shout. I get to practice my bow. For now.'),\n textRun(\"I've read the whole script of this town. Well... skimmed. I'm working on it.\"),\n textRun('Big dreams for a stick figure: guide, helper, friend. In that order.'),\n [\n { kind: 'text', text: \"When the curtain rises on my real role, you'll be the first to know. You \" },\n { kind: 'emphasis', text: 'did' },\n { kind: 'text', text: ' click me first.' },\n ],\n textRun('Until my big debut, consider me the most enthusiastic understudy in show business.'),\n textRun(\"Even the greatest playwright who ever lived starts over as an understudy in a town this good. That's my story, anyway.\"),\n textRun('Four hundred years of theatre experience. My résumé? A drawing of myself.'),\n ],\n footer: dockFooter('Bill', BILL_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Kit the Stand-In — permanent Player #2, Bill's rival ─────────────────────\nconst KIT: CompanyMascot = {\n id: 'kit',\n name: 'Kit the Stand-In',\n title: 'The Stand-In',\n billingKind: 'player',\n billingLabel: 'Player',\n shortBio: \"Permanent Player #2, and Bill's rival.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'Sharp, quick, and absolutely certain he should have gone first. Kit auditioned for founding mascot, delivered the finest monologue the empty theatre had ever heard, and lost the part to a stick figure with a “trustworthy wave.” He has been gracious about it every single day since — loudly, to anyone in range. Keeps the rejection letter framed. Ask him about it. He’s dying for you to ask.',\n ),\n },\n {\n kind: 'aside',\n segments: textRun(\n 'Loosely nodding to a certain rival playwright — brilliant, theatrical, gone too soon. One day, an AI-powered guide with this exact personality: genuinely helpful, faintly insulted by the request.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Yes, I'm the Stand-In. Permanently. The irony isn't lost on me — it lives with me now.\"),\n textRun(\"I was FIRST in line at the founding audition. They went with a stick figure who 'waves well.'\"),\n textRun(\"Bill rehearses roles nobody wrote. I've already memorized them. We are not the same.\"),\n textRun(\"One day this whole town will know my name. Today it's 'the other one.' Fine.\"),\n textRun(\"I don't do warm-ups. I arrive brilliant.\"),\n textRun('Founding mascot. FOUNDING. He waved at a login page and they gave him a title.'),\n textRun('My five-year plan is center stage. My five-century plan is also center stage.'),\n textRun('History remembers a playwright who died before his rival got famous. Anyway. No reason.'),\n textRun('Click Bill for encouragement. Click me to hear the truth, beautifully delivered.'),\n textRun('I keep my rejection letter framed. Motivation is motivation.'),\n textRun(\"You clicked me first today. I rehearsed being gracious about this — give me a moment.\"),\n textRun(\"When the curtain finally rises on my lead role, act surprised. I won't.\"),\n textRun('They say I might have been a spy in a past life. I neither confirm nor deny. Mystique.'),\n textRun('The Understudy and the Stand-In on one stage. Somewhere a playwright is laughing at us both.'),\n ],\n footer: dockFooter('Kit', KIT_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Yorick the Forgettable — Stand-In · Limited Engagement ───────────────────\n// Never selectable, never the dock companion; his lines are on-stage only.\nconst YORICK: CompanyMascot = {\n id: 'yorick',\n name: 'Yorick the Forgettable',\n title: 'The Forgettable',\n billingKind: 'standIn',\n billingLabel: 'Stand-In · Limited Engagement',\n shortBio: 'A Limited Engagement Stand-In, keeping the light warm.',\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n \"A fellow of infinite jest, reduced to holding a light he isn't allowed to stand in. Yorick insists he was the funniest jester who ever lived — and unfortunately, everyone who could confirm it is unavailable for comment. He is keeping the stage warm until the role is properly cast, and he'd rather you didn't get attached. You'll forget him anyway. Everyone does. It's in the name.\",\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'no one will admit to it',\n invitesOrigination: false,\n choreographyCaption: 'Bow · Hop · Wave — borrowed from Bill, who says he can have them',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Oh! A visitor. Nobody visits the Wings. I'd know — I keep the guestbook. It's empty.\"),\n textRun(\"I used to kill at court, you know. Standing ovations. Kings weeping. ...You'll take my word for it.\"),\n textRun(\"Don't get attached. I'm told I'm temporary. The skull agrees.\"),\n textRun('Alas, poor me. I knew me well.'),\n textRun('Infinite jest, they said. INFINITE. And yet here I am, finite-ly employed.'),\n textRun(\"One day they'll cast this role properly and I'll be forgotten. Ahead of schedule, honestly.\"),\n ],\n selectable: false,\n};\n\nexport const COMPANY_MASCOTS: Readonly<Record<CompanyCharacterId, CompanyMascot>> = {\n bill: BILL,\n kit: KIT,\n yorick: YORICK,\n};\n\n/** Registry order (Bill → Kit → Yorick), reused from the roster. */\nexport const COMPANY_MASCOT_ORDER: readonly CompanyCharacterId[] = COMPANY_CHARACTER_IDS;\n\n// ── Pure helpers ─────────────────────────────────────────────────────────────\n\n/** True when `x` is a canonical Company character id. */\nexport function isCompanyCharacterId(x: unknown): x is CompanyCharacterId {\n return typeof x === 'string' && (COMPANY_CHARACTER_IDS as readonly string[]).includes(x);\n}\n\n/** True when `id` may be cast as the dock companion — driven by the mascot\n * data's `selectable` field (Yorick is false). */\nexport function isSelectableCompanion(id: CompanyCharacterId): id is SelectableCompanionId {\n return COMPANY_MASCOTS[id].selectable;\n}\n\n/** The mascot record for a character id. */\nexport function getCompanyMascot(id: CompanyCharacterId): CompanyMascot {\n return COMPANY_MASCOTS[id];\n}\n\n// ── Companion-switch snark exchanges (VERBATIM) ──────────────────────────────\n// Keyed by the character being switched TO. Outgoing line first (the departing\n// companion), then the incoming retort.\nexport const COMPANION_SWITCH_EXCHANGES: Readonly<\n Record<SelectableCompanionId, readonly CompanionSwitchExchange[]>\n> = {\n // Switching TO Kit — Bill exits, Kit enters.\n kit: [\n {\n outgoing: { id: 'bill', line: \"Kit?! ...No, it's fine. It's fine. I'll be in the wings. Rehearsing. Alone.\" },\n incoming: { id: 'kit', line: 'Finally. Someone with taste.' },\n },\n {\n outgoing: { id: 'bill', line: 'Take care of them, Kit. They click gently.' },\n incoming: { id: 'kit', line: 'I know how to be adored, Bill.' },\n },\n {\n outgoing: { id: 'bill', line: 'The understudy yields the stage. Again.' },\n incoming: { id: 'kit', line: 'And yet history will say I earned it. Because I did.' },\n },\n {\n outgoing: { id: 'bill', line: \"You'll come back. They always— they usually come back.\" },\n incoming: { id: 'kit', line: \"Don't wait up.\" },\n },\n {\n outgoing: { id: 'bill', line: 'Break a leg, Kit.' },\n incoming: { id: 'kit', line: 'I never break anything but hearts and attendance records.' },\n },\n ],\n // Switching TO Bill — Kit exits, Bill enters.\n bill: [\n {\n outgoing: { id: 'kit', line: 'Unbelievable. UNBELIEVABLE.' },\n incoming: { id: 'bill', line: \"It's good to be back! ...He'll be alright.\" },\n },\n {\n outgoing: { id: 'kit', line: \"Enjoy the waving. That's all he does, you know.\" },\n incoming: { id: 'bill', line: \"I also bow now! I've been practicing.\" },\n },\n {\n outgoing: { id: 'kit', line: 'I was BRILLIANT and you choose the stick figure with the cap.' },\n incoming: { id: 'bill', line: \"He means 'welcome back.' We're working on it.\" },\n },\n {\n outgoing: { id: 'kit', line: 'Fine. FINE. The wings have better lighting anyway.' },\n incoming: { id: 'bill', line: \"They really don't. I'd know.\" },\n },\n {\n outgoing: { id: 'kit', line: 'This is the founding audition all over again.' },\n incoming: { id: 'bill', line: \"You'll get the next one, Kit. ...Probably not. But maybe!\" },\n },\n ],\n};\n\n// ── Yorick block lines (VERBATIM) ────────────────────────────────────────────\n// Spoken by the ACTIVE companion when the user presses Yorick's cast button.\nexport const YORICK_BLOCK_LINES: Readonly<Record<SelectableCompanionId, readonly string[]>> = {\n bill: [\n \"Soft you now — he's a Stand-In! He's only keeping the light warm. Thou art stuck with me. Nay — blessed with me.\",\n \"Yorick?! He doesn't even know his blocking. Literally. He asks me where to stand.\",\n \"You can't cast Yorick — he's on a Limited Engagement. Very limited. He leaves when the real role is cast.\",\n 'Alas, poor choice — I knew him better than you do. Pick a Player.',\n ],\n kit: [\n 'The skeleton crew? No. Absolutely not. You have TWO trained professionals right here.',\n \"He doesn't even know his blocking. I've watched him bow into the curtain. Twice.\",\n \"Yorick's not staying. Don't get attached to the help.\",\n \"You'd pass over ME for the temp? ...I need to sit down. On the couch he's not allowed on.\",\n ],\n};\n\n// ── Signed-out dock lines (VERBATIM) ─────────────────────────────────────────\n// Spoken by whichever Player is on the dock when NO user is signed in — the\n// pre-login pitch.\nexport const SIGNED_OUT_DOCK_LINES: readonly string[] = [\n \"The show's inside — and it's free. No ads, just an email.\",\n \"I'd introduce you to the whole Company, but you'll need a ticket. Tickets are free.\",\n 'Everything in this town is made by real people. Come see.',\n];\n\n// ── Onboarding cameo lines (VERBATIM) ────────────────────────────────────────\nexport const ONBOARDING_CAMEOS: OnboardingCameos = {\n kitAuditionStage:\n \"The Audition Stage. Where stars are born. I was robbed here once — anyway, you'll love it.\",\n yorickHall:\n 'The Hall — every tale, tune, and show the town keeps. Four hundred years of my material, and not one shelf. Enjoy.',\n curtainCall: {\n bill: 'Break a leg out there.',\n kit: 'Try not to embarrass us.',\n yorick: \"You'll forget me. It's fine. Go.\",\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"company-mascots.js","sourceRoot":"","sources":["../../src/constants/company-mascots.ts"],"names":[],"mappings":"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","sourcesContent":["// ============================================================================\n// THE COMPANY — canonical Green Room mascot contract + content (ARCH-102).\n//\n// The ONE home for the pure, server-safe Company business truths (id unions,\n// billing kinds, performance intents, selectability, roster order) AND the\n// DJ-approved VERBATIM character content (studies, click lines, footers,\n// companion-switch exchanges, Yorick block lines, signed-out dock lines,\n// onboarding cameos). Moved here losslessly from the app's staging modules\n// (`src/lib/company-contract` + `src/lib/company-mascots.tsx`).\n//\n// This module is pure data: NO React, NO JSX, NO Next links, NO CSS, NO SVG,\n// NO functions inside the data. Rich copy is modelled as discriminated\n// `CompanyCopySegment`s so a web renderer, a phone app, or an AI voice can each\n// present the exact approved words without importing a UI framework. The app\n// owns the puppets, rig, choreography, and the adapter that turns these\n// segments into `<p>`, `<em>`, and route-aware links.\n//\n// Canonical dialogue stays a versioned code constant here (never Firestore):\n// it is the personality source, the safe AI-unavailable fallback, and the\n// voice-regression fixture. Never reword — curly quotes/apostrophes are\n// authored exactly as they render.\n// ============================================================================\n\n// ── Contract: id unions, billing, intents, selectability ─────────────────────\n\n/** Every member of the Company, in roster order. */\nexport type CompanyCharacterId = 'bill' | 'kit' | 'yorick';\n\n/** The roster, in billing order (Bill → Kit → Yorick). */\nexport const COMPANY_CHARACTER_IDS: readonly CompanyCharacterId[] = ['bill', 'kit', 'yorick'];\n\n/** Billing tiers: the founding Player, permanent Players, and Stand-Ins\n * (Limited Engagement — never selectable as the companion). */\nexport type CompanyBillingKind = 'foundingPlayer' | 'player' | 'standIn';\n\n/** Demoable move intents — keyed by intent from day one so future event\n * performances (page-grabs, standing ovations) land as content, not code. */\nexport type CompanyPerformanceIntent = 'bow' | 'hop' | 'wave';\n\n/** The performance intents, in demo-button order. The app previously\n * hand-mirrored this union in two places; consumers derive from this array. */\nexport const COMPANY_PERFORMANCE_INTENTS: readonly CompanyPerformanceIntent[] = ['bow', 'hop', 'wave'];\n\n/** The characters a user may cast as their dock companion (never a Stand-In). */\nexport type SelectableCompanionId = 'bill' | 'kit';\n\n/** The castable dock companions, in order. */\nexport const SELECTABLE_COMPANION_IDS: readonly SelectableCompanionId[] = ['bill', 'kit'];\n\n// ── Rich-copy pure-data model ────────────────────────────────────────────────\n\n/** Semantic destinations the copy can link to. Each client maps these to its\n * own route/navigation — the package never carries an href in mascot copy. */\nexport type CompanyNavigationTarget = 'greenRoom' | 'futurePlans';\n\n/** A single run of copy. `link` carries a semantic target, not a URL. */\nexport type CompanyCopySegment =\n | { readonly kind: 'text'; readonly text: string }\n | { readonly kind: 'emphasis'; readonly text: string }\n | { readonly kind: 'link'; readonly label: string; readonly target: CompanyNavigationTarget };\n\n/** A block of copy — a paragraph or a set-aside aside. */\nexport type CompanyCopyBlockKind = 'paragraph' | 'aside';\n\nexport interface CompanyCopyBlock {\n readonly kind: CompanyCopyBlockKind;\n readonly segments: readonly CompanyCopySegment[];\n}\n\n// ── Registry shapes ──────────────────────────────────────────────────────────\n\nexport interface CompanyPerformance {\n readonly id: string;\n readonly label: string;\n readonly intent: CompanyPerformanceIntent;\n /** Community \"Choreography by\" credit — null until an audition stages it. */\n readonly creditUid: string | null;\n}\n\nexport interface CompanyMascot {\n readonly id: CompanyCharacterId;\n /** Full stage name shown on nameplates + the playbill (\"Bill the Understudy\"). */\n readonly name: string;\n /** The ironic-understatement epithet (the Company tradition). */\n readonly title: string;\n readonly billingKind: CompanyBillingKind;\n /** Billing line rendered beside the name (\"Founding Player\"). */\n readonly billingLabel: string;\n /** One-line structural descriptor (not character voice). */\n readonly shortBio: string;\n /** Playbill character study (human-written; the future AI personality source). */\n readonly characterStudy: readonly CompanyCopyBlock[];\n /** \"Role originated by\" — resolves live via the app when set. */\n readonly originatedByUid: string | null;\n /** Text shown after \"Role originated by — \" when originatedByUid is null. */\n readonly originatedByFallback: string;\n /** Whether the origination frame invites the reader (\"→ your name here?\"). */\n readonly invitesOrigination: boolean;\n /** The performances credit caption under the demo buttons. */\n readonly choreographyCaption: string;\n readonly performances: readonly CompanyPerformance[];\n /** Rotating click lines (dock companion bubble + on-stage line pop). Each\n * line is a segment run — most are a single text segment. */\n readonly lines: readonly (readonly CompanyCopySegment[])[];\n /** Dock speech-bubble footer segments. The character's short name is a\n * `greenRoom` link segment; the app renders it as a link when signed in and\n * as plain text when signed out. \"one day\" always links to `futurePlans`.\n * Absent for Stand-Ins (Yorick — never the dock companion). */\n readonly footer?: readonly CompanyCopySegment[];\n /** False for Stand-Ins (Yorick) — never storable as the dock companion. */\n readonly selectable: boolean;\n}\n\n/** Companion-switch snark exchange, keyed (in COMPANION_SWITCH_EXCHANGES) by the\n * character switched TO. Outgoing line first (the departing companion), then the\n * incoming retort. Plain strings. */\nexport interface CompanionSwitchExchange {\n readonly outgoing: { readonly id: SelectableCompanionId; readonly line: string };\n readonly incoming: { readonly id: SelectableCompanionId; readonly line: string };\n}\n\n/** Onboarding cameo lines — Company members crashing the registration tour. */\nexport interface OnboardingCameos {\n /** Kit crashes The Audition Stage step. */\n readonly kitAuditionStage: string;\n /** Yorick cameos on The Hall step. */\n readonly yorickHall: string;\n /** The send-off curtain call — all three bow. */\n readonly curtainCall: Readonly<Record<CompanyCharacterId, string>>;\n}\n\n// ── Segment construction helpers (module-private; output is pure data) ────────\n\n/** A line/footer that is a single plain-text run. */\nconst textRun = (text: string): readonly CompanyCopySegment[] => [{ kind: 'text', text }];\n\n/** A character's dock footer, built from the one verbatim sentence. The name is\n * a `greenRoom` link segment (the app renders it plain when signed out); \"one\n * day\" always links to `futurePlans`; `tail` is the character-specific close. */\nconst dockFooter = (name: string, tail: string): readonly CompanyCopySegment[] => [\n { kind: 'link', label: name, target: 'greenRoom' },\n { kind: 'text', text: ' is a basic version for now — ' },\n { kind: 'link', label: 'one day', target: 'futurePlans' },\n { kind: 'text', text: ` ${tail}` },\n];\n\nconst SHARED_PERFORMANCES: readonly CompanyPerformance[] = [\n { id: 'bow', label: 'Bow', intent: 'bow', creditUid: null },\n { id: 'hop', label: 'Hop', intent: 'hop', creditUid: null },\n { id: 'wave', label: 'Wave', intent: 'wave', creditUid: null },\n];\n\n// The dock-footer close sentences, VERBATIM (the pre-Company Bill wording; Kit's\n// from the settled spec). Curly apostrophes authored exactly as rendered.\nconst BILL_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide who helps you navigate the site. He’ll never make content, just help.';\nconst KIT_FOOTER_TAIL =\n 'we hope to make him an AI-powered guide with this exact attitude. He’ll never make content. He does have opinions about yours.';\n\n// ── Bill the Understudy — Founding Player ────────────────────────────────────\n// The 14 approved lines are VERBATIM (incl. the italic emphasis in line 11).\nconst BILL: CompanyMascot = {\n id: 'bill',\n name: 'Bill the Understudy',\n title: 'The Understudy',\n billingKind: 'foundingPlayer',\n billingLabel: 'Founding Player',\n shortBio: \"TTT's founding player and your first guide.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'The most enthusiastic understudy in show business, and TTT Productions’ founding player. Bill has read the whole script of this town — well, skimmed it — and rehearses every day for the role of your guide to everything here. He insists the ‘Bill’ is short for William, and that he once wrote plays in a town called Stratford. We have chosen to let him believe it. Someday he’ll answer anything you ask about this place. Today, he mostly waves.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"One day I'll help you find your perfect collaborator. Today, I mostly wave.\"),\n textRun(\"I'm just an understudy for now — but someday I'll know every corner of this town.\"),\n textRun('Rehearsing my big role: your guide to everything TTT. No spoilers.'),\n textRun(\"They say one day I'll have real personalities. Plural. I'm excited too.\"),\n textRun(\"I'll never make the art — that's your job. I'll just help you find your people.\"),\n textRun(\"Every great production starts with somebody standing in the wings. That's me. Literally.\"),\n textRun(\"Someday you'll ask me anything about this place and I'll actually answer. Bold, I know.\"),\n textRun('The Town Crier gets to shout. I get to practice my bow. For now.'),\n textRun(\"I've read the whole script of this town. Well... skimmed. I'm working on it.\"),\n textRun('Big dreams for a stick figure: guide, helper, friend. In that order.'),\n [\n { kind: 'text', text: \"When the curtain rises on my real role, you'll be the first to know. You \" },\n { kind: 'emphasis', text: 'did' },\n { kind: 'text', text: ' click me first.' },\n ],\n textRun('Until my big debut, consider me the most enthusiastic understudy in show business.'),\n textRun(\"Even the greatest playwright who ever lived starts over as an understudy in a town this good. That's my story, anyway.\"),\n textRun('Four hundred years of theatre experience. My résumé? A drawing of myself.'),\n ],\n footer: dockFooter('Bill', BILL_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Kit the Stand-In — permanent Player #2, Bill's rival ─────────────────────\nconst KIT: CompanyMascot = {\n id: 'kit',\n name: 'Kit the Stand-In',\n title: 'The Stand-In',\n billingKind: 'player',\n billingLabel: 'Player',\n shortBio: \"Permanent Player #2, and Bill's rival.\",\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n 'Sharp, quick, and absolutely certain he should have gone first. Kit auditioned for founding mascot, delivered the finest monologue the empty theatre had ever heard, and lost the part to a stick figure with a “trustworthy wave.” He has been gracious about it every single day since — loudly, to anyone in range. Keeps the rejection letter framed. Ask him about it. He’s dying for you to ask.',\n ),\n },\n {\n kind: 'aside',\n segments: textRun(\n 'Loosely nodding to a certain rival playwright — brilliant, theatrical, gone too soon. One day, an AI-powered guide with this exact personality: genuinely helpful, faintly insulted by the request.',\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'To be determined',\n invitesOrigination: true,\n choreographyCaption: 'Choreography by — to be determined',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Yes, I'm the Stand-In. Permanently. The irony isn't lost on me — it lives with me now.\"),\n textRun(\"I was FIRST in line at the founding audition. They went with a stick figure who 'waves well.'\"),\n textRun(\"Bill rehearses roles nobody wrote. I've already memorized them. We are not the same.\"),\n textRun(\"One day this whole town will know my name. Today it's 'the other one.' Fine.\"),\n textRun(\"I don't do warm-ups. I arrive brilliant.\"),\n textRun('Founding mascot. FOUNDING. He waved at a login page and they gave him a title.'),\n textRun('My five-year plan is center stage. My five-century plan is also center stage.'),\n textRun('History remembers a playwright who died before his rival got famous. Anyway. No reason.'),\n textRun('Click Bill for encouragement. Click me to hear the truth, beautifully delivered.'),\n textRun('I keep my rejection letter framed. Motivation is motivation.'),\n textRun(\"You clicked me first today. I rehearsed being gracious about this — give me a moment.\"),\n textRun(\"When the curtain finally rises on my lead role, act surprised. I won't.\"),\n textRun('They say I might have been a spy in a past life. I neither confirm nor deny. Mystique.'),\n textRun('The Understudy and the Stand-In on one stage. Somewhere a playwright is laughing at us both.'),\n ],\n footer: dockFooter('Kit', KIT_FOOTER_TAIL),\n selectable: true,\n};\n\n// ── Yorick the Forgettable — Stand-In · Limited Engagement ───────────────────\n// Never selectable, never the dock companion; his lines are on-stage only.\nconst YORICK: CompanyMascot = {\n id: 'yorick',\n name: 'Yorick the Forgettable',\n title: 'The Forgettable',\n billingKind: 'standIn',\n billingLabel: 'Stand-In · Limited Engagement',\n shortBio: 'A Limited Engagement Stand-In, keeping the light warm.',\n characterStudy: [\n {\n kind: 'paragraph',\n segments: textRun(\n \"A fellow of infinite jest, reduced to holding a light he isn't allowed to stand in. Yorick insists he was the funniest jester who ever lived — and unfortunately, everyone who could confirm it is unavailable for comment. He is keeping the stage warm until the role is properly cast, and he'd rather you didn't get attached. You'll forget him anyway. Everyone does. It's in the name.\",\n ),\n },\n ],\n originatedByUid: null,\n originatedByFallback: 'no one will admit to it',\n invitesOrigination: false,\n choreographyCaption: 'Bow · Hop · Wave — borrowed from Bill, who says he can have them',\n performances: SHARED_PERFORMANCES,\n lines: [\n textRun(\"Oh! A visitor. Nobody visits the Wings. I'd know — I keep the guestbook. It's empty.\"),\n textRun(\"I used to kill at court, you know. Standing ovations. Kings weeping. ...You'll take my word for it.\"),\n textRun(\"Don't get attached. I'm told I'm temporary. The skull agrees.\"),\n textRun('Alas, poor me. I knew me well.'),\n textRun('Infinite jest, they said. INFINITE. And yet here I am, finite-ly employed.'),\n textRun(\"One day they'll cast this role properly and I'll be forgotten. Ahead of schedule, honestly.\"),\n ],\n selectable: false,\n};\n\nexport const COMPANY_MASCOTS: Readonly<Record<CompanyCharacterId, CompanyMascot>> = {\n bill: BILL,\n kit: KIT,\n yorick: YORICK,\n};\n\n/** Registry order (Bill → Kit → Yorick), reused from the roster. */\nexport const COMPANY_MASCOT_ORDER: readonly CompanyCharacterId[] = COMPANY_CHARACTER_IDS;\n\n// ── Pure helpers ─────────────────────────────────────────────────────────────\n\n/** True when `x` is a canonical Company character id. */\nexport function isCompanyCharacterId(x: unknown): x is CompanyCharacterId {\n return typeof x === 'string' && (COMPANY_CHARACTER_IDS as readonly string[]).includes(x);\n}\n\n/** True when `id` may be cast as the dock companion — driven by the mascot\n * data's `selectable` field (Yorick is false). */\nexport function isSelectableCompanion(id: CompanyCharacterId): id is SelectableCompanionId {\n return COMPANY_MASCOTS[id].selectable;\n}\n\n/** The mascot record for a character id. */\nexport function getCompanyMascot(id: CompanyCharacterId): CompanyMascot {\n return COMPANY_MASCOTS[id];\n}\n\n// ── Companion-switch snark exchanges (VERBATIM) ──────────────────────────────\n// Keyed by the character being switched TO. Outgoing line first (the departing\n// companion), then the incoming retort.\nexport const COMPANION_SWITCH_EXCHANGES: Readonly<\n Record<SelectableCompanionId, readonly CompanionSwitchExchange[]>\n> = {\n // Switching TO Kit — Bill exits, Kit enters.\n kit: [\n {\n outgoing: { id: 'bill', line: \"Kit?! ...No, it's fine. It's fine. I'll be in the wings. Rehearsing. Alone.\" },\n incoming: { id: 'kit', line: 'Finally. Someone with taste.' },\n },\n {\n outgoing: { id: 'bill', line: 'Take care of them, Kit. They click gently.' },\n incoming: { id: 'kit', line: 'I know how to be adored, Bill.' },\n },\n {\n outgoing: { id: 'bill', line: 'The understudy yields the stage. Again.' },\n incoming: { id: 'kit', line: 'And yet history will say I earned it. Because I did.' },\n },\n {\n outgoing: { id: 'bill', line: \"You'll come back. They always— they usually come back.\" },\n incoming: { id: 'kit', line: \"Don't wait up.\" },\n },\n {\n outgoing: { id: 'bill', line: 'Break a leg, Kit.' },\n incoming: { id: 'kit', line: 'I never break anything but hearts and attendance records.' },\n },\n ],\n // Switching TO Bill — Kit exits, Bill enters.\n bill: [\n {\n outgoing: { id: 'kit', line: 'Unbelievable. UNBELIEVABLE.' },\n incoming: { id: 'bill', line: \"It's good to be back! ...He'll be alright.\" },\n },\n {\n outgoing: { id: 'kit', line: \"Enjoy the waving. That's all he does, you know.\" },\n incoming: { id: 'bill', line: \"I also bow now! I've been practicing.\" },\n },\n {\n outgoing: { id: 'kit', line: 'I was BRILLIANT and you choose the stick figure with the cap.' },\n incoming: { id: 'bill', line: \"He means 'welcome back.' We're working on it.\" },\n },\n {\n outgoing: { id: 'kit', line: 'Fine. FINE. The wings have better lighting anyway.' },\n incoming: { id: 'bill', line: \"They really don't. I'd know.\" },\n },\n {\n outgoing: { id: 'kit', line: 'This is the founding audition all over again.' },\n incoming: { id: 'bill', line: \"You'll get the next one, Kit. ...Probably not. But maybe!\" },\n },\n ],\n};\n\n// ── Yorick block lines (VERBATIM) ────────────────────────────────────────────\n// Spoken by the ACTIVE companion when the user presses Yorick's cast button.\nexport const YORICK_BLOCK_LINES: Readonly<Record<SelectableCompanionId, readonly string[]>> = {\n bill: [\n \"Soft you now — he's a Stand-In! He's only keeping the light warm. Thou art stuck with me. Nay — blessed with me.\",\n \"Yorick?! He doesn't even know his blocking. Literally. He asks me where to stand.\",\n \"You can't cast Yorick — he's on a Limited Engagement. Very limited. He leaves when the real role is cast.\",\n 'Alas, poor choice — I knew him better than you do. Pick a Player.',\n ],\n kit: [\n 'The skeleton crew? No. Absolutely not. You have TWO trained professionals right here.',\n \"He doesn't even know his blocking. I've watched him bow into the curtain. Twice.\",\n \"Yorick's not staying. Don't get attached to the help.\",\n \"You'd pass over ME for the temp? ...I need to sit down. On the couch he's not allowed on.\",\n ],\n};\n\n// ── Signed-out dock lines (VERBATIM) ─────────────────────────────────────────\n// Spoken by whichever Player is on the dock when NO user is signed in — the\n// pre-login pitch.\nexport const SIGNED_OUT_DOCK_LINES: readonly string[] = [\n \"The show's inside — and it's free. No ads, just an email.\",\n \"I'd introduce you to the whole Company, but you'll need a ticket. Tickets are free.\",\n 'Everything in this town is made by real people. Come see.',\n];\n\n// ── Onboarding cameo lines (VERBATIM) ────────────────────────────────────────\nexport const ONBOARDING_CAMEOS: OnboardingCameos = {\n kitAuditionStage:\n \"The Audition Stage. Where stars are born. I was robbed here once — anyway, you'll love it.\",\n yorickHall:\n 'The Hall — every tale, tune, and show the town keeps. Four hundred years of my material, and not one shelf. Enjoy.',\n curtainCall: {\n bill: 'Break a leg out there.',\n kit: 'Try not to embarrass us.',\n yorick: \"You'll forget me. It's fine. Go.\",\n },\n};\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// HALL-PUBLISH ATTESTATION COPY — the ONE home for the consistent-format
|
|
3
|
-
// attestation wording (
|
|
3
|
+
// attestation wording (ARCH-102, extended 2026-07-13; consolidated from the
|
|
4
4
|
// former component-local map in ttt-prod publish-attestations.tsx). The
|
|
5
5
|
// attestation carries a Work-type-specific example using the Work's own unit
|
|
6
6
|
// word; the publish flow always knows the type.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-attestations.js","sourceRoot":"","sources":["../../src/constants/publish-attestations.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,yEAAyE;AACzE,
|
|
1
|
+
{"version":3,"file":"publish-attestations.js","sourceRoot":"","sources":["../../src/constants/publish-attestations.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,yEAAyE;AACzE,4EAA4E;AAC5E,wEAAwE;AACxE,6EAA6E;AAC7E,gDAAgD;AAChD,+EAA+E;AAI/E,MAAM,CAAC,MAAM,yBAAyB,GAAoC;IACxE,KAAK,EACH,yJAAyJ;IAC3J,KAAK,EACH,4IAA4I;IAC9I,UAAU,EACR,oJAAoJ;CACvJ,CAAC","sourcesContent":["// ============================================================================\n// HALL-PUBLISH ATTESTATION COPY — the ONE home for the consistent-format\n// attestation wording (ARCH-102, extended 2026-07-13; consolidated from the\n// former component-local map in ttt-prod publish-attestations.tsx). The\n// attestation carries a Work-type-specific example using the Work's own unit\n// word; the publish flow always knows the type.\n// ============================================================================\n\nimport type { WorkProjectType } from '../types/content.js';\n\nexport const CONSISTENT_FORMAT_WORDING: Record<WorkProjectType, string> = {\n Tales:\n 'All items in this Work are the same kind of thing — a consistent format throughout. If chapter 1 is a short story, then all chapters are short stories.',\n Tunes:\n 'All items in this Work are the same kind of thing — a consistent format throughout. If track 1 is a podcast, then all tracks are podcasts.',\n Television:\n 'All items in this Work are the same kind of thing — a consistent format throughout. If episode 1 is a clip show, then all episodes are clip shows.',\n};\n"]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// attestations that gate the highest-risk operator/admin safety callables (standing in
|
|
3
3
|
// for the passkey two-step until [H-17]).
|
|
4
4
|
//
|
|
5
|
-
//
|
|
5
|
+
// ARCH-102: each phrase is ONE named declaration here, and every enforcement point DERIVES
|
|
6
6
|
// from it — the ttt-core callable input schema (`z.literal(PHRASE)`), the frontend typed-
|
|
7
7
|
// confirmation gate, and the frontend mutation payload all import the same const. The
|
|
8
8
|
// operator must type the exact string, and the backend `z.literal` rejects anything else,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safety-confirmation-phrases.js","sourceRoot":"","sources":["../../src/constants/safety-confirmation-phrases.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,uFAAuF;AACvF,0CAA0C;AAC1C,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"safety-confirmation-phrases.js","sourceRoot":"","sources":["../../src/constants/safety-confirmation-phrases.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,uFAAuF;AACvF,0CAA0C;AAC1C,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,sFAAsF;AACtF,0FAA0F;AAC1F,sFAAsF;AACtF,yFAAyF;AACzF,yFAAyF;AACzF,EAAE;AACF,0FAA0F;AAC1F,4EAA4E;AAE5E,uFAAuF;AACvF,MAAM,CAAC,MAAM,2BAA2B,GAAG,gCAAgC,CAAC;AAE5E,uEAAuE;AACvE,MAAM,CAAC,MAAM,+BAA+B,GAAG,sCAAsC,CAAC;AAEtF,yFAAyF;AACzF,MAAM,CAAC,MAAM,kCAAkC,GAAG,+BAA+B,CAAC;AAElF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,iCAAiC,GAAG,4CAA4C,CAAC;AAE9F,6EAA6E;AAC7E,MAAM,CAAC,MAAM,sCAAsC,GACjD,6DAA6D,CAAC;AAEhE,oEAAoE;AACpE,MAAM,CAAC,MAAM,iCAAiC,GAAG,qDAAqD,CAAC;AAEvG,uFAAuF;AACvF,MAAM,CAAC,MAAM,oCAAoC,GAAG,kDAAkD,CAAC;AAEvG,2FAA2F;AAC3F,MAAM,CAAC,MAAM,kCAAkC,GAAG,+CAA+C,CAAC;AAElG,oFAAoF;AACpF,MAAM,CAAC,MAAM,wCAAwC,GAAG,4CAA4C,CAAC","sourcesContent":["// Trust & Safety typed-confirmation phrases — the interim explicit typed-confirmation\n// attestations that gate the highest-risk operator/admin safety callables (standing in\n// for the passkey two-step until [H-17]).\n//\n// ARCH-102: each phrase is ONE named declaration here, and every enforcement point DERIVES\n// from it — the ttt-core callable input schema (`z.literal(PHRASE)`), the frontend typed-\n// confirmation gate, and the frontend mutation payload all import the same const. The\n// operator must type the exact string, and the backend `z.literal` rejects anything else,\n// so the two sides can never drift only if they read from the same declaration. A raw\n// re-quote of any of these phrases at an enforcement point is drift by definition and is\n// caught by the definition-redeclaration guard (this file is each phrase's owner there).\n//\n// Declared as plain string consts (NOT widened to `string`), so `z.literal(PHRASE)` keeps\n// the exact-literal schema and `z.infer` narrows to the precise wire value.\n\n/** `commandSafetyCaseActions` / close-out — the batched safety-case staged actions. */\nexport const SAFETY_ACTIONS_CONFIRMATION = 'I confirm these safety actions';\n\n/** `reopenSafetyCase` — reopen a terminal child-safety / NCII case. */\nexport const SAFETY_CASE_REOPEN_CONFIRMATION = 'I confirm reopening this safety case';\n\n/** `commandAccountAction` — apply a per-account safety action on a child-safety case. */\nexport const SAFETY_ACCOUNT_ACTION_CONFIRMATION = 'I confirm this account action';\n\n/** `recordNcmecPortalReceiptArtifact` — register the NCMEC manual-portal receipt artifact. */\nexport const NCMEC_PORTAL_RECEIPT_CONFIRMATION = 'I confirm this is the NCMEC portal receipt';\n\n/** `markNcmecPortalComplete` — mark the NCMEC manual-portal report filed. */\nexport const NCMEC_MANUAL_PORTAL_FILED_CONFIRMATION =\n 'I confirm this NCMEC report was filed via the manual portal';\n\n/** `revealCaseEvidence` — metadata→evidence reveal under reauth. */\nexport const REVEAL_CASE_EVIDENCE_CONFIRMATION = 'I confirm I am revealing case evidence under reauth';\n\n/** `recordNcmecPortalCorrection` — record an NCMEC manual-portal correction filing. */\nexport const NCMEC_PORTAL_CORRECTION_CONFIRMATION = 'I confirm this NCMEC portal correction was filed';\n\n/** `decideTakeItDownValidity` — the operator validity ruling on a TAKE IT DOWN request. */\nexport const TAKE_IT_DOWN_VALIDITY_CONFIRMATION = 'I confirm this TAKE IT DOWN validity decision';\n\n/** `setReportDisposition` — the legal reporting disposition on a protected case. */\nexport const LEGAL_REPORTING_DISPOSITION_CONFIRMATION = 'I confirm this legal reporting disposition';\n"]}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
// erasure (revoking the epoch) before committing a hold against a leased account.
|
|
25
25
|
// A revoked epoch makes every still-running destructive step a no-op. The lease
|
|
26
26
|
// lives HERE — not a parallel safety-only deletion subsystem — so the one shared
|
|
27
|
-
// hold/destructive contract owns the fence (
|
|
27
|
+
// hold/destructive contract owns the fence (engineering-rules ARCH-001).
|
|
28
28
|
import { z } from 'zod';
|
|
29
29
|
/** Lifecycle of an account-deletion request. */
|
|
30
30
|
export const AccountDeletionRequestStatusSchema = z.enum([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account-deletion.js","sourceRoot":"","sources":["../../src/doc-schemas/account-deletion.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,EAAE;AACF,6EAA6E;AAC7E,gFAAgF;AAChF,iFAAiF;AACjF,6EAA6E;AAC7E,mEAAmE;AACnE,iFAAiF;AACjF,qEAAqE;AACrE,iFAAiF;AACjF,iFAAiF;AACjF,kFAAkF;AAClF,6CAA6C;AAC7C,EAAE;AACF,gFAAgF;AAChF,8DAA8D;AAC9D,EAAE;AACF,+EAA+E;AAC/E,iFAAiF;AACjF,+EAA+E;AAC/E,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,kFAAkF;AAClF,gFAAgF;AAChF,iFAAiF;AACjF
|
|
1
|
+
{"version":3,"file":"account-deletion.js","sourceRoot":"","sources":["../../src/doc-schemas/account-deletion.ts"],"names":[],"mappings":"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","sourcesContent":["// Account-deletion / GDPR-erasure request SCHEMA — `accountDeletionRequests/{uid}`.\n//\n// N3 data-deletion flow. A user clicks \"delete account\" on their profile → a\n// request doc is created (one per user, doc id = uid, create-if-absent) and the\n// account is immediately deactivated/locked out. The request runs a 30-day grace\n// window (logging back in CANCELS it). After the window, the scheduled scrub\n// worker checks for any BLOCKING safety hold over the user's data:\n// - no hold → anonymize-in-place (scrub PII, release reserved name, anonymize\n// chat history, tombstone memberships) → `completed`.\n// - hold → `parkedOnHold` (re-checked periodically): resumes + `completed`\n// once cleared, or → `superseded` if it becomes a ban-for-cause /\n// evidence-preservation outcome (the erasure is overridden and the\n// data retained as evidence).\n//\n// The scrub itself deletes/anonymizes data across many collections; this doc is\n// ONLY the request lifecycle + the worker's resumable cursor.\n//\n// [C-02] Erasure-vs-safety-hold race fence. The destructive scrub and a safety\n// hold landing mid-scrub race over the SAME account. The fence is an epoch LEASE\n// stamped on THIS doc (`erasureLease`): the scrub transactionally acquires the\n// lease ONLY when the account owns no active blocking hold; every destructive\n// write re-checks the SAME epoch in its own transaction; and `commitSafetyHold`\n// (the SINGLE shared hold authority) reads this doc's live lease and PARKS the\n// erasure (revoking the epoch) before committing a hold against a leased account.\n// A revoked epoch makes every still-running destructive step a no-op. The lease\n// lives HERE — not a parallel safety-only deletion subsystem — so the one shared\n// hold/destructive contract owns the fence (engineering-rules ARCH-001).\n\nimport { z } from 'zod';\n\n/** Lifecycle of an account-deletion request. */\nexport const AccountDeletionRequestStatusSchema = z.enum([\n 'pending', // grace window running; user can still cancel by logging in\n 'cancelled', // user cancelled (logged back in) before the window elapsed\n 'scrubbing', // the scrub worker has started the anonymize-in-place erasure\n // [C-02] the scrub holds an ACTIVE erasure lease and is mid-destruction. A hold\n // landing now revokes the lease (→ parkedOnHold) so the scrub aborts deterministically.\n 'leased',\n 'parkedOnHold', // erasure deferred — a blocking safety hold covers the user's data\n 'completed', // erasure finished\n 'superseded', // overridden by a ban-for-cause / evidence-preservation outcome\n]);\nexport type AccountDeletionRequestStatus = z.infer<typeof AccountDeletionRequestStatusSchema>;\n\n/**\n * [C-02] The erasure LEASE / epoch token — the race fence between the destructive\n * scrub and a mid-scrub safety hold.\n *\n * The scrub acquires this transactionally ONLY when the account owns no active\n * blocking hold; it then re-verifies the SAME `epoch` inside every destructive\n * Firestore transaction and immediately before AND after each non-transactional\n * external delete (Auth/Storage). `commitSafetyHold` reads this lease and, when it\n * is `active`, REVOKES it (sets `revokedByHold`/`revokedAt`, status → `parkedOnHold`)\n * in the SAME transaction that commits the hold — so a hold deterministically wins\n * the race and the scrub, finding its epoch revoked on the next check, aborts into\n * a recoverable parked state without finishing the destruction.\n */\nexport const ErasureLeaseV1Schema = z\n .object({\n /** Monotonic acquisition token. The \"live lease\" identity: every destructive step\n * re-reads the doc and proceeds ONLY if this still equals the epoch it acquired. */\n epoch: z.number().int().nonnegative(),\n /** 'active' = the scrub holds the lease; 'revoked' = a hold reclaimed it mid-scrub\n * (the scrub must abort); 'released' = the scrub finished/relinquished cleanly. */\n state: z.enum(['active', 'revoked', 'released']),\n acquiredAt: z.number(),\n /** Staleness boundary. A still-`active` lease past this is presumed crashed and may\n * be safely superseded by a fresh acquisition (idempotent retry / crash recovery). */\n expiresAt: z.number(),\n /** Last destructive phase the scrub reached under this epoch (observability + recovery). */\n phase: z.string().optional(),\n /** Set when a hold revoked the lease — the caseId/refId of the winning hold (audit trail). */\n revokedByHoldRefId: z.string().min(1).optional(),\n revokedAt: z.number().optional(),\n releasedAt: z.number().optional(),\n })\n .strict();\nexport type ErasureLeaseV1 = z.infer<typeof ErasureLeaseV1Schema>;\n\n/** `accountDeletionRequests/{uid}` — one per user; doc id IS the uid. */\nexport const AccountDeletionRequestV1Schema = z\n .object({\n schemaVersion: z.literal(1),\n uid: z.string().min(1),\n status: AccountDeletionRequestStatusSchema,\n requestedAt: z.number(),\n // requestedAt + graceDays; the scrub worker queries status='pending' AND\n // scheduledScrubAt <= now (composite index, ttt-prod firestore.indexes.json).\n scheduledScrubAt: z.number(),\n graceDays: z.number(), // recorded for the audit/compliance trail (30 at launch)\n cancelledAt: z.number().optional(),\n scrubStartedAt: z.number().optional(),\n // Why a scrub is parked (e.g. 'blocking safety hold over user data') — kept for\n // the GDPR compliance record so a deferred erasure is explainable.\n parkedReason: z.string().optional(),\n parkedAt: z.number().optional(),\n lastHoldCheckAt: z.number().optional(),\n completedAt: z.number().optional(),\n supersededAt: z.number().optional(),\n supersededReason: z.string().optional(),\n // [C-02] the erasure-vs-hold race fence (see ErasureLeaseV1). Absent until the\n // scrub first acquires the lease; thereafter it carries the live epoch + state.\n erasureLease: ErasureLeaseV1Schema.optional(),\n createdAt: z.number(),\n updatedAt: z.number(),\n })\n .strict();\nexport type AccountDeletionRequestV1 = z.infer<typeof AccountDeletionRequestV1Schema>;\n"]}
|
|
@@ -227,7 +227,7 @@ export const COLLECTION_SCHEMAS = {
|
|
|
227
227
|
'_config/termsOfService': LegalPageDocumentSchema,
|
|
228
228
|
'_config/privacyPolicy': LegalPageDocumentSchema,
|
|
229
229
|
'_config/takeItDownPageCopy': TakeItDownPageCopySchema,
|
|
230
|
-
// ===== _serverData singletons (server-only — Cloud-Functions-only readers,
|
|
230
|
+
// ===== _serverData singletons (server-only — Cloud-Functions-only readers, BACKEND-108) =====
|
|
231
231
|
'_serverData/agePolicy': AgePolicyConfigV1Schema,
|
|
232
232
|
'_serverData/nciiPolicy': NciiPolicyConfigV1Schema,
|
|
233
233
|
'_serverData/privilegedReviewerSecurity': PrivilegedReviewerSecurityProfileV1Schema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/doc-schemas/registry.ts"],"names":[],"mappings":"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","sourcesContent":["// Firestore collection registry — the single, authoritative binding from each Firestore\n// collection/subcollection path template to its document Zod schema. This is the input to\n// the schema-doc generator and the drift-check, and its completeness is CI-enforced\n// (registry.test.ts) against the COLLECTIONS / *_SUBCOLLECTIONS name constants, so a new\n// collection cannot be added without either a schema or an explicit PENDING entry.\n//\n// Path templates reuse the segment names from ../paths/collections.ts (and the shapes the\n// path-builders produce). `{placeholder}` segments are document/parent IDs.\n\nimport type { z } from 'zod';\nimport {\n FullUserSchema,\n UserPrivateDataSchema,\n CraftSkillSchema,\n CraftSkillReferenceSchema,\n} from './user.js';\nimport { PublicUserSchema } from './publicUser.js';\nimport { AccountDeletionRequestV1Schema } from './account-deletion.js';\nimport {\n FullWorkProjectSchema,\n PublicWorkProjectSchema,\n WorkFileFolderSchema,\n WorkFileSchema,\n WorkRealmSchema,\n GuildmateUserSchema,\n PublicGuildmateUserSchema,\n} from './work-project.js';\nimport {\n FullTaleSchema,\n FullChapterSchema,\n FullTuneSchema,\n FullTuneTrackSchema,\n FullTelevisionSchema,\n FullTelevisionEpisodeSchema,\n ThresholdItemSchema,\n PublishedHallItemSchema,\n PublishedChapterSchema,\n PublishedTuneTrackSchema,\n PublishedTelevisionEpisodeSchema,\n HallContentChangeRequestSchema,\n FuturePlansDocumentSchema,\n RulesAndAgreementsSchema,\n LegalPageDocumentSchema,\n TakeItDownPageCopySchema,\n HallLibraryPreferencesSchema,\n} from './content.js';\nimport {\n SquareStreetzPostSchema,\n MentionHistoryDocumentSchema,\n FollowEdgeSchema,\n FollowCounterSchema,\n SquareStreetzLikeSchema,\n TrendingPostsSchema,\n} from './social.js';\nimport {\n PledgePaymentSchema,\n PledgePaymentProviderRefSchema,\n ProcessedStripeEventSchema,\n PledgePaymentLedgerEventSchema,\n PaymentWebhookQuarantineSchema,\n PledgePaymentTotalsDocSchema,\n PledgeRefundRequestSchema,\n} from './payments.js';\nimport {\n FullCommissionListingSchema,\n CommissionProposalSchema,\n AuditionSchema,\n AuditionEntrySchema,\n UserAuditionVoteSchema,\n} from './commissions.js';\nimport {\n GuildChatChannelSchema,\n GuildInviteConversationSchema,\n AdminDispatchSchema,\n ChatMessageV1Schema,\n} from './messaging.js';\nimport { AppConfigSchema, AdminListSchema, ProfanityListSchema, ReservedUsernamesSchema, BlockedFranchiseNamesSchema, AppModeMarkerSchema } from './system.js';\nimport {\n ContentViolationSchema,\n ModerationCascadeManifestSchema,\n ModerationCascadeChangedDocSchema,\n} from './moderation.js';\nimport {\n AdminTaskDocSchema,\n} from './report-docs.js';\nimport { TTTAuditEventSchema } from './audit.js';\nimport {\n NotificationDocSchema,\n NotificationHistoryDocSchema,\n PendingNotificationSchema,\n} from './notifications.js';\nimport {\n NotificationDeliverySchema,\n NotificationFanoutJobSchema,\n} from './notification-ledger.js';\nimport {\n ChatChannelAuthProjectionSchema,\n ChatScopeDegradedSchema,\n ChatScopeDegradedCauseSchema,\n ChatSyncEventSchema,\n ChatSyncFanoutJobSchema,\n ChatMessageOutboxSchema,\n ChatAdminActionCommandSchema,\n ChatHistoryAnonymizationJobSchema,\n ChatHistoryAnonymizationAffectedChunkSchema,\n} from './chat-sync.js';\nimport { SquareAnnouncementJobSchema } from './square-announcement-jobs.js';\nimport { PendingMediaSchema, ArchivedPendingMediaSchema } from '../media/pending-media.js';\nimport { MediaAssetSchema } from './media-assets.js';\nimport { MediaActivationJobSchema } from './media-activation-jobs.js';\nimport {\n ReservedDisplayNameSchema,\n ReservedRealmNameSchema,\n StakeShareAuditEventSchema,\n ShortLinkSchema,\n FeedbackAliasSchema,\n UserSuggestionSchema,\n StatusReconcileQueueEntrySchema,\n} from './operational.js';\n// ===== Trust & Safety — report spine (§A1) =====\nimport {\n ProtectedReportRootV1Schema,\n ReportPublicProjectionV1Schema,\n ReportGroupV1Schema,\n ReportTargetSnapshotV1Schema,\n NarrativeRecordV1Schema,\n} from './safety/report.js';\nimport { SafetyCaseAlertV1Schema } from './safety/case-alert.js';\n// ===== Trust & Safety — child-safety case spine (§A1b, §A2) =====\nimport {\n ChildSafetyCaseListV1Schema,\n ChildSafetyCaseV1Schema,\n ChildSafetySourceSignalV1Schema,\n ChildSafetyDecisionV1Schema,\n ChildSafetyDecisionViewV1Schema,\n ChildSafetyCaseAccountV1Schema,\n ChildSafetyCaseAccountHistoryV1Schema,\n ChildSafetyNcmecSubmissionV1Schema,\n ChildSafetyNcmecSubmissionFileV1Schema,\n ChildSafetyLegalProcessEventV1Schema,\n} from './safety/case.js';\nimport {\n ChildSafetyOwningAliasV1Schema,\n} from './safety/case-aliases.js';\nimport {\n SafetyHoldRefV1Schema,\n SafetyHoldResourceV1Schema,\n SafetyResourceCommandV1Schema,\n SafetyResourceCommandAuthorizedRequestV1Schema,\n SafetyResourceCommandBypassRefV1Schema,\n} from './safety/holds.js';\nimport {\n SafetyEvidenceManifestV1Schema,\n SafetyEvidenceJobV1Schema,\n SafetyEvidenceJobItemV1Schema,\n SafetyEvidenceDispositionV1Schema,\n} from './safety/evidence.js';\nimport { EventProvenanceV1Schema } from './safety/provenance.js';\nimport {\n QuarantineSagaJobV1Schema,\n QuarantineSagaRelatedAssetV1Schema,\n NcmecSubmissionJobV1Schema,\n AccountActionCommandV1Schema,\n} from './safety/sagas.js';\nimport {\n SafetySlaMonitorV1Schema,\n SafetyMonitorHeartbeatV1Schema,\n} from './safety/monitors.js';\nimport { AgeAttestationNonceV1Schema, AgePolicyConfigV1Schema } from './safety/age.js';\nimport {\n PrivilegedReviewerPasskeyProfileV1Schema,\n PrivilegedReviewerCapabilityGrantV1Schema,\n} from './safety/reviewer-security.js';\n// ===== Trust & Safety — NCII / TAKE IT DOWN (§A11) =====\nimport { NciiAllegationV1Schema } from './ncii/allegations.js';\nimport {\n TakeItDownRequestRootV1Schema,\n TakeItDownRequesterPrivateV1Schema,\n TakeItDownSubmissionV1Schema,\n TakeItDownValidityDecisionV1Schema,\n TakeItDownRequestActionV1Schema,\n TakeItDownEvidenceV1Schema,\n NciiRetainedEvidenceInventoryV1Schema,\n} from './ncii/requests.js';\nimport {\n NciiCaseV1Schema,\n NciiCaseAllegationLinkV1Schema,\n NciiCaseRequestLinkV1Schema,\n NciiCaseRemovalActionV1Schema,\n NciiBlockedHashV1Schema,\n} from './ncii/cases.js';\nimport { NciiTemporaryHoldV1Schema } from './ncii/holds.js';\nimport {\n NciiRemovalJobV1Schema,\n NciiRemovalTargetV1Schema,\n} from './ncii/removal.js';\nimport {\n NciiPolicyConfigV1Schema,\n PrivilegedReviewerSecurityProfileV1Schema,\n} from './ncii/config.js';\n\nexport const COLLECTION_SCHEMAS = {\n // ===== Users =====\n 'userProfiles/{userId}': FullUserSchema,\n 'userProfiles/{userId}/privateData/{userId}': UserPrivateDataSchema,\n 'userProfiles/{userId}/privateData/hallLibraryPreferences': HallLibraryPreferencesSchema,\n 'userProfiles/{userId}/profileCraftSkills/{craftSkillId}': CraftSkillSchema,\n 'userProfiles/{userId}/auditionVotes/{auditionId}': UserAuditionVoteSchema,\n 'userProfiles/{userId}/mentionHistory/{docId}': MentionHistoryDocumentSchema,\n 'userProfiles/{userId}/notificationHistory/{notificationId}': NotificationHistoryDocSchema,\n 'userProfiles/{userId}/userLikes/likeHistory/squareStreetzLikes/{postId}': SquareStreetzLikeSchema,\n 'publicUsers/{uid}': PublicUserSchema,\n\n // ===== Work / Realm / Guild =====\n 'allWorkProjects/{workProjectId}': FullWorkProjectSchema,\n 'allWorkProjects/{workProjectId}/guildmateUsers/{uid}': GuildmateUserSchema,\n 'allWorkProjects/{workProjectId}/publicGuildmateUsers/{uid}': PublicGuildmateUserSchema,\n 'allWorkProjects/{workProjectId}/workFileFolders/{workFileFolderId}': WorkFileFolderSchema,\n 'allWorkProjects/{workProjectId}/workFileFolders/{workFileFolderId}/workFiles/{workFileId}': WorkFileSchema,\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}': FullTaleSchema,\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}/taleChapters/{chapterId}': FullChapterSchema,\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}': FullTuneSchema,\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}/tuneTracks/{trackId}': FullTuneTrackSchema,\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}': FullTelevisionSchema,\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}/televisionEpisodes/{episodeId}': FullTelevisionEpisodeSchema,\n 'allWorkProjects/{workProjectId}/guildChatChannels/{guildChatChannelId}': GuildChatChannelSchema,\n // Guild channel + invite messages are REALTIME-ONLY (chat Worker DO) — no Firestore schema.\n 'publicWorkProjects/{workProjectId}': PublicWorkProjectSchema,\n 'workRealms/{workRealmId}': WorkRealmSchema,\n 'guildInviteConversations/{guildInviteId}': GuildInviteConversationSchema,\n\n // ===== Square / Social =====\n 'squareStreetzFeed/activePosts/socialPosts/{postId}': SquareStreetzPostSchema,\n 'squareStreetzFeed/trendingPosts': TrendingPostsSchema,\n 'followEdges/{followEdgeId}': FollowEdgeSchema,\n 'followCounters/{followCounterId}': FollowCounterSchema,\n // Durable Square announcement outbox (Admin-SDK-only; deterministic job ids).\n 'squareAnnouncementJobs/{jobId}': SquareAnnouncementJobSchema,\n\n // ===== Payments / pledge ledger =====\n 'pledgePayments/{pledgePaymentId}': PledgePaymentSchema,\n 'pledgePaymentProviderRefs/{pledgePaymentId}': PledgePaymentProviderRefSchema,\n 'processedStripeEvents/{stripeEventId}': ProcessedStripeEventSchema,\n 'pledgePaymentLedgerEvents/{ledgerId}': PledgePaymentLedgerEventSchema,\n 'paymentWebhookQuarantine/{stripeEventId}': PaymentWebhookQuarantineSchema,\n 'pledgePaymentTotals/summary': PledgePaymentTotalsDocSchema,\n 'pledgeRefundRequests/{requestId}': PledgeRefundRequestSchema,\n\n // ===== Threshold / Hall =====\n 'thresholdItems/{thresholdItemId}': ThresholdItemSchema,\n 'hallItems/{hallItemId}': PublishedHallItemSchema,\n // Published hall sub-item projections — the chapter/track/episode docs copied out of\n // the Work at publish time (runPublishApprovedHallLibraryItem). Segment names are the\n // HALL_ITEM_SUBCOLLECTIONS constants (the lowercased WorkProjectType).\n 'hallItems/{hallItemId}/tales/{itemId}': PublishedChapterSchema,\n 'hallItems/{hallItemId}/tunes/{itemId}': PublishedTuneTrackSchema,\n 'hallItems/{hallItemId}/television/{itemId}': PublishedTelevisionEpisodeSchema,\n 'hallContentChangeRequests/{changeRequestId}': HallContentChangeRequestSchema,\n\n // ===== Commission / Audition =====\n 'commissionListings/{commissionListingId}': FullCommissionListingSchema,\n 'commissionListings/{commissionListingId}/commissionProposals/{commissionProposalId}': CommissionProposalSchema,\n 'auditionBoard/{auditionId}': AuditionSchema,\n 'auditionBoard/{auditionId}/auditionEntries/{auditionEntryId}': AuditionEntrySchema,\n\n // ===== Moderation / Reports / Admin =====\n // The report spine (§A1): the restricted root, its public projection subdoc, and the\n // dedup/count group. The root + projection are written by the app's submitReport\n // callable; the group is maintained by an app-side trigger.\n 'contentReports/{reportId}': ProtectedReportRootV1Schema,\n 'contentReports/{reportId}/publicProjection/{reportId}': ReportPublicProjectionV1Schema,\n 'contentReports/{reportId}/private/snapshot': ReportTargetSnapshotV1Schema,\n 'contentReports/{reportId}/private/narrative': NarrativeRecordV1Schema,\n 'activeReportGroups/{groupKey}': ReportGroupV1Schema,\n 'adminTasks/{taskId}': AdminTaskDocSchema,\n 'contentViolations/{violationId}': ContentViolationSchema,\n 'moderationCascadeManifests/{cascadeId}': ModerationCascadeManifestSchema,\n 'moderationCascadeManifests/{cascadeId}/changedDocs/{changedDocId}': ModerationCascadeChangedDocSchema,\n 'auditEvents/{eventId}': TTTAuditEventSchema,\n 'stakeShareAuditEvents/{eventId}': StakeShareAuditEventSchema,\n 'pendingAdminDispatches/{adminDispatchId}': AdminDispatchSchema,\n 'pendingAdminDispatches/{adminDispatchId}/conversationMessages/{adminDispatchMessageId}': ChatMessageV1Schema,\n\n // ===== Media pipeline =====\n 'pendingMedia/{pendingMediaId}': PendingMediaSchema,\n 'pendingMediaArchive/{pendingMediaId}': ArchivedPendingMediaSchema,\n 'mediaAssets/{mediaAssetId}': MediaAssetSchema,\n 'mediaActivationJobs/{jobId}': MediaActivationJobSchema,\n\n // ===== Notifications =====\n 'activeUserNotifications/{notificationId}': NotificationDocSchema,\n 'activeAdminNotifications/{notificationId}': NotificationDocSchema,\n 'adminNotificationHistory/{notificationId}': NotificationHistoryDocSchema,\n 'pendingNotifications/{notificationId}': PendingNotificationSchema,\n\n // ===== Notification redesign — delivery ledger + fanout engine =====\n 'notificationDeliveries/{deliveryId}': NotificationDeliverySchema,\n 'notificationFanoutJobs/{jobId}': NotificationFanoutJobSchema,\n\n // ===== Chat realtime sync / projection / commands =====\n 'chatChannelAuthProjections/{authPairKey}': ChatChannelAuthProjectionSchema,\n 'chatScopeDegraded/{scopeKey}': ChatScopeDegradedSchema,\n 'chatScopeDegraded/{scopeKey}/causes/{causeId}': ChatScopeDegradedCauseSchema,\n 'chatSyncEvents/{eventId}': ChatSyncEventSchema,\n 'chatSyncFanoutJobs/{jobId}': ChatSyncFanoutJobSchema,\n 'chatMessageOutbox/{commandId}': ChatMessageOutboxSchema,\n 'chatAdminActionCommands/{requestId}': ChatAdminActionCommandSchema,\n 'chatHistoryAnonymizationJobs/{jobId}': ChatHistoryAnonymizationJobSchema,\n 'chatHistoryAnonymizationJobs/{jobId}/affectedChunks/{chunkOrdinal}': ChatHistoryAnonymizationAffectedChunkSchema,\n\n // ===== Craft skills index =====\n 'craftSkillsByTag/{tag}/taggedCraftSkills/{compositeId}': CraftSkillReferenceSchema,\n\n // ===== Operational / utility =====\n 'reservedDisplayNames/{displayNameUppercase}': ReservedDisplayNameSchema,\n 'reservedRealmNames/{workingTitleUppercase}': ReservedRealmNameSchema,\n 'accountDeletionRequests/{uid}': AccountDeletionRequestV1Schema,\n 'shortLinks/{shortId}': ShortLinkSchema,\n 'feedbackAliases/{aliasId}': FeedbackAliasSchema,\n 'feedbackSubmissions/{feedbackType}/userSuggestions/{suggestionId}': UserSuggestionSchema,\n 'statusReconcileQueue/{uid}': StatusReconcileQueueEntrySchema,\n\n // ===== Trust & Safety — child-safety case spine (§A1b, §A2) =====\n 'childSafetyCaseList/{caseId}': ChildSafetyCaseListV1Schema,\n 'activeSafetyCaseAlerts/{caseId}': SafetyCaseAlertV1Schema,\n 'childSafetyCases/{caseId}': ChildSafetyCaseV1Schema,\n 'childSafetyCases/{caseId}/sourceSignals/{signalId}': ChildSafetySourceSignalV1Schema,\n 'childSafetyCases/{caseId}/decisions/{decisionId}': ChildSafetyDecisionV1Schema,\n 'childSafetyCases/{caseId}/decisions/{decisionId}/views/{viewId}': ChildSafetyDecisionViewV1Schema,\n 'childSafetyCases/{caseId}/accounts/{uid}': ChildSafetyCaseAccountV1Schema,\n 'childSafetyCases/{caseId}/accounts/{uid}/history/{historyId}': ChildSafetyCaseAccountHistoryV1Schema,\n 'childSafetyCases/{caseId}/ncmecSubmissions/{submissionId}': ChildSafetyNcmecSubmissionV1Schema,\n 'childSafetyCases/{caseId}/ncmecSubmissions/{submissionId}/files/{fileId}': ChildSafetyNcmecSubmissionFileV1Schema,\n 'childSafetyCases/{caseId}/legalProcess/{eventId}': ChildSafetyLegalProcessEventV1Schema,\n 'childSafetyOwningAliases/{aliasId}': ChildSafetyOwningAliasV1Schema,\n\n // ===== Trust & Safety — holds + resource commands (§A3) =====\n 'safetyHoldRefs/{holdRefId}': SafetyHoldRefV1Schema,\n 'safetyHoldResources/{resourceKeyHash}': SafetyHoldResourceV1Schema,\n 'safetyResourceCommands/{commandDocId}': SafetyResourceCommandV1Schema,\n 'safetyResourceCommands/{commandDocId}/authorizedRequests/{requestId}': SafetyResourceCommandAuthorizedRequestV1Schema,\n 'safetyResourceCommands/{commandDocId}/bypassRefs/{refId}': SafetyResourceCommandBypassRefV1Schema,\n\n // ===== Trust & Safety — evidence + provenance (§A4, §A6) =====\n // SafetyEvidenceManifestV1Schema is a refined ZodObject (superRefine for the H5\n // sourceKind invariant); the schema-doc generator unwraps the effect to introspect\n // its shape, so binding the refined schema here is correct.\n 'safetyEvidenceManifests/{manifestId}': SafetyEvidenceManifestV1Schema,\n 'safetyEvidenceJobs/{jobId}': SafetyEvidenceJobV1Schema,\n 'safetyEvidenceJobs/{jobId}/items/{itemId}': SafetyEvidenceJobItemV1Schema,\n 'safetyEvidenceJobs/{jobId}/disposition/{locationId}': SafetyEvidenceDispositionV1Schema,\n 'eventProvenance/{eventId}': EventProvenanceV1Schema,\n\n // ===== Trust & Safety — sagas + closure (§A5) =====\n 'quarantineSagaJobs/{caseId}': QuarantineSagaJobV1Schema,\n 'quarantineSagaJobs/{caseId}/relatedAssets/{assetId}': QuarantineSagaRelatedAssetV1Schema,\n 'ncmecSubmissionJobs/{ncmecJobId}': NcmecSubmissionJobV1Schema,\n 'accountActionCommands/{accountActionCommandId}': AccountActionCommandV1Schema,\n\n // ===== Trust & Safety — SLA monitors + heartbeat (§A8) =====\n 'safetySlaMonitors/{monitorId}': SafetySlaMonitorV1Schema,\n 'safetyMonitorHeartbeat/global': SafetyMonitorHeartbeatV1Schema,\n\n // ===== Trust & Safety — age attestation nonces (§A7) =====\n 'ageAttestationNonces/{nonceHash}': AgeAttestationNonceV1Schema,\n\n // ===== Trust & Safety — per-operator privileged-reviewer security (§A11 [M-6] / [H-17]) =====\n // Backend-only (Cloud-Functions-only readers/writers; client access denied in firestore.rules).\n 'privilegedReviewerPasskeyProfiles/{uid}': PrivilegedReviewerPasskeyProfileV1Schema,\n 'privilegedReviewerCapabilityGrants/{uid}': PrivilegedReviewerCapabilityGrantV1Schema,\n\n // ===== Trust & Safety — NCII / TAKE IT DOWN (§A11) =====\n 'nciiAllegations/{allegationId}': NciiAllegationV1Schema,\n 'takeItDownRequests/{requestId}': TakeItDownRequestRootV1Schema,\n 'takeItDownRequests/{requestId}/private/requester': TakeItDownRequesterPrivateV1Schema,\n 'takeItDownRequests/{requestId}/submissions/{submissionId}': TakeItDownSubmissionV1Schema,\n 'takeItDownRequests/{requestId}/validityDecisions/{decisionId}': TakeItDownValidityDecisionV1Schema,\n 'takeItDownRequests/{requestId}/actions/{actionId}': TakeItDownRequestActionV1Schema,\n 'takeItDownRequests/{requestId}/evidence/{evidenceId}': TakeItDownEvidenceV1Schema,\n 'nciiCases/{caseId}': NciiCaseV1Schema,\n 'nciiCases/{caseId}/allegationLinks/{allegationId}': NciiCaseAllegationLinkV1Schema,\n 'nciiCases/{caseId}/requestLinks/{requestId}': NciiCaseRequestLinkV1Schema,\n 'nciiCases/{caseId}/removalActions/{actionId}': NciiCaseRemovalActionV1Schema,\n 'nciiCases/{caseId}/blockedHashes/{hashId}': NciiBlockedHashV1Schema,\n 'nciiRetainedEvidenceInventory/{inventoryId}': NciiRetainedEvidenceInventoryV1Schema,\n // [H-01] dead-letter sink for inventory rows that could not be written to the primary\n // nciiRetainedEvidenceInventory collection. Stores the same document shape.\n 'nciiInventoryDeadLetter/{inventoryId}': NciiRetainedEvidenceInventoryV1Schema,\n 'nciiTemporaryHolds/{holdId}': NciiTemporaryHoldV1Schema,\n 'nciiRemovalJobs/{jobId}': NciiRemovalJobV1Schema,\n 'nciiRemovalJobs/{jobId}/targets/{targetKeyHash}': NciiRemovalTargetV1Schema,\n\n // ===== _config singletons (public) =====\n '_config/app': AppConfigSchema,\n '_config/futurePlans': FuturePlansDocumentSchema,\n '_config/rulesAndAgreements': RulesAndAgreementsSchema,\n // Content-pages migration (DJ ruling 2026-07-06): /terms, /privacy, and the\n // /take-it-down page copy render exclusively from these (all public pages —\n // take-it-down is a NO-LOGIN page, so its copy doc must be publicly readable).\n '_config/termsOfService': LegalPageDocumentSchema,\n '_config/privacyPolicy': LegalPageDocumentSchema,\n '_config/takeItDownPageCopy': TakeItDownPageCopySchema,\n\n // ===== _serverData singletons (server-only — Cloud-Functions-only readers, Rule 32) =====\n '_serverData/agePolicy': AgePolicyConfigV1Schema,\n '_serverData/nciiPolicy': NciiPolicyConfigV1Schema,\n '_serverData/privilegedReviewerSecurity': PrivilegedReviewerSecurityProfileV1Schema,\n\n // ===== _systemData singletons =====\n '_systemData/adminList': AdminListSchema,\n '_systemData/profanityList': ProfanityListSchema,\n '_systemData/reservedUsernames': ReservedUsernamesSchema,\n '_systemData/blockedFranchiseNames': BlockedFranchiseNamesSchema,\n '_systemData/appMode': AppModeMarkerSchema,\n} as const satisfies Record<string, z.ZodTypeAny>;\n\nexport type RegisteredCollectionPath = keyof typeof COLLECTION_SCHEMAS;\n\n/**\n * Doc-id field annotation: for the listed bindings, the named body field equals the\n * Firestore document id and is injected at READ time (`{ ...doc.data(), <field>: doc.id }`),\n * never persisted — the write callables store the body via `Omit<…, '<field>'>`. The bound\n * schema models the (correct) consumer/read shape, where the field is required, so a raw\n * stored doc is \"missing\" it. The drift-check injects `{ [field]: doc.id, ...data }` before\n * validating, generalizing the one-off `AdminTaskDocSchema` stored-shape workaround into a\n * single mechanism so real-callable drift-checks don't false-flag every doc-id collection.\n * The schema-doc generator ignores this map. Keys are compiler-checked against the registry.\n */\nexport const COLLECTION_DOC_ID_FIELDS = {\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}/taleChapters/{chapterId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}/tuneTracks/{trackId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}/televisionEpisodes/{episodeId}': 'uid',\n 'allWorkProjects/{workProjectId}/guildChatChannels/{guildChatChannelId}': 'guildChatChannelId',\n // Published hall sub-items: the doc id IS the live sub-item's id; `uid` is injected at\n // read (the publish writer spreads the live doc's stored body, which has no `uid`).\n 'hallItems/{hallItemId}/tales/{itemId}': 'uid',\n 'hallItems/{hallItemId}/tunes/{itemId}': 'uid',\n 'hallItems/{hallItemId}/television/{itemId}': 'uid',\n 'activeUserNotifications/{notificationId}': 'id',\n 'activeAdminNotifications/{notificationId}': 'id',\n 'adminNotificationHistory/{notificationId}': 'archiveOccurrenceId',\n 'userProfiles/{userId}/notificationHistory/{notificationId}': 'archiveOccurrenceId',\n 'pendingNotifications/{notificationId}': 'id',\n 'statusReconcileQueue/{uid}': 'uid',\n} as const satisfies Partial<Record<RegisteredCollectionPath, string>>;\n\n/**\n * Collections that exist (in COLLECTIONS / *_SUBCOLLECTIONS or firestore.rules) but are\n * intentionally NOT bound to a schema, each with a reason. Listed EXPLICITLY so completeness is\n * enforced and nothing is silently uncovered; the registry test fails if a NEW unlisted collection\n * appears. These three are the only remaining gaps after the schema-registry binding pass:\n *\n * - userMetadata: `userProfiles/{uid}/userMetadata/notificationSettings` — a firestore.rules\n * match and `PATH_BUILDERS.userMetadata` exist, but there is no live reader/writer and no\n * notification-settings type anywhere yet. Bind once that shape is implemented.\n * - checkedOutItems: a `userProfiles/{uid}/checkedOutItems` subcollection constant with no writer,\n * reader, rule, or path-builder (the admin \"checked out items\" UI reads adminTasks by\n * `checkoutDetails.userId`, not this subcollection). Vestigial — remove once confirmed safe.\n * - feedbackDenylist: `feedbackDenylist/{deniedWord}` — Console-managed (firestore.rules §3F: no\n * callable writes it) and submitFeedback reads it via `.exists` only, so there is no field\n * contract to author a schema from. The doc id is the denied word; the body is unused.\n */\nexport const PENDING_COLLECTIONS: readonly string[] = [\n 'userMetadata',\n 'checkedOutItems',\n 'feedbackDenylist',\n // Append-only NCII case closure/reopen event rows — the doc shape is owned app-side\n // (NciiCaseV1 closure events), not modeled in ttt-core doc-schemas.\n 'closureEvents',\n] as const;\n"]}
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/doc-schemas/registry.ts"],"names":[],"mappings":"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","sourcesContent":["// Firestore collection registry — the single, authoritative binding from each Firestore\n// collection/subcollection path template to its document Zod schema. This is the input to\n// the schema-doc generator and the drift-check, and its completeness is CI-enforced\n// (registry.test.ts) against the COLLECTIONS / *_SUBCOLLECTIONS name constants, so a new\n// collection cannot be added without either a schema or an explicit PENDING entry.\n//\n// Path templates reuse the segment names from ../paths/collections.ts (and the shapes the\n// path-builders produce). `{placeholder}` segments are document/parent IDs.\n\nimport type { z } from 'zod';\nimport {\n FullUserSchema,\n UserPrivateDataSchema,\n CraftSkillSchema,\n CraftSkillReferenceSchema,\n} from './user.js';\nimport { PublicUserSchema } from './publicUser.js';\nimport { AccountDeletionRequestV1Schema } from './account-deletion.js';\nimport {\n FullWorkProjectSchema,\n PublicWorkProjectSchema,\n WorkFileFolderSchema,\n WorkFileSchema,\n WorkRealmSchema,\n GuildmateUserSchema,\n PublicGuildmateUserSchema,\n} from './work-project.js';\nimport {\n FullTaleSchema,\n FullChapterSchema,\n FullTuneSchema,\n FullTuneTrackSchema,\n FullTelevisionSchema,\n FullTelevisionEpisodeSchema,\n ThresholdItemSchema,\n PublishedHallItemSchema,\n PublishedChapterSchema,\n PublishedTuneTrackSchema,\n PublishedTelevisionEpisodeSchema,\n HallContentChangeRequestSchema,\n FuturePlansDocumentSchema,\n RulesAndAgreementsSchema,\n LegalPageDocumentSchema,\n TakeItDownPageCopySchema,\n HallLibraryPreferencesSchema,\n} from './content.js';\nimport {\n SquareStreetzPostSchema,\n MentionHistoryDocumentSchema,\n FollowEdgeSchema,\n FollowCounterSchema,\n SquareStreetzLikeSchema,\n TrendingPostsSchema,\n} from './social.js';\nimport {\n PledgePaymentSchema,\n PledgePaymentProviderRefSchema,\n ProcessedStripeEventSchema,\n PledgePaymentLedgerEventSchema,\n PaymentWebhookQuarantineSchema,\n PledgePaymentTotalsDocSchema,\n PledgeRefundRequestSchema,\n} from './payments.js';\nimport {\n FullCommissionListingSchema,\n CommissionProposalSchema,\n AuditionSchema,\n AuditionEntrySchema,\n UserAuditionVoteSchema,\n} from './commissions.js';\nimport {\n GuildChatChannelSchema,\n GuildInviteConversationSchema,\n AdminDispatchSchema,\n ChatMessageV1Schema,\n} from './messaging.js';\nimport { AppConfigSchema, AdminListSchema, ProfanityListSchema, ReservedUsernamesSchema, BlockedFranchiseNamesSchema, AppModeMarkerSchema } from './system.js';\nimport {\n ContentViolationSchema,\n ModerationCascadeManifestSchema,\n ModerationCascadeChangedDocSchema,\n} from './moderation.js';\nimport {\n AdminTaskDocSchema,\n} from './report-docs.js';\nimport { TTTAuditEventSchema } from './audit.js';\nimport {\n NotificationDocSchema,\n NotificationHistoryDocSchema,\n PendingNotificationSchema,\n} from './notifications.js';\nimport {\n NotificationDeliverySchema,\n NotificationFanoutJobSchema,\n} from './notification-ledger.js';\nimport {\n ChatChannelAuthProjectionSchema,\n ChatScopeDegradedSchema,\n ChatScopeDegradedCauseSchema,\n ChatSyncEventSchema,\n ChatSyncFanoutJobSchema,\n ChatMessageOutboxSchema,\n ChatAdminActionCommandSchema,\n ChatHistoryAnonymizationJobSchema,\n ChatHistoryAnonymizationAffectedChunkSchema,\n} from './chat-sync.js';\nimport { SquareAnnouncementJobSchema } from './square-announcement-jobs.js';\nimport { PendingMediaSchema, ArchivedPendingMediaSchema } from '../media/pending-media.js';\nimport { MediaAssetSchema } from './media-assets.js';\nimport { MediaActivationJobSchema } from './media-activation-jobs.js';\nimport {\n ReservedDisplayNameSchema,\n ReservedRealmNameSchema,\n StakeShareAuditEventSchema,\n ShortLinkSchema,\n FeedbackAliasSchema,\n UserSuggestionSchema,\n StatusReconcileQueueEntrySchema,\n} from './operational.js';\n// ===== Trust & Safety — report spine (§A1) =====\nimport {\n ProtectedReportRootV1Schema,\n ReportPublicProjectionV1Schema,\n ReportGroupV1Schema,\n ReportTargetSnapshotV1Schema,\n NarrativeRecordV1Schema,\n} from './safety/report.js';\nimport { SafetyCaseAlertV1Schema } from './safety/case-alert.js';\n// ===== Trust & Safety — child-safety case spine (§A1b, §A2) =====\nimport {\n ChildSafetyCaseListV1Schema,\n ChildSafetyCaseV1Schema,\n ChildSafetySourceSignalV1Schema,\n ChildSafetyDecisionV1Schema,\n ChildSafetyDecisionViewV1Schema,\n ChildSafetyCaseAccountV1Schema,\n ChildSafetyCaseAccountHistoryV1Schema,\n ChildSafetyNcmecSubmissionV1Schema,\n ChildSafetyNcmecSubmissionFileV1Schema,\n ChildSafetyLegalProcessEventV1Schema,\n} from './safety/case.js';\nimport {\n ChildSafetyOwningAliasV1Schema,\n} from './safety/case-aliases.js';\nimport {\n SafetyHoldRefV1Schema,\n SafetyHoldResourceV1Schema,\n SafetyResourceCommandV1Schema,\n SafetyResourceCommandAuthorizedRequestV1Schema,\n SafetyResourceCommandBypassRefV1Schema,\n} from './safety/holds.js';\nimport {\n SafetyEvidenceManifestV1Schema,\n SafetyEvidenceJobV1Schema,\n SafetyEvidenceJobItemV1Schema,\n SafetyEvidenceDispositionV1Schema,\n} from './safety/evidence.js';\nimport { EventProvenanceV1Schema } from './safety/provenance.js';\nimport {\n QuarantineSagaJobV1Schema,\n QuarantineSagaRelatedAssetV1Schema,\n NcmecSubmissionJobV1Schema,\n AccountActionCommandV1Schema,\n} from './safety/sagas.js';\nimport {\n SafetySlaMonitorV1Schema,\n SafetyMonitorHeartbeatV1Schema,\n} from './safety/monitors.js';\nimport { AgeAttestationNonceV1Schema, AgePolicyConfigV1Schema } from './safety/age.js';\nimport {\n PrivilegedReviewerPasskeyProfileV1Schema,\n PrivilegedReviewerCapabilityGrantV1Schema,\n} from './safety/reviewer-security.js';\n// ===== Trust & Safety — NCII / TAKE IT DOWN (§A11) =====\nimport { NciiAllegationV1Schema } from './ncii/allegations.js';\nimport {\n TakeItDownRequestRootV1Schema,\n TakeItDownRequesterPrivateV1Schema,\n TakeItDownSubmissionV1Schema,\n TakeItDownValidityDecisionV1Schema,\n TakeItDownRequestActionV1Schema,\n TakeItDownEvidenceV1Schema,\n NciiRetainedEvidenceInventoryV1Schema,\n} from './ncii/requests.js';\nimport {\n NciiCaseV1Schema,\n NciiCaseAllegationLinkV1Schema,\n NciiCaseRequestLinkV1Schema,\n NciiCaseRemovalActionV1Schema,\n NciiBlockedHashV1Schema,\n} from './ncii/cases.js';\nimport { NciiTemporaryHoldV1Schema } from './ncii/holds.js';\nimport {\n NciiRemovalJobV1Schema,\n NciiRemovalTargetV1Schema,\n} from './ncii/removal.js';\nimport {\n NciiPolicyConfigV1Schema,\n PrivilegedReviewerSecurityProfileV1Schema,\n} from './ncii/config.js';\n\nexport const COLLECTION_SCHEMAS = {\n // ===== Users =====\n 'userProfiles/{userId}': FullUserSchema,\n 'userProfiles/{userId}/privateData/{userId}': UserPrivateDataSchema,\n 'userProfiles/{userId}/privateData/hallLibraryPreferences': HallLibraryPreferencesSchema,\n 'userProfiles/{userId}/profileCraftSkills/{craftSkillId}': CraftSkillSchema,\n 'userProfiles/{userId}/auditionVotes/{auditionId}': UserAuditionVoteSchema,\n 'userProfiles/{userId}/mentionHistory/{docId}': MentionHistoryDocumentSchema,\n 'userProfiles/{userId}/notificationHistory/{notificationId}': NotificationHistoryDocSchema,\n 'userProfiles/{userId}/userLikes/likeHistory/squareStreetzLikes/{postId}': SquareStreetzLikeSchema,\n 'publicUsers/{uid}': PublicUserSchema,\n\n // ===== Work / Realm / Guild =====\n 'allWorkProjects/{workProjectId}': FullWorkProjectSchema,\n 'allWorkProjects/{workProjectId}/guildmateUsers/{uid}': GuildmateUserSchema,\n 'allWorkProjects/{workProjectId}/publicGuildmateUsers/{uid}': PublicGuildmateUserSchema,\n 'allWorkProjects/{workProjectId}/workFileFolders/{workFileFolderId}': WorkFileFolderSchema,\n 'allWorkProjects/{workProjectId}/workFileFolders/{workFileFolderId}/workFiles/{workFileId}': WorkFileSchema,\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}': FullTaleSchema,\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}/taleChapters/{chapterId}': FullChapterSchema,\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}': FullTuneSchema,\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}/tuneTracks/{trackId}': FullTuneTrackSchema,\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}': FullTelevisionSchema,\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}/televisionEpisodes/{episodeId}': FullTelevisionEpisodeSchema,\n 'allWorkProjects/{workProjectId}/guildChatChannels/{guildChatChannelId}': GuildChatChannelSchema,\n // Guild channel + invite messages are REALTIME-ONLY (chat Worker DO) — no Firestore schema.\n 'publicWorkProjects/{workProjectId}': PublicWorkProjectSchema,\n 'workRealms/{workRealmId}': WorkRealmSchema,\n 'guildInviteConversations/{guildInviteId}': GuildInviteConversationSchema,\n\n // ===== Square / Social =====\n 'squareStreetzFeed/activePosts/socialPosts/{postId}': SquareStreetzPostSchema,\n 'squareStreetzFeed/trendingPosts': TrendingPostsSchema,\n 'followEdges/{followEdgeId}': FollowEdgeSchema,\n 'followCounters/{followCounterId}': FollowCounterSchema,\n // Durable Square announcement outbox (Admin-SDK-only; deterministic job ids).\n 'squareAnnouncementJobs/{jobId}': SquareAnnouncementJobSchema,\n\n // ===== Payments / pledge ledger =====\n 'pledgePayments/{pledgePaymentId}': PledgePaymentSchema,\n 'pledgePaymentProviderRefs/{pledgePaymentId}': PledgePaymentProviderRefSchema,\n 'processedStripeEvents/{stripeEventId}': ProcessedStripeEventSchema,\n 'pledgePaymentLedgerEvents/{ledgerId}': PledgePaymentLedgerEventSchema,\n 'paymentWebhookQuarantine/{stripeEventId}': PaymentWebhookQuarantineSchema,\n 'pledgePaymentTotals/summary': PledgePaymentTotalsDocSchema,\n 'pledgeRefundRequests/{requestId}': PledgeRefundRequestSchema,\n\n // ===== Threshold / Hall =====\n 'thresholdItems/{thresholdItemId}': ThresholdItemSchema,\n 'hallItems/{hallItemId}': PublishedHallItemSchema,\n // Published hall sub-item projections — the chapter/track/episode docs copied out of\n // the Work at publish time (runPublishApprovedHallLibraryItem). Segment names are the\n // HALL_ITEM_SUBCOLLECTIONS constants (the lowercased WorkProjectType).\n 'hallItems/{hallItemId}/tales/{itemId}': PublishedChapterSchema,\n 'hallItems/{hallItemId}/tunes/{itemId}': PublishedTuneTrackSchema,\n 'hallItems/{hallItemId}/television/{itemId}': PublishedTelevisionEpisodeSchema,\n 'hallContentChangeRequests/{changeRequestId}': HallContentChangeRequestSchema,\n\n // ===== Commission / Audition =====\n 'commissionListings/{commissionListingId}': FullCommissionListingSchema,\n 'commissionListings/{commissionListingId}/commissionProposals/{commissionProposalId}': CommissionProposalSchema,\n 'auditionBoard/{auditionId}': AuditionSchema,\n 'auditionBoard/{auditionId}/auditionEntries/{auditionEntryId}': AuditionEntrySchema,\n\n // ===== Moderation / Reports / Admin =====\n // The report spine (§A1): the restricted root, its public projection subdoc, and the\n // dedup/count group. The root + projection are written by the app's submitReport\n // callable; the group is maintained by an app-side trigger.\n 'contentReports/{reportId}': ProtectedReportRootV1Schema,\n 'contentReports/{reportId}/publicProjection/{reportId}': ReportPublicProjectionV1Schema,\n 'contentReports/{reportId}/private/snapshot': ReportTargetSnapshotV1Schema,\n 'contentReports/{reportId}/private/narrative': NarrativeRecordV1Schema,\n 'activeReportGroups/{groupKey}': ReportGroupV1Schema,\n 'adminTasks/{taskId}': AdminTaskDocSchema,\n 'contentViolations/{violationId}': ContentViolationSchema,\n 'moderationCascadeManifests/{cascadeId}': ModerationCascadeManifestSchema,\n 'moderationCascadeManifests/{cascadeId}/changedDocs/{changedDocId}': ModerationCascadeChangedDocSchema,\n 'auditEvents/{eventId}': TTTAuditEventSchema,\n 'stakeShareAuditEvents/{eventId}': StakeShareAuditEventSchema,\n 'pendingAdminDispatches/{adminDispatchId}': AdminDispatchSchema,\n 'pendingAdminDispatches/{adminDispatchId}/conversationMessages/{adminDispatchMessageId}': ChatMessageV1Schema,\n\n // ===== Media pipeline =====\n 'pendingMedia/{pendingMediaId}': PendingMediaSchema,\n 'pendingMediaArchive/{pendingMediaId}': ArchivedPendingMediaSchema,\n 'mediaAssets/{mediaAssetId}': MediaAssetSchema,\n 'mediaActivationJobs/{jobId}': MediaActivationJobSchema,\n\n // ===== Notifications =====\n 'activeUserNotifications/{notificationId}': NotificationDocSchema,\n 'activeAdminNotifications/{notificationId}': NotificationDocSchema,\n 'adminNotificationHistory/{notificationId}': NotificationHistoryDocSchema,\n 'pendingNotifications/{notificationId}': PendingNotificationSchema,\n\n // ===== Notification redesign — delivery ledger + fanout engine =====\n 'notificationDeliveries/{deliveryId}': NotificationDeliverySchema,\n 'notificationFanoutJobs/{jobId}': NotificationFanoutJobSchema,\n\n // ===== Chat realtime sync / projection / commands =====\n 'chatChannelAuthProjections/{authPairKey}': ChatChannelAuthProjectionSchema,\n 'chatScopeDegraded/{scopeKey}': ChatScopeDegradedSchema,\n 'chatScopeDegraded/{scopeKey}/causes/{causeId}': ChatScopeDegradedCauseSchema,\n 'chatSyncEvents/{eventId}': ChatSyncEventSchema,\n 'chatSyncFanoutJobs/{jobId}': ChatSyncFanoutJobSchema,\n 'chatMessageOutbox/{commandId}': ChatMessageOutboxSchema,\n 'chatAdminActionCommands/{requestId}': ChatAdminActionCommandSchema,\n 'chatHistoryAnonymizationJobs/{jobId}': ChatHistoryAnonymizationJobSchema,\n 'chatHistoryAnonymizationJobs/{jobId}/affectedChunks/{chunkOrdinal}': ChatHistoryAnonymizationAffectedChunkSchema,\n\n // ===== Craft skills index =====\n 'craftSkillsByTag/{tag}/taggedCraftSkills/{compositeId}': CraftSkillReferenceSchema,\n\n // ===== Operational / utility =====\n 'reservedDisplayNames/{displayNameUppercase}': ReservedDisplayNameSchema,\n 'reservedRealmNames/{workingTitleUppercase}': ReservedRealmNameSchema,\n 'accountDeletionRequests/{uid}': AccountDeletionRequestV1Schema,\n 'shortLinks/{shortId}': ShortLinkSchema,\n 'feedbackAliases/{aliasId}': FeedbackAliasSchema,\n 'feedbackSubmissions/{feedbackType}/userSuggestions/{suggestionId}': UserSuggestionSchema,\n 'statusReconcileQueue/{uid}': StatusReconcileQueueEntrySchema,\n\n // ===== Trust & Safety — child-safety case spine (§A1b, §A2) =====\n 'childSafetyCaseList/{caseId}': ChildSafetyCaseListV1Schema,\n 'activeSafetyCaseAlerts/{caseId}': SafetyCaseAlertV1Schema,\n 'childSafetyCases/{caseId}': ChildSafetyCaseV1Schema,\n 'childSafetyCases/{caseId}/sourceSignals/{signalId}': ChildSafetySourceSignalV1Schema,\n 'childSafetyCases/{caseId}/decisions/{decisionId}': ChildSafetyDecisionV1Schema,\n 'childSafetyCases/{caseId}/decisions/{decisionId}/views/{viewId}': ChildSafetyDecisionViewV1Schema,\n 'childSafetyCases/{caseId}/accounts/{uid}': ChildSafetyCaseAccountV1Schema,\n 'childSafetyCases/{caseId}/accounts/{uid}/history/{historyId}': ChildSafetyCaseAccountHistoryV1Schema,\n 'childSafetyCases/{caseId}/ncmecSubmissions/{submissionId}': ChildSafetyNcmecSubmissionV1Schema,\n 'childSafetyCases/{caseId}/ncmecSubmissions/{submissionId}/files/{fileId}': ChildSafetyNcmecSubmissionFileV1Schema,\n 'childSafetyCases/{caseId}/legalProcess/{eventId}': ChildSafetyLegalProcessEventV1Schema,\n 'childSafetyOwningAliases/{aliasId}': ChildSafetyOwningAliasV1Schema,\n\n // ===== Trust & Safety — holds + resource commands (§A3) =====\n 'safetyHoldRefs/{holdRefId}': SafetyHoldRefV1Schema,\n 'safetyHoldResources/{resourceKeyHash}': SafetyHoldResourceV1Schema,\n 'safetyResourceCommands/{commandDocId}': SafetyResourceCommandV1Schema,\n 'safetyResourceCommands/{commandDocId}/authorizedRequests/{requestId}': SafetyResourceCommandAuthorizedRequestV1Schema,\n 'safetyResourceCommands/{commandDocId}/bypassRefs/{refId}': SafetyResourceCommandBypassRefV1Schema,\n\n // ===== Trust & Safety — evidence + provenance (§A4, §A6) =====\n // SafetyEvidenceManifestV1Schema is a refined ZodObject (superRefine for the H5\n // sourceKind invariant); the schema-doc generator unwraps the effect to introspect\n // its shape, so binding the refined schema here is correct.\n 'safetyEvidenceManifests/{manifestId}': SafetyEvidenceManifestV1Schema,\n 'safetyEvidenceJobs/{jobId}': SafetyEvidenceJobV1Schema,\n 'safetyEvidenceJobs/{jobId}/items/{itemId}': SafetyEvidenceJobItemV1Schema,\n 'safetyEvidenceJobs/{jobId}/disposition/{locationId}': SafetyEvidenceDispositionV1Schema,\n 'eventProvenance/{eventId}': EventProvenanceV1Schema,\n\n // ===== Trust & Safety — sagas + closure (§A5) =====\n 'quarantineSagaJobs/{caseId}': QuarantineSagaJobV1Schema,\n 'quarantineSagaJobs/{caseId}/relatedAssets/{assetId}': QuarantineSagaRelatedAssetV1Schema,\n 'ncmecSubmissionJobs/{ncmecJobId}': NcmecSubmissionJobV1Schema,\n 'accountActionCommands/{accountActionCommandId}': AccountActionCommandV1Schema,\n\n // ===== Trust & Safety — SLA monitors + heartbeat (§A8) =====\n 'safetySlaMonitors/{monitorId}': SafetySlaMonitorV1Schema,\n 'safetyMonitorHeartbeat/global': SafetyMonitorHeartbeatV1Schema,\n\n // ===== Trust & Safety — age attestation nonces (§A7) =====\n 'ageAttestationNonces/{nonceHash}': AgeAttestationNonceV1Schema,\n\n // ===== Trust & Safety — per-operator privileged-reviewer security (§A11 [M-6] / [H-17]) =====\n // Backend-only (Cloud-Functions-only readers/writers; client access denied in firestore.rules).\n 'privilegedReviewerPasskeyProfiles/{uid}': PrivilegedReviewerPasskeyProfileV1Schema,\n 'privilegedReviewerCapabilityGrants/{uid}': PrivilegedReviewerCapabilityGrantV1Schema,\n\n // ===== Trust & Safety — NCII / TAKE IT DOWN (§A11) =====\n 'nciiAllegations/{allegationId}': NciiAllegationV1Schema,\n 'takeItDownRequests/{requestId}': TakeItDownRequestRootV1Schema,\n 'takeItDownRequests/{requestId}/private/requester': TakeItDownRequesterPrivateV1Schema,\n 'takeItDownRequests/{requestId}/submissions/{submissionId}': TakeItDownSubmissionV1Schema,\n 'takeItDownRequests/{requestId}/validityDecisions/{decisionId}': TakeItDownValidityDecisionV1Schema,\n 'takeItDownRequests/{requestId}/actions/{actionId}': TakeItDownRequestActionV1Schema,\n 'takeItDownRequests/{requestId}/evidence/{evidenceId}': TakeItDownEvidenceV1Schema,\n 'nciiCases/{caseId}': NciiCaseV1Schema,\n 'nciiCases/{caseId}/allegationLinks/{allegationId}': NciiCaseAllegationLinkV1Schema,\n 'nciiCases/{caseId}/requestLinks/{requestId}': NciiCaseRequestLinkV1Schema,\n 'nciiCases/{caseId}/removalActions/{actionId}': NciiCaseRemovalActionV1Schema,\n 'nciiCases/{caseId}/blockedHashes/{hashId}': NciiBlockedHashV1Schema,\n 'nciiRetainedEvidenceInventory/{inventoryId}': NciiRetainedEvidenceInventoryV1Schema,\n // [H-01] dead-letter sink for inventory rows that could not be written to the primary\n // nciiRetainedEvidenceInventory collection. Stores the same document shape.\n 'nciiInventoryDeadLetter/{inventoryId}': NciiRetainedEvidenceInventoryV1Schema,\n 'nciiTemporaryHolds/{holdId}': NciiTemporaryHoldV1Schema,\n 'nciiRemovalJobs/{jobId}': NciiRemovalJobV1Schema,\n 'nciiRemovalJobs/{jobId}/targets/{targetKeyHash}': NciiRemovalTargetV1Schema,\n\n // ===== _config singletons (public) =====\n '_config/app': AppConfigSchema,\n '_config/futurePlans': FuturePlansDocumentSchema,\n '_config/rulesAndAgreements': RulesAndAgreementsSchema,\n // Content-pages migration (DJ ruling 2026-07-06): /terms, /privacy, and the\n // /take-it-down page copy render exclusively from these (all public pages —\n // take-it-down is a NO-LOGIN page, so its copy doc must be publicly readable).\n '_config/termsOfService': LegalPageDocumentSchema,\n '_config/privacyPolicy': LegalPageDocumentSchema,\n '_config/takeItDownPageCopy': TakeItDownPageCopySchema,\n\n // ===== _serverData singletons (server-only — Cloud-Functions-only readers, BACKEND-108) =====\n '_serverData/agePolicy': AgePolicyConfigV1Schema,\n '_serverData/nciiPolicy': NciiPolicyConfigV1Schema,\n '_serverData/privilegedReviewerSecurity': PrivilegedReviewerSecurityProfileV1Schema,\n\n // ===== _systemData singletons =====\n '_systemData/adminList': AdminListSchema,\n '_systemData/profanityList': ProfanityListSchema,\n '_systemData/reservedUsernames': ReservedUsernamesSchema,\n '_systemData/blockedFranchiseNames': BlockedFranchiseNamesSchema,\n '_systemData/appMode': AppModeMarkerSchema,\n} as const satisfies Record<string, z.ZodTypeAny>;\n\nexport type RegisteredCollectionPath = keyof typeof COLLECTION_SCHEMAS;\n\n/**\n * Doc-id field annotation: for the listed bindings, the named body field equals the\n * Firestore document id and is injected at READ time (`{ ...doc.data(), <field>: doc.id }`),\n * never persisted — the write callables store the body via `Omit<…, '<field>'>`. The bound\n * schema models the (correct) consumer/read shape, where the field is required, so a raw\n * stored doc is \"missing\" it. The drift-check injects `{ [field]: doc.id, ...data }` before\n * validating, generalizing the one-off `AdminTaskDocSchema` stored-shape workaround into a\n * single mechanism so real-callable drift-checks don't false-flag every doc-id collection.\n * The schema-doc generator ignores this map. Keys are compiler-checked against the registry.\n */\nexport const COLLECTION_DOC_ID_FIELDS = {\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTales/{taleId}/taleChapters/{chapterId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTunes/{tuneId}/tuneTracks/{trackId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}': 'uid',\n 'allWorkProjects/{workProjectId}/workProjectTelevision/{televisionId}/televisionEpisodes/{episodeId}': 'uid',\n 'allWorkProjects/{workProjectId}/guildChatChannels/{guildChatChannelId}': 'guildChatChannelId',\n // Published hall sub-items: the doc id IS the live sub-item's id; `uid` is injected at\n // read (the publish writer spreads the live doc's stored body, which has no `uid`).\n 'hallItems/{hallItemId}/tales/{itemId}': 'uid',\n 'hallItems/{hallItemId}/tunes/{itemId}': 'uid',\n 'hallItems/{hallItemId}/television/{itemId}': 'uid',\n 'activeUserNotifications/{notificationId}': 'id',\n 'activeAdminNotifications/{notificationId}': 'id',\n 'adminNotificationHistory/{notificationId}': 'archiveOccurrenceId',\n 'userProfiles/{userId}/notificationHistory/{notificationId}': 'archiveOccurrenceId',\n 'pendingNotifications/{notificationId}': 'id',\n 'statusReconcileQueue/{uid}': 'uid',\n} as const satisfies Partial<Record<RegisteredCollectionPath, string>>;\n\n/**\n * Collections that exist (in COLLECTIONS / *_SUBCOLLECTIONS or firestore.rules) but are\n * intentionally NOT bound to a schema, each with a reason. Listed EXPLICITLY so completeness is\n * enforced and nothing is silently uncovered; the registry test fails if a NEW unlisted collection\n * appears. These three are the only remaining gaps after the schema-registry binding pass:\n *\n * - userMetadata: `userProfiles/{uid}/userMetadata/notificationSettings` — a firestore.rules\n * match and `PATH_BUILDERS.userMetadata` exist, but there is no live reader/writer and no\n * notification-settings type anywhere yet. Bind once that shape is implemented.\n * - checkedOutItems: a `userProfiles/{uid}/checkedOutItems` subcollection constant with no writer,\n * reader, rule, or path-builder (the admin \"checked out items\" UI reads adminTasks by\n * `checkoutDetails.userId`, not this subcollection). Vestigial — remove once confirmed safe.\n * - feedbackDenylist: `feedbackDenylist/{deniedWord}` — Console-managed (firestore.rules §3F: no\n * callable writes it) and submitFeedback reads it via `.exists` only, so there is no field\n * contract to author a schema from. The doc id is the denied word; the body is unused.\n */\nexport const PENDING_COLLECTIONS: readonly string[] = [\n 'userMetadata',\n 'checkedOutItems',\n 'feedbackDenylist',\n // Append-only NCII case closure/reopen event rows — the doc shape is owned app-side\n // (NciiCaseV1 closure events), not modeled in ttt-core doc-schemas.\n 'closureEvents',\n] as const;\n"]}
|
|
@@ -214,7 +214,7 @@ export const UserPrivateDataAgeFieldsSchema = z.object({
|
|
|
214
214
|
// artisans — the money boundary — so collection happens there, with UI copy warning the
|
|
215
215
|
// DOB must match the user's future payout identity. Server re-derives 18+ from the entered
|
|
216
216
|
// DOB; an under-18 derivation rejects with a failure audit and stores nothing. PII —
|
|
217
|
-
// privateData only (
|
|
217
|
+
// privateData only (BACKEND-105); same no-log posture as the raw DOB (scrubber + canary).
|
|
218
218
|
attestedDateOfBirth: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(), // 'YYYY-MM-DD'
|
|
219
219
|
attestedDobRecordedAt: z.number().optional(), // epoch ms
|
|
220
220
|
attestedDobSource: z.enum(['artisanOnboarding']).optional(),
|