Support typed Advanced Truthtrance shipment commitments

Extend the existing reserve-shipment promise pipeline to base Advanced
games without Guild or optional modules. Share scope between parser, save
validation and UI. Reuse canonical Ghola normal/elite revival eligibility
and retain live BG conversion responses while proving conditional private
feasibility. Hide future-price guidance until pending responses finish.
Show exact Sardaukar/Fedaykin allocation in private executable steps.

Validation: types, lint and all 4,192 offline tests pass; production build
and all 40 HTTP tests pass. 41 focused shipment tests include 15 new cases
covering genuine Advanced setup, all five non-Guild factions and four bot
profiles, typed Ghola quota, BG allowance/cancellation/alternatives,
private views, saved continuations and production SQLite duplicate races.
Independent review found and resolved optional-module scope and pending
price-guidance issues. Browser rooms EUZZ8D4M and GWNCVCAP verified an AI No
route and human Yes with four-force/one-Sardaukar Ghola then six-force
shipment. Phone settlement controls and refresh passed. Both existing
browser room hashes/versions preserved through HTTP tests; 30 rooms added.

Full source-bound report: 20260913-advanced-shipment-final; fingerprint
6c2f29d9b3e61bf6b9544ee3a95c47538abfb05e1c3b2ae9d0a603ef0cef38dd
Broad checks ran once after focused fixes/review. No full-game AI study
or complete Advanced mode acceptance is claimed; all existing release
gates and pending Guild settlement questions remain intact.
This commit is contained in:
Quintine committed 2026-09-13 11:08:29 +10:00
1 parent 6e26ba5daa
commit 32791ed5e2
14 files changed
+902 -38

No files matched your search

+7 -2
View File
@@ -42,12 +42,17 @@ export function ShipmentPromises({
const share = shipping
? Number(next.allyPayment ?? Math.max(0, cost! - (me.spice ?? 0)))
: 0;
const elite = Number(next?.elite ?? 0);
const allocation =
elite > 0
? `, including ${elite} ${me.faction === 'emperor' ? 'Sardaukar' : me.faction === 'fremen' ? 'Fedaykin' : 'elite force' + (elite === 1 ? '' : 's')}`
: '';
const description = next
? shipping
? `Ship ${Number(next.amount)} forces to ${territory(String(next.territory)).name}, sector ${Number(next.sector)}`
? `Ship ${Number(next.amount)} forces${allocation} to ${territory(String(next.territory)).name}, sector ${Number(next.sector)}`
: next.type === 'pledgeAid'
? 'Reclaim your unused ally pledge'
: `Play ${me.hand?.find((c) => c.id === next.card)?.name ?? 'your preparation card'}${next.amount ? ` to revive ${Number(next.amount)} forces` : ' for your shipment discount'}`
: `Play ${me.hand?.find((c) => c.id === next.card)?.name ?? 'your preparation card'}${next.amount ? ` to revive ${Number(next.amount)} forces${allocation}` : ' for your shipment discount'}`
: '';
return (
<section
+4 -4
View File
@@ -8,6 +8,7 @@ import Link from 'next/link';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { CHEAP_HERO_TRAITOR } from '@/game/traitors';
import { shipmentPromiseModeSupported } from '@/game/shipment-promises';
import {
TRUTH_CARD_NAMES,
truthQuestionText,
@@ -41,8 +42,7 @@ export function Truthtrance({
shipmentMinimum < 1 ||
shipmentMinimum > 20;
const shipmentAvailable =
!g.advanced &&
!g.expansions.length &&
shipmentPromiseModeSupported(g) &&
g.phase === 5 &&
g.active === target &&
!g.players.find((p) => p.id === target)?.shipped &&
@@ -356,8 +356,8 @@ export function Truthtrance({
{!shipmentAvailable && (
<p className="notice">
Automatic enforcement currently supports the active
player’s unused shipment in the Basic game without
expansions. Select that player and finish pending
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.
</p>