From 19e554666ee4bf55dd33d162a6a1f987a699ed03 Mon Sep 17 00:00:00 2001
From: Quintine <15965533+Quintine@users.noreply.github.com>
Date: Sat, 24 Oct 2026 16:34:19 +1100
Subject: [PATCH] Admit Mirror and Stone in Basic native E3 battles
Reuse original copied-weapon and typed coalition accounting for bare Basic
Ecaz/Moritani and selected Ix. Preserve optional-module guards and physical
card identity, actual force-owner commitments and native continuations.
---
docs/CURRENT_STATUS.md | 21 +++
docs/IMPLEMENTATION_STATUS.md | 30 +++++
docs/MIRROR_WEAPON_ENGINE_AUDIT.md | 81 ++++++++++-
docs/RULE_DECISIONS.md | 2 +-
docs/STONE_BURNER_ENGINE_AUDIT.md | 10 ++
game/mirror-weapon-mode.ts | 8 +-
game/reference.ts | 18 +--
tests/basic-native-mirror-controls.test.tsx | 102 ++++++++++++++
tests/basic-native-mirror-engine.test.ts | 140 ++++++++++++++++++++
tests/fixture-basic-native-mirror.ts | 124 +++++++++++++++++
tests/fixture-battle-outcome-window.ts | 21 +++
tests/fixture-ix-revealed-weapons.ts | 2 +
tests/fixture-stone-harass.ts | 2 +
tests/ix-revealed-weapons.test.ts | 5 +-
tests/mirror-weapon-engine.test.ts | 4 +-
tests/stone-burner-bots.test.ts | 2 +
tests/stone-burner-engine.test.ts | 12 +-
tests/stone-harass-runtime.test.ts | 5 +-
18 files changed, 566 insertions(+), 23 deletions(-)
create mode 100644 tests/basic-native-mirror-controls.test.tsx
create mode 100644 tests/basic-native-mirror-engine.test.ts
create mode 100644 tests/fixture-basic-native-mirror.ts
create mode 100644 tests/fixture-battle-outcome-window.ts
diff --git a/docs/CURRENT_STATUS.md b/docs/CURRENT_STATUS.md
index 9fd64dde..f0c4a8b6 100644
--- a/docs/CURRENT_STATUS.md
+++ b/docs/CURRENT_STATUS.md
@@ -16,6 +16,27 @@ open mode gates.
## Current checkpoint and work
+**Basic native Mirror/Stone — 24 October. Prototyped / Partial.**
+Bare Basic Ecaz/Moritani families, including selected Ix, now admit the physical
+Mirror and original Stone through existing native resolution. Preserve fixed
+Ecaz accounting, actual allied typed pools, copy-first independent choices and
+physical winner retention. Basic E3 phase-module guards remain; existing
+Advanced permissions do not expand.
+
+Disjoint source/control lanes, bounded review and owner integration pass
+**17 files130/130**, types/lint/build and six actual gameplay/table-rendering
+journeys. Both coalition leads and an actual Moritani combatant copy Tooth and
+Stone; the original Ixian physical owner chooses6/9 undialed counters, and
+Moritani's five physical counters beat four despite the opposing dial9.
+Genuine six-native setup/alliance/battle admission retains explicit conserved
+board/budget/card staging. Twelve existing-profile paths accept36 proposals
+plus256 separate native continuations. Updated legacy fixtures close actual
+final-priority controls; two old allocation-guard tests now explicitly model
+unstamped battles. [Source, proof and limits](MIRROR_WEAPON_ENGINE_AUDIT.md#basic-native-e3-admission--24-october-2026).
+Optional combinations, complete modes, full AI work and comprehensive/browser/
+deployed acceptance remain unfinished. No saved-room/D1/reset/restart/deployment
+operation.
+
**Owned Ghola movement preparation — 24 October. Prototyped / Partial.**
Held physical Ghola and known/paid Box recovery now prepare exact force returns
before an unused affordable shipment and qualifying ground move. Keep normal
diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md
index 1b722e6d..9a651d84 100644
--- a/docs/IMPLEMENTATION_STATUS.md
+++ b/docs/IMPLEMENTATION_STATUS.md
@@ -1,5 +1,35 @@
# Dune implementation status
+## 24 October 2026 — Basic native Mirror and Stone
+
+Bare Basic native E3 with CHOAM/Richese, including selected Ix, now uses original
+Mirror/Stone resolution. Actual fixed Ecaz strength/losses, variable allied
+typed pools, public-only admission, physical-owner allocation and later native
+cleanup remain separate. Copy-first and user-selected physical winner retention
+are unchanged. Basic E3 phase modules remain guarded; existing Advanced no-Ix
+phase-module permission is retained.
+
+Disjoint source/control lanes, bounded review and owner integration pass17 files
+130/130, types/lint/build and six gameplay/GameTable SSR programmes across both
+coalition leads and an actual Moritani combatant. Copied Tooth/Stone remain
+independent,6/9 physical choices belong to Ix, and five Moritani counters beat
+four opposing physical counters despite total dial9. Native setup/alliance/
+battle admission is genuine; conserved battle-board, thirty-spice and original
+card staging is explicit. Twelve minimal-profile continuations accept36 actions
+plus256 separate native steps. Rendered inline choices and actual event actions
+are distinguished from direct physical-allocation component callback proof.
+
+The initial union exposed outdated final-priority fixture continuations and
+old precommit expectations. A committed-profile probe confirms the old Mirror
+failure predates this admission. Actual final Ready controls now precede result
+assertions; two conservative guard tests explicitly model unstamped legacy
+battles. New stamped cases retain real count commitments. A reserved lint
+variable is renamed; final frozen proof passes.
+[Authority, exact evidence and unfinished scope](MIRROR_WEAPON_ENGINE_AUDIT.md#basic-native-e3-admission--24-october-2026).
+No full mode/combination, browser/deployed or comprehensive assurance certificate,
+AI strategy/calibration or saved-room/D1/reset/restart/deployment operation.
+
+
## 24 October 2026 — Owned Ghola movement preparation
Basic movement witnesses use current physical Ghola force choices and exact
diff --git a/docs/MIRROR_WEAPON_ENGINE_AUDIT.md b/docs/MIRROR_WEAPON_ENGINE_AUDIT.md
index 19a9f3ec..ed9eda31 100644
--- a/docs/MIRROR_WEAPON_ENGINE_AUDIT.md
+++ b/docs/MIRROR_WEAPON_ENGINE_AUDIT.md
@@ -1,9 +1,88 @@
# Mirror Weapon: source and engine integration audit
-Audited 6 September 2026 as a proposed contract. The 28 September bounded runtime now admits canonical Mirror in CHOAM/Richese-deck classic/CHOAM/Richese battles without optional combined modules; the hook map and former blockers below describe the earlier audit, not current inactive status. Richese expansion starts remain gated.
+The [24 October Basic native follow-up](#basic-native-e3-admission--24-october-2026) is the current bare-profile boundary. Older September audits, blocker descriptions and start restrictions below are dated evidence. Complete expansion rules and publication acceptance remain gated.
**28 September ruling and runtime:** the user selected ordinary winner retention for the physical Mirror even when its copy activates Tooth or Artillery. This is an explicit product interpretation, not a located GF9 clarification. `game/effective-weapons.ts` keeps physical identity apart from copied attacks; the engine now connects copied Tooth/Stone choices, Stone comparison, custody, battle controls and legal AI in the bounded configuration.
+## Basic native E3 admission — 24 October 2026
+
+**Prototyped / Partial.** Bare Basic CHOAM/Richese plus Ecaz/Moritani now uses
+the same canonical physical Mirror and original Stone handling as supported
+Advanced tables. Selected Ix can remain present with its real Cyborg/Suboid
+pools. This supersedes the older Advanced-only native-E3 boundary below.
+The public profile admits the configured families without inspecting hands or
+sealed plans. Homeworlds, Nexus, Leader Skills, Discoveries and active Sandtrout
+remain guarded. Basic E3 with Tech Tokens or Stronghold Cards also stays outside
+this slice; existing Advanced E3 without Ix retains its prior phase-module
+permission. Mixed Advanced E3/Ix phase modules keep their existing guard.
+
+The actual battle actors, native fixed Ecaz commitment and variable allied
+forces remain separate. Copied Tooth and Stone choose before their originals,
+with original physical IDs in sealed/revealed plans. An ambiguous Stone total
+is committed by the original physical force owner, even when Ecaz selected its
+own leader and plan. Keep Basic zero support, actual typed casualties, later
+Ix substitution and native cleanup. No new numerical or timing ruling is made:
+printed copy-first, the existing provisional allocation procedure and the
+user-selected physical-Mirror winner retention stay in force.
+
+New fixtures start through genuine public Basic native setup, original cards,
+a real Nexus alliance and actual battle admission. They explicitly inherit a
+conserved controlled battle board, thirty-spice budget and original-card
+transfers; they are not unstaged acquisition or complete-game evidence. Both
+coalition leads and an actual Moritani combatant receive their own Mirror.
+Native controls remain explicit and persistent; minimal profiles use the
+current public profile and own legal plan/decision views.
+
+### Basic native source and verification
+
+The original six-faction Basic setup retains Ecaz, Ixians, CHOAM, Richese,
+Moritani and Tleilaxu, original native components and the actual Ecaz/Ix alliance.
+Before real admission, the source explicitly conserves five Ecaz and eight
+allied Ixian counters (including two Cyborgs), or replaces the opposing CHOAM
+army with five conserved Moritani counters. It inherits the labelled thirty-spice
+controlled budget and moves original physical cards between their actual
+cache/deck/hand locations. Neither the phase, alliance, battle, plan nor finished
+outcome is installed. This is genuine setup plus controlled rule-case staging,
+not an unstaged full game or a naturally played Mirror acquisition.
+
+Both coalition leads copy Tooth before the original, keep physical Mirror after
+winning and pay no Basic support. Real leader deaths supply their printed
+bounty. Copied Stone independently chooses before its original; fixed Ecaz3
+and undialed2 remain separate from the allied pool. Two real physical-count
+alternatives6/9 belong to Ix regardless of the selected plan actor; each extreme
+settles its actual winner, typed losses, native substitution and cleanup.
+Moritani's five undialed counters defeat the coalition's four despite its total
+dial9. Original card inventory and physical pools remain conserved.
+
+The final frozen batch passes **17 files130/130**, npm run check:quick,
+production build and six actual-state gameplay/GameTable SSR programmes.
+Two native Stone-allocation component callbacks retain busy no-submit and
+submit the original event/count. Copied Tooth/Stone inline GameTable controls
+are rendered persistently with busy choices and exercised through actual
+event-bound engine actions; their inline callbacks are not directly invoked.
+Twelve existing-profile continuations accept36 proposals plus256 separate
+native controls. No strategy change or strength calibration is performed.
+
+The first batch's legacy Mirror/Stone tests asserted results before the
+existing final outcome window closed. One committed-profile probe reproduces
+the old Mirror failure. Shared fixture continuations now submit the actual
+two final Ready controls; two old ambiguity guards are explicitly limited to
+legacy unstamped battles. Fresh v1 cases keep their physical commitments.
+Later narrow feedback fixes one such old guard and a reserved lint identifier.
+The final frozen source, including these repairs, passes all required checks.
+
+Private artifacts: /home/quintine/.local/share/dune/checkpoints/20261024-basic-native-mirror/,
+final frozen-integrated-4/report.json, runtime-smoke.json, private HTML/logs,
+committed-profile-baseline.log, verified-files.json and documentation-overlay.json.
+Before final prose: base49992d322f543726ad858e0bed60226711f1c32d,
+source tree512bef259fadc063d64325dfac227144b202d746d0cff8d19d4d3753ec24db06,
+2661 tracked/nonignored files unchanged throughout verification. Only four
+checkpoint-prose/reference overlays follow proof; links/evidence and reference
+syntax/keys are reviewed separately. Framework aliases/CSS stubs do not prove
+browser/visual/deployed acceptance. Full modes, optional combinations and
+comprehensive assurance remain open. No saved-room/D1/reset/restart/deployment
+operation occurs.
+
## Original phase-module composition — 16 October 2026
Selected Ix/CHOAM now preserves original Tech3+ and/or Advanced Strongholds2+
diff --git a/docs/RULE_DECISIONS.md b/docs/RULE_DECISIONS.md
index 3c8a793f..e1519ce0 100644
--- a/docs/RULE_DECISIONS.md
+++ b/docs/RULE_DECISIONS.md
@@ -903,7 +903,7 @@ dedicated retrieved worked FAQs. [Contract and remaining limits](HOMEWORLD_OCCUP
| Homeworld custody and mobility | Physical home/visitor groups, population thresholds, tariffs and transport permissions retain distinct sources; Homeworld immunity is not universal immunity. | [Homeworld rules](HOMEWORLD_RULES.md), [benefits](HOMEWORLD_BENEFITS_RULES.md), [mobility](HOMEWORLD_MOBILITY_RULES.md), [invasion](HOMEWORLD_INVASION_RULES.md), [Guild transport](GUILD_HOMEWORLD_TRANSPORT_RULES.md) |
| Homeworld effects | Keep original payment/revival/placement identities and qualification observations; observations alone do not choose an occupied-benefit owner. | [Payments](HOMEWORLD_PAYMENT_INCOME_RULES.md), [card economy](HOMEWORLD_CARD_ECONOMY_RULES.md), [Collection](HOMEWORLD_COLLECTION_RULES.md), [revival deployment](HOMEWORLD_REVIVAL_DEPLOYMENT_RULES.md), [victory reinforcement](HOMEWORLD_VICTORY_REINFORCEMENT_RULES.md), [replacement](HOMEWORLD_REPLACEMENT_RULES.md), [Tupile](HOMEWORLD_TUPILE_INTELLIGENCE_RULES.md) |
| Duke Vidal revival custody | The user selected living set-aside custody after Ecaz revives Duke; a separate Ambassador/Nexus acquisition grants battle control. Only Ecaz may revive him, including Ghola. Native repeated returns now use the separately labelled provisional identity-cohort policy, not a new publisher example or user number. Captured scope and broad combinations remain separately bounded. | [Selected custody](ECAZ_REVIVAL_RULES.md#selected-product-interpretation-28-september-2026), [current cohort policy](ECAZ_REVIVAL_RULES.md#identity-tracked-repeated-cohorts--14-october-2026) |
-| Mirror Weapon copied-card cleanup | The user selected ordinary winner retention for the physical Mirror even if its effective copy activates Tooth or Artillery. The original Tooth/Artillery cards retain their named mandatory-discard exceptions. This is a product interpretation, **not** a located publisher ruling. Independent copy-first Tooth/Stone choices and physical cleanup now have a bounded CHOAM/Richese-deck battle runtime; combined modules and full Richese games remain gated. | [Printed Mirror face and source audit](MIRROR_WEAPON_ENGINE_AUDIT.md#user-selected-cleanup-interpretation-28-september-2026) |
+| Mirror Weapon copied-card cleanup | The user selected ordinary winner retention for the physical Mirror even if its effective copy activates Tooth or Artillery. The original Tooth/Artillery cards retain their named mandatory-discard exceptions. This is a product interpretation, **not** a located publisher ruling. Independent copy-first Tooth/Stone choices and physical cleanup have a bounded CHOAM/Richese-deck runtime, including bare Basic native E3 and selected Ix with original fixed/typed coalition accounting. Basic E3 phase modules and other combined modules/full games remain gated. | [Printed Mirror face and source audit](MIRROR_WEAPON_ENGINE_AUDIT.md#user-selected-cleanup-interpretation-28-september-2026) |
| Advanced Kull specific effect | Supplied physical29/logical27 restricts the attempted Karama for a specific effect, unlike publisher Basic phase-wide wording. New signed Advanced attempts bind semantic purpose; purchase/payment and native special variants normalize, as do enhanced Prescience/advisor conversion. CHOAM effects and special-force faction powers stay distinct. Retaining turn/phase expiry is explicit provisional composition under the 14 October policy, not supplied wording. Legacy unstamped pending/restriction frames retain broad scope. Prior distinct counter, BG-before-conversion and deferred overbid selections stay. | [Source cutover and keys](CHOAM_KULL_SOURCE_UPDATE.md#advanced-specific-effect-scope--18-october-2026), [connected implementation and limits](CHOAM_KULL_DESIGN.md#advanced-effect-scope--18-october-2026) |
| Kull Wahad preview timing | User selected a **distinct eligible counter** while the interrupted physical card stays reserved, and BG Worthless interception **before conversion/discard**. Pending declaration is not a ban; only success stamps turn/phase and retains original/special once-use. Decline or prevention resumes the original once. Old `kull` stays printed-only; fresh `nexus-kull` admits native CHOAM plus classic Basic/Advanced seats, CHOAM/Ix Treachery and Nexus alone, without physical Sandtrout. Nexus Use needs actual unallied CHOAM Nexus and canonical eligible own fuel: accepted declaration spends Nexus even if prevented, fuel stays held until success. Use requires source/event/card, with no old-source action shim or proactive Kull. Verified prior printed counter saves migrate only their selection binding; no new-choice retrofit. Reservations, promises and remaining winning-payment coverage constrain fuel/counters; ordinary retained Karama payment is not a canceled Cunning effect. Priority/custody/overbid are user policy; neutral timing/spend conventions are application policy. Bounded checks/CLI/runtime/phone cases pass; broader verification is Partial and no full/public/deployed gate opens. | [Selected preview policy](CHOAM_KULL_SOURCE_UPDATE.md#user-selected-preview-timing--30-september-2026), [source/cost boundary](NEXUS_CHOAM_RULES.md#kull-source-cost-and-action-boundary), [runtime and remaining limits](CHOAM_KULL_DESIGN.md), [new evidence](NEXUS_CHOAM_RUNTIME.md#five-part-status-for-the-new-interaction) |
| Semuta full-hand exchange | User selected **Allow exchange**: acquisition followed by Semuta disposal is an atomic net-zero hand exchange at the faction limit. Existing incoming reservations still consume capacity; this does not permit an already overfull hand or settle Box/Richese purchase timing. | [Selected capacity policy](SEMUTA_SOURCE_UPDATE_20260907.md#user-selected-full-hand-exchange--30-september-2026) |
diff --git a/docs/STONE_BURNER_ENGINE_AUDIT.md b/docs/STONE_BURNER_ENGINE_AUDIT.md
index 1a9228e3..67e8778b 100644
--- a/docs/STONE_BURNER_ENGINE_AUDIT.md
+++ b/docs/STONE_BURNER_ENGINE_AUDIT.md
@@ -2,6 +2,16 @@
Audit: 2026-09-06. Scope: the canonical weapon, its revealed-plan choice and physical undialed-force comparison. No runtime files were changed in this audit. This is not a full optional-module or expansion certification.
+## Basic native E3 follow-up — 24 October 2026
+
+Bare Basic Ecaz/Moritani with CHOAM/Richese, including selected Ix, now admits
+the original Stone and physical Mirror through the existing native calculator.
+Fixed Ecaz dial/losses and undialed counters remain separate from allied typed
+pools; actual physical owners retain scalar allocation and later casualty/
+substitution controls. This changes a public configuration boundary, not Stone
+arithmetic, copy-first or provisional online timing.
+[Source, bounded proof and unfinished scope](MIRROR_WEAPON_ENGINE_AUDIT.md#basic-native-e3-admission--24-october-2026).
+
## Outcome-changing physical totals — 18 October 2026
**Prototyped / Partial.** New original battles now finish the previously guarded
diff --git a/game/mirror-weapon-mode.ts b/game/mirror-weapon-mode.ts
index 5842f39c..d0d68a7b 100644
--- a/game/mirror-weapon-mode.ts
+++ b/game/mirror-weapon-mode.ts
@@ -21,11 +21,11 @@ export function mirrorWeaponModeBlock(g: {
}): string | null {
if (!g.expansions.includes('choam') ||
g.expansions.some(id => id !== 'choam' && id !== 'ecaz' && id !== 'ix') ||
- (g.expansions.includes('ecaz') && g.advanced !== true) ||
g.players.some((p) => !supported.has(p.faction)))
- return 'Mirror Weapon needs selected CHOAM/Richese with supported native factions; Ecaz/Moritani combinations require Advanced.';
- if (g.expansions.includes('ix') && g.expansions.includes('ecaz') && (g.techTokens || g.strongholdCards))
- return 'Mixed E3 Stone/Mirror with Tech Tokens or Stronghold Cards remains outside this profile.';
+ return 'Mirror Weapon needs selected CHOAM/Richese with supported native factions.';
+ if (g.expansions.includes('ecaz') && (!g.advanced || g.expansions.includes('ix')) &&
+ (g.techTokens || g.strongholdCards))
+ return 'This E3 Stone/Mirror combination with Tech Tokens or Stronghold Cards remains outside this profile.';
if (g.homeworlds || g.nexusCards || g.leaderSkills || g.discoveries || g.sandtrout)
return 'Mirror Weapon with combined optional modules is still being integrated.';
return null;
diff --git a/game/reference.ts b/game/reference.ts
index 9e8939b1..feeb07b6 100644
--- a/game/reference.ts
+++ b/game/reference.ts
@@ -1265,7 +1265,7 @@ export const RULE_TOPICS: RuleTopic[] = [
: definition.card.effect === 'stoneBurner'
? 'Use Stone Burner in the weapon selector and review public dial/support feasibility before sealing. Clean selected CHOAM/Ix now uses visibly provisional original Stone-first then uncopied Tooth order; copy-first and physical allocation guards remain.'
: definition.card.effect === 'mirrorWeapon'
- ? 'Choose physical Mirror in a supported CHOAM/Richese-deck table, including clean selected Ix and Advanced Ecaz/Moritani. Copied Tooth or Stone chooses before its original. The user-selected winning physical-Mirror retention still applies after copied Tooth or Artillery. Original Stone/Tooth provisionally uses Stone-first order. Other profile/module and public-start gates remain.'
+ ? 'Choose physical Mirror in a supported CHOAM/Richese-deck table, including clean selected Ix and bare Basic or Advanced Ecaz/Moritani. Copied Tooth or Stone chooses before its original. The user-selected winning physical-Mirror retention still applies after copied Tooth or Artillery. Original Stone/Tooth provisionally uses Stone-first order. Other profile/module and public-start gates remain.'
: definition.card.effect === 'portableSnooper'
? 'Choose Portable Snooper as your ordinary poison defense, or use the late-defense panel after reveal before your own traitor decision. It uses ordinary winner retention and cannot stop Poison Tooth.'
: definition.card.effect === 'semutaDrug'
@@ -1405,20 +1405,20 @@ export const RULE_TOPICS: RuleTopic[] = [
: definition.card.effect === 'mirrorWeapon'
? { checklist: [
{ area: 'Implementation' as const, status: 'Partial' as const,
- detail: 'Canonical physical Mirror, copy-first answers and physical retention compose with clean selected Ixian/Tleilaxu pools and original Advanced Occupy. Public feasibility and other profile/module boundaries remain.',
- evidence: ['game/mirror-weapon-mode.ts', 'game/effective-weapons.ts', 'game/engine.ts'] },
+ detail: 'Canonical physical Mirror, copy-first answers and physical retention now compose with bare Basic native E3, both coalition leads and actual Moritani combatants, including selected Ix typed pools. Original fixed Ecaz accounting, physical-owner scalar allocation and later native cleanup remain. Other profile/module boundaries stay separate.',
+ evidence: ['game/mirror-weapon-mode.ts', 'game/effective-weapons.ts', 'game/engine.ts', 'tests/basic-native-mirror-engine.test.ts'] },
{ area: 'Player controls' as const, status: 'Partial' as const,
- detail: 'Actual weapon selectors, independent copied choices and original retention are usable. Ix original Stone/Tooth priority is visibly provisional before commitment and during revelation.',
- evidence: ['components/battle-preparation.tsx', 'components/game-table.tsx'] },
+ detail: 'Actual native Basic selectors admit Mirror. Copied Tooth/Stone choices remain explicit, persistent and busy-disabled; original event actions advance the independent queue. Physical-owner allocation callbacks retain their real event/count and busy no-submit. Inline GameTable callbacks are rendered rather than directly invoked. Ix original Stone/Tooth priority remains visibly provisional.',
+ evidence: ['components/battle-preparation.tsx', 'components/game-table.tsx', 'tests/basic-native-mirror-controls.test.tsx'] },
{ area: 'AI' as const, status: 'Partial' as const,
- detail: 'All four profiles have legal clean-Ix candidate and original/copy continuation paths. This is not strategy or difficulty calibration.',
- evidence: ['game/bots.ts', 'tests/ix-revealed-weapons.test.ts'] },
+ detail: 'Twelve existing-profile native Basic continuations across both coalition leads and Moritani accept36 proposals plus256 separate native controls. Legal Mirror commitments use only the current own view. Earlier clean-Ix paths remain. No strategy or difficulty calibration.',
+ evidence: ['game/bots.ts', 'tests/ix-revealed-weapons.test.ts', 'tests/basic-native-mirror-engine.test.ts'] },
{ area: 'Documentation' as const, status: 'Partial' as const,
detail: 'Printed copy-first, user-selected physical retention and provisional original Stone/Tooth priority are distinguished. Combined modules and full-mode acceptance remain separate.',
evidence: ['docs/MIRROR_WEAPON_ENGINE_AUDIT.md', 'docs/STONE_BURNER_ENGINE_AUDIT.md'] },
{ area: 'Verification' as const, status: 'Partial' as const,
- detail: 'Original Matrix/engine proof plus genuine native setup with explicit conserved battle staging covers Basic/Advanced, both native force pools, original/copy modes, public ambiguity and Advanced fixed/variable Occupy. Mobile and policy proof is bounded, not unstaged complete-game or final assurance certification.',
- evidence: ['tests/ix-revealed-weapons.test.ts', 'tests/fixture-ix-revealed-weapons.ts', 'tests/mirror-weapon-engine.test.ts'] },
+ detail: 'Current17-file130/130, types/lint/build and six gameplay/GameTable SSR programmes pass. Genuine six-native Basic setup/alliance/battle with explicit conserved board/budget/card staging covers Ecaz, allied Ix and Moritani copied Tooth/Stone. Original Ix owner selects6/9 physical totals and later native losses; five Moritani counters beat four despite opposing dial9. Legacy fixture controls and unstamped guards are repaired before final frozen proof. Earlier proofs remain dated; browser/deployed, full modes/combinations and comprehensive assurance stay open.',
+ evidence: ['tests/ix-revealed-weapons.test.ts', 'tests/fixture-ix-revealed-weapons.ts', 'tests/mirror-weapon-engine.test.ts', 'tests/fixture-basic-native-mirror.ts', 'tests/basic-native-mirror-engine.test.ts', 'tests/basic-native-mirror-controls.test.tsx'] },
] }
: {}),
related: [
diff --git a/tests/basic-native-mirror-controls.test.tsx b/tests/basic-native-mirror-controls.test.tsx
new file mode 100644
index 00000000..acfac852
--- /dev/null
+++ b/tests/basic-native-mirror-controls.test.tsx
@@ -0,0 +1,102 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import { registerHooks } from 'node:module';
+import { readFileSync } from 'node:fs';
+import { createElement } from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+import { viewGame, type Action, type Game } from '../game/engine';
+import { botActions } from '../game/bots';
+import { battlePlanCardOptions } from '../components/battle-preparation';
+import {
+ createBasicNativeMirrorFixture, actBasicNativeMirror as act,
+ basicNativeMirrorPlayer as player,
+} from './fixture-basic-native-mirror';
+
+const aliases = registerHooks({
+ resolve(specifier, context, next) {
+ return next(specifier === 'next/image' ? 'vinext/shims/image'
+ : specifier === 'next/link' ? 'vinext/shims/link' : specifier, context);
+ },
+ load(url, context, next) {
+ if (!url.endsWith('.module.css')) return next(url, context);
+ const css = readFileSync(new URL(url), 'utf8');
+ const classes = Object.fromEntries([...css.matchAll(/\.([a-zA-Z_][\w-]*)/g)]
+ .map(match => [match[1], match[1]]));
+ return { format: 'module', source: `export default ${JSON.stringify(classes)}`, shortCircuit: true };
+ },
+});
+const { GameTable } = await import('../components/game-table');
+aliases.deregister();
+
+const table = (game: Game, actor: string, busy = false) => renderToStaticMarkup(
+ createElement(GameTable, { game: viewGame(game, actor), busy,
+ send: async () => assert.fail('Rendering cannot submit a battle action'), onExit() {} }),
+);
+function physicalPlan(game: Game, actor: string, weapon: string): Action {
+ const view = viewGame(game, actor);
+ view.players.find(p => p.id === actor)!.bot = 'Easy';
+ const plan = botActions(view).find(action => action.type === 'battlePlan' &&
+ action.weapon === weapon && !action.defense && Number(action.support ?? 0) === 0);
+ assert.ok(plan, 'The actual Basic plan actor retains a legal plan for this physical weapon');
+ return plan;
+}
+function toothButton(html: string, label: string): string {
+ const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ const button = html.match(new RegExp(``))?.[0];
+ assert.ok(button, `The current decision retains its ${label} control`);
+ return button;
+}
+
+// These exercise actual-state rendering and event-bound engine actions. The
+// Tooth controls are inline GameTable callbacks, not separately invoked here.
+for (const role of ['ecaz', 'moritani'] as const) {
+ void test(`Basic native ${role} Mirror appears in its real selector and keeps copied Tooth choices explicit`, () => {
+ const f = createBasicNativeMirrorFixture({ owner: role, weapon: 'poisonTooth' });
+ let game = f.game;
+ const view = viewGame(game, f.owner), plan = physicalPlan(game, f.owner, f.mirror);
+ assert.equal(game.advanced, false);
+ assert.ok(battlePlanCardOptions(view, 'weapon', String(plan.leader), '', '')
+ .some(card => card.id === f.mirror));
+ const options = table(game, f.owner).match(/