From 66c41b2af537a0902e6ce881a9ea0375ded41cb0 Mon Sep 17 00:00:00 2001 From: Quintine <15965533+Quintine@users.noreply.github.com> Date: Mon, 21 Sep 2026 09:00:51 +1000 Subject: [PATCH] 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 --- components/battle-component-inspection.tsx | 6 +- components/game-table.tsx | 9 ++- components/kwisatz-inspector.tsx | 73 +++++++++++++++++++++ components/private-battle-plan.tsx | 1 + components/revealed-battle.tsx | 1 + components/rules-reference.tsx | 2 + docs/COMPONENT_INVENTORY.md | 8 +++ docs/CURRENT_STATUS.md | 40 +++++------ docs/IMPLEMENTATION_STATUS.md | 11 ++++ docs/KWISATZ_INSPECTION.md | 54 +++++++++++++++ game/kwisatz-display.ts | 37 +++++++++++ game/reference.ts | 21 +++++- public/art/leaders/kwisatz-generation.json | 12 ++++ public/art/leaders/kwisatz-haderach-v1.png | Bin 0 -> 2445712 bytes tests/kwisatz-inspection.test.tsx | 39 +++++++++++ tests/kwisatz.test.ts | 51 ++++++++++++++ 16 files changed, 341 insertions(+), 24 deletions(-) create mode 100644 components/kwisatz-inspector.tsx create mode 100644 docs/KWISATZ_INSPECTION.md create mode 100644 game/kwisatz-display.ts create mode 100644 public/art/leaders/kwisatz-generation.json create mode 100644 public/art/leaders/kwisatz-haderach-v1.png create mode 100644 tests/kwisatz-inspection.test.tsx diff --git a/components/battle-component-inspection.tsx b/components/battle-component-inspection.tsx index 0eeec47f..eaabb119 100644 --- a/components/battle-component-inspection.tsx +++ b/components/battle-component-inspection.tsx @@ -1,6 +1,7 @@ 'use client'; import { CardInspector } from './card-inspector'; +import { KwisatzInspector } from './kwisatz-inspector'; import { LeaderInspector, type LeaderDisplayIdentity, @@ -12,16 +13,19 @@ export function BattleComponentInspection({ cards, leader, playerName, + kwisatz, }: { cards: readonly VisibleCard[]; leader?: LeaderDisplayIdentity; playerName: string; + kwisatz?: boolean; }) { - if (!cards.length && !leader) return null; + if (!cards.length && !leader && !kwisatz) return null; return (
Inspect {playerName}’s plan components
+ {kwisatz && } {leader && (
{leader.name} diff --git a/components/game-table.tsx b/components/game-table.tsx index 30ae86ce..c650d5f0 100644 --- a/components/game-table.tsx +++ b/components/game-table.tsx @@ -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({

)} {me.kwisatz && ( -

+

Kwisatz Haderach:{' '} {me.kwisatz.dead ? 'awaiting revival' @@ -1209,6 +1210,8 @@ export function GameTable({ ? ` · used in ${combatName(me.kwisatz.usedAt)} this turn` : ''}

+ +
)} {g.stormForecast !== null && (
@@ -4688,7 +4691,7 @@ export function GameTable({

)} {me.kwisatz && ( -