From 2cd2a60a36ada3c03b32b27b7e2cb6fdd2d75b80 Mon Sep 17 00:00:00 2001 From: Quintine <15965533+Quintine@users.noreply.github.com> Date: Tue, 27 Oct 2026 19:13:48 +1100 Subject: [PATCH] Support early Charity Truthtrance commitments --- components/truth-charity-promise.tsx | 8 +- components/truthtrance.tsx | 6 +- docs/CURRENT_STATUS.md | 15 +- docs/IMPLEMENTATION_STATUS.md | 21 ++- docs/RULE_DECISIONS.md | 15 +- docs/TRUTHTRANCE_CHARITY.md | 37 ++++- game/engine.ts | 29 ++-- game/reference.ts | 12 +- game/truthtrance.ts | 6 +- tests/fixture-truth-charity-early.ts | 71 ++++++++++ tests/truth-charity-early-controls.test.tsx | 76 +++++++++++ tests/truth-charity-early-runtime.test.ts | 143 ++++++++++++++++++++ 12 files changed, 407 insertions(+), 32 deletions(-) create mode 100644 tests/fixture-truth-charity-early.ts create mode 100644 tests/truth-charity-early-controls.test.tsx create mode 100644 tests/truth-charity-early-runtime.test.ts diff --git a/components/truth-charity-promise.tsx b/components/truth-charity-promise.tsx index 7f28812d..db4fb710 100644 --- a/components/truth-charity-promise.tsx +++ b/components/truth-charity-promise.tsx @@ -10,7 +10,8 @@ type Props = { game: GameView; busy: boolean; send: (action: Action) => void }; export function TruthCharityPromise({ game, busy, send }: Props) { const own = game.truthCharityPromises.filter(promise => promise.turn === game.turn && promise.player === game.me); if (!own.length) return null; - const guide = game.truthCharityGuide, actor = game.me, turn = game.turn, action = guide?.action; + // A later-phase forecast never becomes a current action before Charity opens. + const guide = game.phase === 2 ? game.truthCharityGuide : null, actor = game.me, turn = game.turn, action = guide?.action; const signature = JSON.stringify(action), event = action?.charityPromiseEvent; const canAct = () => { const me = game.players.find(player => player.id === actor); @@ -34,11 +35,12 @@ export function TruthCharityPromise({ game, busy, send }: Props) { return

Your Charity promises

-

Yes requires an actual eligible claim after the answer; No forbids claiming during the rest of this Charity phase. Earlier claims do not count.

+

Yes requires an actual eligible claim after the answer; No forbids claiming during this Charity phase. Earlier claims do not count.

+ {game.phase < 2 &&

Charity has not opened yet. The current turn and its original decisions continue; any claim guide appears only when Charity is available.

} {guide && action?.type === 'bribe' &&

The quoted payment can make you eligible for Charity. You pay immediately; the other player receives the bribe at the start of Mentat Pause.

} {guide && action &&