Files
Dune/components/truthtrance-face-dancer.tsx
T
Quintine 6ea691255a Add verified current Face Dancer questions to Truthtrance
Ask about a currently held unrevealed printed identity through shared facts
and AND/OR authoring. Keep ordinary Traitor meaning separate, candidate
identities public and only the aggregate answer published. Existing answer,
physical disposal and continuation flow need no new AI strategy.

Verified: 12 affected offline files86/86, types/lint and production build;
twelve actual field/question/gameplay/GameTable SSR journeys and sixteen legal
profile answers. Native Basic/Advanced sources and actual Mentat replacement
prove a current Yes creates no future reveal or retention promise.

Existing mixed-shipment admission stays unchanged. No saved-room, D1, reset,
restart or deployment operation; broader Truthtrance/mode assurance remains.
2026-10-24 19:15:46 +11:00

62 lines
2.1 KiB
TypeScript

'use client';
import { DUKE_VIDAL_ID } from '@/game/duke-vidal';
import { CHEAP_HERO_TRAITOR } from '@/game/traitors';
import { parseFaceDancerFact, type FaceDancerFact } from '@/game/truthtrance-face-dancer';
export function FaceDancerFactFields({
value,
leaders,
onChange,
}: {
value: FaceDancerFact;
leaders: readonly { id: string; name: string }[];
onChange: (fact: FaceDancerFact) => void;
}) {
const identities = [
...leaders.filter((leader) => leader.id !== DUKE_VIDAL_ID && leader.id !== CHEAP_HERO_TRAITOR),
{ id: CHEAP_HERO_TRAITOR, name: 'Cheap Hero / Heroine' },
];
const allowed = identities.map((identity) => identity.id);
let error: string | null = null;
try { parseFaceDancerFact(value, allowed); }
catch (cause) { error = cause instanceof Error ? cause.message : 'Choose a printed Face Dancer identity.'; }
return (
<>
<label>
Face Dancer identity
<select
aria-label="Face Dancer identity"
value={value.leader}
aria-invalid={!!error}
onChange={(event) => {
try {
onChange(parseFaceDancerFact({ kind: 'faceDancer', leader: event.currentTarget.value }, allowed));
} catch { return; }
}}
>
{identities.map((identity) => (
<option key={identity.id} value={identity.id}>{identity.name}</option>
))}
</select>
</label>
<p className="fine">
This asks whether the respondent currently holds an unrevealed Face
Dancer for this printed identity. A revealed, absent or returned card
means No.
</p>
<p className="fine">
This is a current fact at the answer, not a promise to reveal a Face
Dancer later. Ordinary traitor questions still ask only about ordinary
Traitor Cards.
</p>
<p className="fine">
Only the aggregate Truthtrance answer is published. This does not
physically reveal a Face Dancer or identify which part of an AND/OR
claim is true.
</p>
{error && <p className="notice" role="alert">{error}</p>}
</>
);
}