Add Kwisatz Haderach component inspection

Connect an original companion face and enlarged rules to the private Atreides panel and battle composer, authorized full-plan inspection, public revealed plans and an internal reference topic. Private loss progress and availability come only from the existing owner projection; plan components receive only inclusion. Rules calculations, save shape, AI strategy and mode gates remain unchanged.

Add focused projection, sealed/revealed rendering, JSON restoration, private-status and asset regressions. All 4950 offline tests, types, lint and production build pass. Independent privacy/rules review found no material findings. Browser checks verify reference opening, loaded artwork, Escape/Close focus return, mobile bounds and keyboard scrolling to the final rule. The focusable scroll region has a documented narrow lint exception. Earlier image-convention and focusability lint failures are retained in private evidence. HTTP tests are unnecessary for this presentation-only change.

All 1373 rooms, 2883 seats and original auxiliary rows remain unchanged; SQLite integrity and foreign keys pass. Existing server reused without restart. Screenshot capture, complete live Advanced browser acceptance and final manufactured-component/art verification remain open. No rules gate is opened by this checkpoint.

Private evidence: 20260921-kwisatz-inspection.
Verified source tree: 1181471eed47b86390882999a2ffce0db6a44b1379c7e8f7fc406bef39a94179
This commit is contained in:
Quintine committed 2026-09-21 09:00:51 +10:00
1 parent ed53eb7d76
commit 66c41b2af5
16 files changed
+341 -24

No files matched your search

+7 -2
View File
@@ -1,6 +1,7 @@
'use client';
import { EcazSetup } from './ecaz-setup';
import { StormCardInspector, StormCardLogInspector } from './storm-cards';
import { KwisatzInspector } from './kwisatz-inspector';
import { LobbyBotControls } from './lobby-bot-controls';
import { IxRicheseTechnology } from './ix-richese-technology';
import { nexusGuildCunningAction, nexusGuildCunningActive, nexusGuildMovementAvailable, nexusGuildShipmentAvailable, nexusGuildSkipShipmentAction } from '@/game/nexus-guild-cunning-options';
@@ -1198,7 +1199,7 @@ export function GameTable({
</p>
)}
{me.kwisatz && (
<p className="fine">
<div className="space-y-2"><p className="fine">
Kwisatz Haderach:{' '}
{me.kwisatz.dead
? 'awaiting revival'
@@ -1209,6 +1210,8 @@ export function GameTable({
? ` · used in ${combatName(me.kwisatz.usedAt)} this turn`
: ''}
</p>
<KwisatzInspector state={me.kwisatz} usedTerritoryName={me.kwisatz.usedAt ? combatName(me.kwisatz.usedAt) : undefined} />
</div>
)}
{g.stormForecast !== null && (
<div className="space-y-2">
@@ -4688,7 +4691,7 @@ export function GameTable({
</p>
)}
{me.kwisatz && (
<label>
<div className="space-y-2"><label>
<input
type="checkbox"
checked={kwisatz}
@@ -4703,6 +4706,8 @@ export function GameTable({
/>
Use Kwisatz Haderach (+2; prevents traitors)
</label>
<KwisatzInspector state={me.kwisatz} usedTerritoryName={me.kwisatz.usedAt ? combatName(me.kwisatz.usedAt) : undefined} battle={{ territory: g.battle.territory, blocked: g.battle.kwisatzBlocked }} />
</div>
)}
{g.battle.fullPlan?.target === me.id && (
<p className="notice">