From 74544567558bebbe3aefcd6f8afbbdfa9cf54ef7 Mon Sep 17 00:00:00 2001 From: Quintine <15965533+Quintine@users.noreply.github.com> Date: Sun, 13 Sep 2026 11:29:05 +1000 Subject: [PATCH] Add verified Truthtrance hand inventory questions Players can ask total-hand and primary-role card-count comparisons using the existing count controls and compound facts. Component presentation shares the same default-role classification, including canonical Richese cards, Ix alternate uses, and Ecaz slot-only specials. Only the respondent receives the verified aggregate answer; current facts do not impose future custody promises. Eight new tests cover all 60 catalog cards, real engine actions, malformed input, private worlds, all four bots, JSON continuation, and a legal custody transfer. Expanded production-room SQLite cases cover restored total/category/compound facts, suspended auction state, and one winning concurrent answer/discard. Independent review's two copy issues were fixed before broad verification. Validation: types, lint and 4,200 offline tests passed; production build passed; 40 HTTP tests passed. One stable broad run (check 123036 ms, build 6505 ms, integration 23467 ms). Browser room LC3E55GY verified combined role counts, total hand size, invalid-input feedback and refresh at 390px phone width. All 33 pre-integration rooms preserved unchanged; HTTP checks added 30 rooms. No complete-mode, full-game or publication gate opened. Private report: 20260913-hand-inventory-final/report.json Source fingerprint: c6a69a9e69941cdd1e5734d92afedbf10d31fda36c91d26ca7e15f4fb7c59b18 Efficiency pilot milestone 3: aggregate counter 58,695,053 to 59,144,653 at completed verification = 449,600 tokens, including context/coordination overhead. Two bounded workhorse-model helpers, reused UI and SQLite fixtures, one browser room. Counter is not monetary cost and this differently sized batch does not establish a savings percentage. Final Git/push overhead follows this sample. --- components/truthtrance-card-count.tsx | 76 +++- components/truthtrance.tsx | 38 +- docs/CURRENT_STATUS.md | 6 + docs/EFFICIENCY_PILOT.md | 16 +- docs/IMPLEMENTATION_STATUS.md | 21 ++ docs/RULE_DECISIONS.md | 1 + docs/TRUTHTRANCE_HAND_INVENTORY.md | 62 ++++ game/card-category.ts | 40 +++ game/card-presentation.ts | 13 +- game/reference.ts | 61 ++++ game/truthtrance-hand-inventory.ts | 88 +++++ game/truthtrance.ts | 21 +- tests/truthtrance-hand-inventory.test.ts | 431 +++++++++++++++++++++++ tests/truthtrance-spice-recovery.test.ts | 257 ++++++++------ 14 files changed, 980 insertions(+), 151 deletions(-) create mode 100644 docs/TRUTHTRANCE_HAND_INVENTORY.md create mode 100644 game/card-category.ts create mode 100644 game/truthtrance-hand-inventory.ts create mode 100644 tests/truthtrance-hand-inventory.test.ts diff --git a/components/truthtrance-card-count.tsx b/components/truthtrance-card-count.tsx index 8d082cb5..eb831d77 100644 --- a/components/truthtrance-card-count.tsx +++ b/components/truthtrance-card-count.tsx @@ -4,29 +4,56 @@ import { useId } from 'react'; import { Input } from '@/components/ui/input'; import { TRUTH_CARD_NAMES } from '@/game/truthtrance'; import type { CardCountFact } from '@/game/truthtrance-card-count'; +import { + HAND_INVENTORY_LABELS, + type HandInventoryFact, +} from '@/game/truthtrance-hand-inventory'; -export function CardCountFields({ +export function CardCountFields({ value, onChange, }: { - value: CardCountFact; - onChange: (fact: CardCountFact) => void; + value: T; + onChange: (fact: T) => void; }) { const id = useId(); const invalid = !Number.isSafeInteger(value.value) || value.value < 0; return ( <> - + {value.kind === 'handCount' ? ( + + ) : ( + + )}

- Counts copies of this exact named card in the player’s hand now. Cards - in the deck, discard pile, or a separate cache do not count. The answer - reveals only whether the comparison is true. + {value.kind === 'handCount' + ? 'Counts copies of this exact named card' + : value.category === 'all' + ? 'Counts all physical cards' + : 'Counts physical cards of the selected primary role'}{' '} + in the player’s hand now. Cards in the deck, discard pile, or a separate + cache do not count. The answer reveals only whether the comparison is + true.

+ {value.kind === 'handInventory' && value.category !== 'all' && ( +

+ Primary roles follow the cards: Weirding Way is a weapon and Chemistry + is a defense. Worthless cards stay separate, including for Bene + Gesserit or CHOAM. Alternate uses and faction powers do not change + this count. +

+ )} {invalid && (

Automatic enforcement currently supports the active player’s unused shipment in base Basic games and base - Advanced games without Guild or optional modules. Select that player and finish pending - decisions first. Earlier questions and other rules - configurations remain unfinished. + Advanced games without Guild or optional modules. Select + that player and finish pending decisions first. Earlier + questions and other rules configurations remain + unfinished.

)}

@@ -442,16 +445,23 @@ export function Truthtrance({ compare: 'gte', value: 2, } - : e.target.value === 'spice' + : e.target.value === 'handInventory' ? { - kind: 'spice', + kind: 'handInventory', + category: 'all', compare: 'gte', - value: 6, - } - : { - kind: 'traitor', - leader: g.allLeaders[0].id, + value: 2, } + : e.target.value === 'spice' + ? { + kind: 'spice', + compare: 'gte', + value: 6, + } + : { + kind: 'traitor', + leader: g.allLeaders[0].id, + } : old, ), ) @@ -461,6 +471,9 @@ export function Truthtrance({ +