Resume native Guild cancellation after Semuta cost recovery

This commit is contained in:
Quintine committed 2026-10-16 00:28:23 +11:00
1 parent 2b8eb77e4e
commit 8386b41015
9 files changed
+450 -21

No files matched your search

+56 -15
View File
@@ -1394,7 +1394,7 @@ export type Game = {
stateSignature: string;
}
| {
kind: 'karamaCharityDiscard' | 'karamaInflationDiscard' | 'karamaBgCharityDiscard' | 'karamaBattleDiscard' | 'karamaChoamWorthlessDiscard' | 'karamaEmperorShareDiscard' | 'karamaIncomeDiscard';
kind: 'karamaCharityDiscard' | 'karamaInflationDiscard' | 'karamaBgCharityDiscard' | 'karamaBattleDiscard' | 'karamaChoamWorthlessDiscard' | 'karamaEmperorShareDiscard' | 'karamaIncomeDiscard' | 'karamaShipmentDiscard';
player: string;
card: string;
use: Extract<KaramaUse, { kind: 'cancel' }>;
@@ -5433,15 +5433,31 @@ function semutaIncomeKaramaResponse(g: Game, response: ResponseWindow): boolean
response.amount === 3 && !!purchase && purchase.owner === owner.id &&
purchase.turn === g.turn && purchase.phase === g.phase;
}
/** The printed cost is fresh while its original native transport remains unpaid. */
function semutaGuildShipmentKaramaResponse(g: Game, response: ResponseWindow): boolean {
if ((response.kind !== 'guildRate' && response.kind !== 'guildTransportPermission') ||
g.phase !== 5 || g.battle || response.owner !== byFaction(g, 'guild')?.id ||
Number(!!g.pendingShipment) + Number(!!g.pendingGuildTransport) +
Number(!!g.pendingHomeworldShipment) !== 1) return false;
if (response.kind === 'guildTransportPermission') {
if (g.pendingHomeworldShipment) validateHomeworldTransportPermission(g, response);
else if (g.pendingGuildTransport) validateGuildTransportPermissionResponse(g, response);
else return false;
} else if (g.pendingHomeworldShipment) validateHomeworldGuildRateResponse(g, response);
else if (g.pendingGuildTransport) validateGuildTransportRateResponse(g, response);
else validateGuildRateResponse(g, response);
return true;
}
type KaramaResponseDiscardContinuation = Extract<
NonNullable<Game['pendingTreacheryDiscard']>['continuation'],
{ kind: 'karamaCharityDiscard' | 'karamaInflationDiscard' | 'karamaBgCharityDiscard' | 'karamaBattleDiscard' | 'karamaChoamWorthlessDiscard' | 'karamaEmperorShareDiscard' | 'karamaIncomeDiscard' }
{ kind: 'karamaCharityDiscard' | 'karamaInflationDiscard' | 'karamaBgCharityDiscard' | 'karamaBattleDiscard' | 'karamaChoamWorthlessDiscard' | 'karamaEmperorShareDiscard' | 'karamaIncomeDiscard' | 'karamaShipmentDiscard' }
>;
function karamaResponseDiscardSignature(g: Game, c: KaramaResponseDiscardContinuation) {
const battle = c.kind === 'karamaBattleDiscard';
const worthless = c.kind === 'karamaChoamWorthlessDiscard';
const emperorShare = c.kind === 'karamaEmperorShareDiscard';
const income = c.kind === 'karamaIncomeDiscard';
const shipment = c.kind === 'karamaShipmentDiscard';
return JSON.stringify({
player: c.player, card: c.card, use: c.use,
parent: nullentropyParentSignature(g, c.resume,
@@ -5477,13 +5493,24 @@ function karamaResponseDiscardSignature(g: Game, c: KaramaResponseDiscardContinu
percentages: g.homeworldOccupiedPercentageLedger,
} : undefined,
} : undefined,
shipment: shipment ? {
reserve: g.pendingShipment, transport: g.pendingGuildTransport,
homeworld: g.pendingHomeworldShipment, custody: g.homeworlds,
occupation: g.homeworldOccupationHistory, aid: g.aid,
rate: g.guildRateBlocked, permission: g.guildTransportBlocked,
purchased: g.karamaShipping, cunning: g.nexusGuildCunningHistory?.at(-1),
active: g.active, ready: g.ready, movementRemaining: g.movementRemaining,
} : undefined,
order: g.order,
players: g.players.map(p => ({
id: p.id, faction: p.faction, ally: p.ally,
hand: p.hand.map(card => card.id), spice: p.spice,
shipped: income ? p.shipped : undefined,
physical: battle || worthless || income ? { forces: p.forces, reserves: p.reserves, tanks: p.tanks,
elites: p.elites, leaders: battle ? p.leaders : undefined } : undefined,
shipped: income || shipment ? p.shipped : undefined,
physical: battle || worthless || income || shipment
? { forces: p.forces, reserves: p.reserves, tanks: p.tanks,
elites: p.elites, leaders: battle ? p.leaders : undefined,
noField: shipment ? p.noField : undefined,
noFieldEvent: shipment ? p.noFieldEvent : undefined } : undefined,
})),
});
}
@@ -6278,7 +6305,8 @@ function treacheryDiscardIntegrity(g: Game) {
continuation?.kind === 'karamaBattleDiscard' ||
continuation?.kind === 'karamaChoamWorthlessDiscard' ||
continuation?.kind === 'karamaEmperorShareDiscard' ||
continuation?.kind === 'karamaIncomeDiscard') {
continuation?.kind === 'karamaIncomeDiscard' ||
continuation?.kind === 'karamaShipmentDiscard') {
const c = continuation, entry = batch.entries[0];
requireRule(
!g.response &&
@@ -6300,7 +6328,9 @@ function treacheryDiscardIntegrity(g: Game) {
(c.kind === 'karamaEmperorShareDiscard' &&
semutaEmperorShareKaramaResponse(g, c.use.response)) ||
(c.kind === 'karamaIncomeDiscard' &&
semutaIncomeKaramaResponse(g, c.use.response))) &&
semutaIncomeKaramaResponse(g, c.use.response)) ||
(c.kind === 'karamaShipmentDiscard' &&
semutaGuildShipmentKaramaResponse(g, c.use.response))) &&
c.use.response.owner !== c.player &&
c.resume.response?.kind === c.use.response.kind &&
JSON.stringify(c.resume.response) === JSON.stringify(c.use.response) &&
@@ -7153,6 +7183,7 @@ function semutaOfferSupported(
continuation.kind !== 'karamaChoamWorthlessDiscard' &&
continuation.kind !== 'karamaEmperorShareDiscard' &&
continuation.kind !== 'karamaIncomeDiscard' &&
continuation.kind !== 'karamaShipmentDiscard' &&
continuation.kind !== 'kaitainDiscard' &&
continuation.kind !== 'tupileCleanupDiscard' &&
continuation.kind !== 'karamaPurchaseDiscard' &&
@@ -7185,6 +7216,7 @@ function semutaOfferSupported(
if (g.homeworlds && continuation.kind !== 'kaitainDiscard' &&
continuation.kind !== 'tupileCleanupDiscard' &&
continuation.kind !== 'karamaIncomeDiscard' &&
continuation.kind !== 'karamaShipmentDiscard' &&
continuation.kind !== 'ordinaryCardDiscard' &&
continuation.kind !== 'nullentropyDiscard' &&
continuation.kind !== 'distransDiscard' &&
@@ -7269,7 +7301,8 @@ function semutaOfferSupported(
continuation.kind === 'karamaBattleDiscard' ||
continuation.kind === 'karamaChoamWorthlessDiscard' ||
continuation.kind === 'karamaEmperorShareDiscard' ||
continuation.kind === 'karamaIncomeDiscard'
continuation.kind === 'karamaIncomeDiscard' ||
continuation.kind === 'karamaShipmentDiscard'
? (continuation.kind === 'karamaBattleDiscard'
? semutaBattleKaramaResponse(g, continuation.use.response)
: continuation.kind === 'karamaChoamWorthlessDiscard'
@@ -7278,7 +7311,9 @@ function semutaOfferSupported(
? semutaEmperorShareKaramaResponse(g, continuation.use.response)
: continuation.kind === 'karamaIncomeDiscard'
? semutaIncomeKaramaResponse(g, continuation.use.response)
: ['choamCharity', 'choamInflation', 'bgCharity'].includes(continuation.resume.response?.kind ?? '')) &&
: continuation.kind === 'karamaShipmentDiscard'
? semutaGuildShipmentKaramaResponse(g, continuation.use.response)
: ['choamCharity', 'choamInflation', 'bgCharity'].includes(continuation.resume.response?.kind ?? '')) &&
!continuation.resume.decision && !continuation.resume.pendingKarama &&
!continuation.resume.phaseOpening && !g.pendingKarama &&
(!g.response || JSON.stringify(g.response) === JSON.stringify(continuation.resume.response))
@@ -7305,12 +7340,13 @@ function semutaOfferSupported(
continuation.kind === 'karamaChoamWorthlessDiscard' ||
continuation.kind === 'karamaEmperorShareDiscard' ||
continuation.kind === 'karamaIncomeDiscard' ||
continuation.kind === 'karamaShipmentDiscard' ||
(!continuation.resume.response && !continuation.resume.decision &&
!continuation.resume.pendingKarama &&
(continuation.kind === 'amalDiscard'
? continuation.resume.phaseOpening?.passed.length === 0
: !continuation.resume.phaseOpening)))) &&
!g.karamaShipping &&
(continuation.kind === 'karamaShipmentDiscard' || !g.karamaShipping) &&
(continuation.kind === 'ixAllyCard'
? !!g.currentAuctionSale && continuation.sale.origin === g.currentAuctionSale.origin &&
(continuation.sale.origin === 'normal'
@@ -7351,8 +7387,10 @@ function semutaOfferSupported(
!g.pendingArrivalOverlap && !g.pendingRevival &&
!g.ornithopter && !g.ecologicalStorm)) &&
!g.pendingExchange && !g.pendingIxAlly && !g.pendingNullentropy &&
!g.pendingAmbassador && !g.pendingTerrorEntry && !g.pendingShipment &&
!g.pendingHomeworldShipment && !g.pendingRicheseGift &&
!g.pendingAmbassador && !g.pendingTerrorEntry &&
(continuation.kind === 'karamaShipmentDiscard' ||
(!g.pendingShipment && !g.pendingHomeworldShipment)) &&
!g.pendingRicheseGift &&
((continuation.kind === 'karamaIncomeDiscard' &&
continuation.use.response.kind === 'richesePurchaseIncome') || !g.pendingRichesePurchaseIncome) &&
(continuation.kind === 'choamSaleDiscard'
@@ -7585,6 +7623,7 @@ function finishTreacheryDiscard(g: Game, claim?: { player: string; card: string
next.kind === 'karamaChoamWorthlessDiscard' ||
next.kind === 'karamaEmperorShareDiscard' ||
next.kind === 'karamaIncomeDiscard' ||
next.kind === 'karamaShipmentDiscard' ||
next.kind === 'karamaPurchaseDiscard' ||
next.kind === 'karamaPaymentDiscard') {
g.response = next.resume.response;
@@ -14224,6 +14263,8 @@ function spendKarama(g: Game, p: Player, card: Card, use: KaramaUse, kullOffered
'Kull preview cannot accept this unproven Truthtrance counter continuation.');
if (!kullOffered && beginKullAttempt(g, p, card, { kind: 'ordinary', use }, promiseProven)) return;
const used = discard(g, p, card.id);
const guildShipmentDiscard = g.semutaPreview && card.effect === 'karama' &&
use.kind === 'cancel' && semutaGuildShipmentKaramaResponse(g, use.response);
if (g.semutaPreview && card.effect === 'karama' &&
use.kind === 'cancel' &&
(use.response.kind === 'choamCharity' ||
@@ -14231,10 +14272,10 @@ function spendKarama(g: Game, p: Player, card: Card, use: KaramaUse, kullOffered
use.response.kind === 'bgCharity' || semutaBattleKaramaResponse(g, use.response) ||
semutaChoamKaramaResponse(g, use.response) ||
semutaEmperorShareKaramaResponse(g, use.response) ||
semutaIncomeKaramaResponse(g, use.response))) {
semutaIncomeKaramaResponse(g, use.response) || guildShipmentDiscard)) {
const continuation: KaramaResponseDiscardContinuation = {
kind: use.response.kind === 'choamCharity'
? 'karamaCharityDiscard'
kind: guildShipmentDiscard ? 'karamaShipmentDiscard'
: use.response.kind === 'choamCharity' ? 'karamaCharityDiscard'
: use.response.kind === 'choamInflation'
? 'karamaInflationDiscard'
: use.response.kind === 'bgCharity' ? 'karamaBgCharityDiscard'
+7 -5
View File
@@ -1201,6 +1201,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'A distinct printed Karama canceling those five ordinary native CHOAM printed or Cunning powers also offers its public cost before the original denial completes. CHOAM retains the declared fuel; a Cunning Nexus remains spent. Claim or Continue restores the same saved response and one original movement, free-revival, storm or closing-Mentat suffix. Acquiring Karama cannot return the canceled force, grant range, stop the original request, protect the storm or restore Nexus. The retained CHOAM fuel is not a discard candidate; Kull and unsupported arrival/flight parents remain separate.',
'A printed Karama canceling the Emperor’s shared gift or extra allied revival also offers that exact public cost before the denial completes. The canceled share moves no spice, forces or revival; the Emperor’s ally and extra-revival ledger are unchanged. Claim or Continue restores the saved response and finishes the cancellation once. Only the actual Semuta holder sees the private claimant choice; other seats see the neutral offer.',
'A printed Karama canceling original paid Guild shipment income, non-Ambassador Emperor auction income or Richese special-purchase income also offers its exact public cost before the native denial. The price and physical transaction have already committed: claim or Continue cannot refund spice, re-ship forces, undo cache acquisition or replay a purchase. Original Movement, next-lot inspection or the Richese purchase’s suspended controls resume once. A winner may spend the very Karama it just bought; claiming that identity does not reverse its payment. Homeworld and Ambassador payment compositions remain separate.',
'A printed Karama canceling native Guild transport permission or shipment rate now offers that exact public cost while the original reserve, cross/return or typed Homeworld declaration remains unpaid. Claim or Continue restores and applies that cancellation once. Recovering the cost never restores a denied route, retains the native discount, finances an unfunded group or repeats shipment. Ordinary movement and legal replacements remain. Independent price grants stay distinct; shipment-price activation disposal and special-stop refund binding remain separate.',
'The separate fresh semuta --homeworlds entry retains original Richese/CHOAM and classic Homeworld occupation setup with exact CHOAM and no other modules. Paid Box search, clean Distrans transfer, definite Truthtrance answers, used ordinary specials, paid Kaitain disposal, Tupile cleanup and printed Karama canceling native Guild/Emperor/Richese-purchase income offer Semuta. Native printed Kulon, Baliset, La La La, Trip to Gamont and Jubba costs also pause before their original effect: claim/pass adds one movement bonus, denies free allowance without charging/moving forces, stops the uncommitted Baliset move, returns one original board counter before the same CHOAM close, or applies protection before the same recorded storm moves. Printed Karama canceling these powers pauses separately before denial; the retained Worthless fuel is not a candidate. A canceled reactive Baliset resumes its original declared move once; canceled Kulon/La La La/Gamont/Jubba do not apply their effects. A recovered card grants no other faction CHOAM power. Kaitain private groups require commitment before selection; each Tupile holder has a separate cost. Native income denial retains payment and the original occupied-share allocation. Basic unresolved epochs, Kull, other producers and public starts remain guarded.',
'Legal completed CHOAM market sales also offer their used card in the Homeworld profile. Worthless cashout keeps its original two-spice credit; a non-Worthless duplicate keeps its three-spice credit and the original same-name witness stays held. The high-Tupile Worthless-sale prohibition still applies, including duplicate Worthless sales. Claim/pass cannot repeat payout, undo the actual reserve shipment or replace the original market close; no new bank-income interpretation is made.',
'Final Ornithopter disposal also offers its used card in the Homeworld profile after the one-group range-three or original two-group movement completes, including an early end with no useful original group. Claim/pass cannot move those counters again or replay the paid native shipment; prior-move/Hajr, advisor and Homeworld-transfer boundaries remain. Clean Sapho Once Around and unstarted Movement first/last costs likewise offer after reordering the finite unacted queue. Earlier bids/funding and physical storm order stay committed, and the same next bidder or combined turn resumes once. Cyclic auctions, partly completed turns, first-versus-Guild and late battle timing are not opened.',
@@ -1225,31 +1226,31 @@ export const RULE_TOPICS: RuleTopic[] = [
area: 'Implementation' as const,
status: 'Partial' as const,
detail:
'The Richese preview interrupts clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama canceling clean CHOAM Charity, Inflation or Bene Gesserit Charity or settling a normal auction purchase or winning bid, a completed CHOAM sale, clean Kulon, proactive or reactive La La La/Baliset and ordinary Trip to Gamont Worthless use, accepted printed Jubba before storm protection, Ix-deck Thumper/Amal and three battle discard stages, including before native Advanced Harkonnen capture. A private normal-auction or Black Market Ixian ally replacement pauses before its draw with a neutral, face-hidden offer; original payment and seller income settle once. Cache purchases retain their native allied-replacement prohibition. Ordinary definite Truthtrance answers pause whether or not another question remains reserved, and also when the answer bound a supported shipment or unsubmitted battle-plan promise. CHOAM sale income is committed before its neutral offer and the same market resumes once; Kulon adds one movement range, La La La blocks one target’s free revival, Baliset restricts the chosen player’s movement, ordinary Trip returns one selected force, and Jubba protects one CHOAM territory only after their offers. Karama’s physical cost is discarded before its neutral offer; the original response is canceled or the reserved lot settles once. Residual Poison commits one random leader death; Sapho commits its finite priority. Thumper waits before worm/spice draw; Amal restores an already-halved opening. Owner-only candidates and one physical Semuta transfer retain privacy. The user-approved full-hand exchange preserves final hand count and incoming reservations. Other Karama uses, other reactive Worthless uses, other private discards, nested responses and other pending rewards remain unfinished.',
'The Richese preview interrupts clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama canceling clean CHOAM Charity, Inflation or Bene Gesserit Charity or settling a normal auction purchase or winning bid, a completed CHOAM sale, clean Kulon, proactive or reactive La La La/Baliset and ordinary Trip to Gamont Worthless use, accepted printed Jubba before storm protection, Ix-deck Thumper/Amal and three battle discard stages, including before native Advanced Harkonnen capture. A private normal-auction or Black Market Ixian ally replacement pauses before its draw with a neutral, face-hidden offer; original payment and seller income settle once. Cache purchases retain their native allied-replacement prohibition. Ordinary definite Truthtrance answers pause whether or not another question remains reserved, and also when the answer bound a supported shipment or unsubmitted battle-plan promise. CHOAM sale income is committed before its neutral offer and the same market resumes once; Kulon adds one movement range, La La La blocks one target’s free revival, Baliset restricts the chosen player’s movement, ordinary Trip returns one selected force, and Jubba protects one CHOAM territory only after their offers. Karama’s physical cost is discarded before its neutral offer; the original response is canceled or the reserved lot settles once. Residual Poison commits one random leader death; Sapho commits its finite priority. Thumper waits before worm/spice draw; Amal restores an already-halved opening. Owner-only candidates and one physical Semuta transfer retain privacy. The user-approved full-hand exchange preserves final hand count and incoming reservations. Other Karama uses, other reactive Worthless uses, other private discards, nested responses and other pending rewards remain unfinished. Printed native Guild permission/rate costs now use a dedicated unpaid shipment continuation for reserve, cross/return and typed Homeworld sources; claim/pass applies the same denial/repricing once without delivery replay or invented funding.',
},
{
area: 'Player controls' as const,
status: 'Partial' as const,
detail:
'All seats can Continue at the neutral fresh-discard boundary; only the actual holder sees Commit. In a mixed-owner battle batch, a committed holder can inspect and select only cards discarded by another player; nonholders receive no candidates. Normal Richese starts remain gated.',
'All seats can Continue at the neutral fresh-discard boundary; only the actual holder sees Commit. In a mixed-owner battle batch, a committed holder can inspect and select only cards discarded by another player; nonholders receive no candidates. Normal Richese starts remain gated. Four current original-action390px cost/continuation journeys exercise full4 reserve claim, denied cross plus ordinary1, typed full2 all-seat decline, and poor2/full4 release then one-force full2. No overflow/browser/application error; one tool-only stale-node race was resolved with fresh evidence, not replay.',
},
{
area: 'AI' as const,
status: 'Partial' as const,
detail:
'All four AI profiles use their own projected hand to commit or pass the exact current event, and can choose only privately projected committed candidates. This is minimal legal participation, not tuned strategy.',
'All four AI profiles use their own projected hand to commit or pass the exact current event, and can choose only privately projected committed candidates. This is minimal legal participation, not tuned strategy. For both new native permission and rate cost parents, all four actual original-state profiles recover the exact cost through legal actions and preserve the original denial/repricing. No tuning or calibration.',
},
{
area: 'Documentation' as const,
status: 'Partial' as const,
detail:
'The guide distinguishes clean public ordinary-card, paid Box, Ornithopter, Distrans, definite ordinary Truthtrance answers (including queued questions, supported shipment promises and battle answers before or after plan submission/reveal), four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal and three battle batches from a private normal-auction or Black Market Ixian ally replacement, the cache replacement prohibition, privacy-neutral acknowledgements, the user-approved atomic full-hand exchange and remaining discard sources.',
'The guide distinguishes clean public ordinary-card, paid Box, Ornithopter, Distrans, definite ordinary Truthtrance answers (including queued questions, supported shipment promises and battle answers before or after plan submission/reveal), four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal and three battle batches from a private normal-auction or Black Market Ixian ally replacement, the cache replacement prohibition, privacy-neutral acknowledgements, the user-approved atomic full-hand exchange and remaining discard sources. The native Guild followup distinguishes unpaid transport from completed income and keeps existing denial/no-debt interpretations. Both original cards are actually auctioned; two extra active-price probes explicitly disclose controlled second-card acquisition. Shipment-price activation disposal/refund remains separate.',
},
{
area: 'Verification' as const,
status: 'Partial' as const,
detail:
'Genuine setup, custody, hidden-hand parity, saved JSON, authenticated SQLite continuation and legal AI participation cover clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal, a private normal-auction Ixian ally replacement and three battle discard stages. Other private producers, Karama uses, other reactive Worthless uses, pending rewards, full games and live deployment remain unverified.',
'Genuine setup, custody, hidden-hand parity, saved JSON, authenticated SQLite continuation and legal AI participation cover clean ordinary-card, paid Box, Ornithopter, Distrans, Truthtrance, four Sapho scopes, pre-leader Residual Poison, printed Karama cancellation of CHOAM Charity, Inflation or Bene Gesserit Charity or clean normal-auction purchase or winning-bid payment, completed CHOAM card sales, clean Kulon/proactive La La La/Baliset/ordinary Trip to Gamont Worthless and accepted printed Jubba Cloak, Ix-deck Thumper/Amal, a private normal-auction Ixian ally replacement and three battle discard stages. Other private producers, Karama uses, other reactive Worthless uses, pending rewards, full games and live deployment remain unverified. Current thirteen-file158/158 passes, including12 new cases. Thirty-two original-action runtime/policy paths and four original-action390px journeys pass; two separately controlled cross/typed active-price probes retain the original independent grant. No worker/D1/real-room/deployed assurance or complete-mode claim.',
evidence: [
'tests/semuta-engine.test.ts',
'tests/semuta-recovery.test.ts',
@@ -1301,6 +1302,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'tests/semuta-homeworld-emperor-share.test.ts',
'tests/semuta-homeworld-capture-karama.test.ts',
'tests/semuta-homeworld-choam-battle-karama.test.ts',
'tests/semuta-guild-transport.test.ts',
],
},
],