From 26be6fd8ee5580f270d0616d5aed77412af36319 Mon Sep 17 00:00:00 2001 From: Quintine <15965533+Quintine@users.noreply.github.com> Date: Wed, 28 Oct 2026 19:28:19 +1100 Subject: [PATCH] Support Sapho replay and public cache questions --- README.md | 10 ++- components/mixed-shipment-fields.tsx | 4 +- components/truthtrance-knowledge.tsx | 14 +++- docs/CURRENT_STATUS.md | 17 ++++ docs/JUICE_OF_SAPHO_RUNTIME.md | 23 ++++- docs/RULE_DECISIONS.md | 16 ++++ docs/TRUTHTRANCE_KNOWLEDGE.md | 15 ++++ game/engine.ts | 5 +- game/reference.ts | 6 +- game/sapho-movement-order.ts | 12 ++- game/truthtrance-knowledge.ts | 22 ++++- tests/sapho-movement-order.test.ts | 4 +- tests/sapho-movement-replay.test.ts | 84 +++++++++++++++++++ tests/sapho-self-last-order.test.ts | 2 +- tests/truthtrance-cache-lot-controls.test.tsx | 75 +++++++++++++++++ tests/truthtrance-cache-lot-knowledge.test.ts | 53 ++++++++++++ tests/truthtrance-cache-lot-runtime.test.ts | 53 ++++++++++++ 17 files changed, 393 insertions(+), 22 deletions(-) create mode 100644 tests/sapho-movement-replay.test.ts create mode 100644 tests/truthtrance-cache-lot-controls.test.tsx create mode 100644 tests/truthtrance-cache-lot-knowledge.test.ts create mode 100644 tests/truthtrance-cache-lot-runtime.test.ts diff --git a/README.md b/README.md index b35bac6f..e46b1612 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,12 @@ During play, **Public deals** lets two to six human seats record terms, accept or decline an offer, and agree to release it. Every party must accept, and every pair of parties must be nonallied when the offer is made or accepted. Terms are visible to the -table and rely on players to honor them; the game does not interpret promises -or determine impossibility. An optional immediate spice payment is executed -using the normal bribe rules when the final participant accepts. AI negotiation -and enforcement of future promises remain unfinished. See +table and rely on players to honor free-text terms. An optional immediate spice +payment is executed using the normal bribe rules when the final participant +accepts. A structured payment may instead be due on the current or a later +turn; the payer can pay it early or on the due turn. The provisional payment +feasibility and expiry rules cover supported cases, while free-text enforcement, +broader combinations and AI negotiation remain unfinished. See [public deals](docs/PUBLIC_DEALS.md). For the provisional two-person setup, the host enables **Two players, two diff --git a/components/mixed-shipment-fields.tsx b/components/mixed-shipment-fields.tsx index 61748aef..095ae2b7 100644 --- a/components/mixed-shipment-fields.tsx +++ b/components/mixed-shipment-fields.tsx @@ -67,6 +67,7 @@ export function TruthFactFields({ value: fact, game, target, onChange }: { stormForecast: { kind: 'stormForecast', compare: 'gte', value: 1 }, spicePeek: { kind: 'spicePeek', value: 'worm' }, auctionPeek: { kind: 'auctionPeek', name: 'Shield' }, + cacheLot: { kind: 'cacheLot', name: 'Shield' }, ixPoolPeek: { kind: 'ixPoolPeek', name: 'Shield' }, presciencePeek: { kind: 'presciencePeek', field: 'leader', name: 'None' }, spice: { kind: 'spice', compare: 'gte', value: 6 }, @@ -89,6 +90,7 @@ export function TruthFactFields({ value: fact, game, target, onChange }: { + @@ -106,7 +108,7 @@ export function TruthFactFields({ value: fact, game, target, onChange }: { : fact.kind === 'noFieldValue' ? : fact.kind === 'forceCount' ? player.id === target)!} onChange={onChange} /> : - fact.kind === 'prediction' || fact.kind === 'stormDial' || fact.kind === 'stormForecast' || fact.kind === 'spicePeek' || fact.kind === 'auctionPeek' || fact.kind === 'ixPoolPeek' || fact.kind === 'presciencePeek' ? + fact.kind === 'prediction' || fact.kind === 'stormDial' || fact.kind === 'stormForecast' || fact.kind === 'spicePeek' || fact.kind === 'auctionPeek' || fact.kind === 'cacheLot' || fact.kind === 'ixPoolPeek' || fact.kind === 'presciencePeek' ? : fact.kind === 'spice' ? <>

In Basic Bidding, this asks whether the named card is in the Ixian’s recorded inspected auction pool. If that knowledge is unavailable, the answer is I don’t know. Only the answer is published; the pool itself remains private.

+ ) : value.kind === 'cacheLot' ? ( + <> + +

This asks about the current public Richese cache auction card in Basic play. If that auction is unavailable, the answer is I don’t know. Only the answer is published.

+ ) : value.kind === 'auctionPeek' ? ( <>