Adopt the Sneak Attack shipment classification for Heighliners

A positive Moritani Sneak Attack in Shipment and Movement now accrues the
Heighliners token once for its owner through the same techIncome helper as an
ordinary off-planet arrival. The token still enforces its working phase, its
printed Guild exception and one accrual per turn, and a zero-force resolution
accrues nothing; the previous phase-5 guard is removed rather than duplicated.

This is an explicitly adopted implementation interpretation, not a retrieved
publisher ruling: the printed verb is "Send", and classifying the expressly
off-planet reserve transfer as a shipment is the supported reading already
recorded in the source note. Bene Gesserit spiritual-advisor accompaniment and
Intrusion stay gated because their ordering inherits the unresolved
arrival-timing boundary; a Spice Blow worm-ride Sneak Attack stays outside the
token's working phase.

Evidence: tests/moritani-force-leader.test.ts asserts the accrual, the
once-per-turn guard, the unchanged zero-force resolution and the altered-sector
rejection; the former unsupported-classification pin was replaced by the
adopted behaviour rather than re-pinned. The component inventory, the source
note, the pending-interpretation registry, the player reference and the status
log record the reduced boundary. Offline suite 7,797/7,797 with typecheck and
lint clean. No game, seat, saved state or deployment changes.
This commit is contained in:
Quintine committed 2026-10-07 18:40:19 +11:00
1 parent 0e1a442dca
commit 972b781d0a
8 files changed
+79 -8

No files matched your search

+1 -1
View File
@@ -306,7 +306,7 @@ This later 2026-09-06 checkpoint supersedes the preceding statements that Assass
| Robbery | One opaque physical token; original source-traced definition | Choose half the entrant's available spice rounded up, or top card; full hands draw before a private chosen discard; empty deck finishes without inventing a card | Owner reveal/choice/discard controls; own card names only; revealed face publicly inspectable | Chooses card or spice using its own private view | `tests/moritani-entry.test.ts` | Combined arrival reactions and broader timing audit; no full-game acceptance |
| Sabotage | One token; random discard and optional gift described separately | Random entrant discard, with generic public log; optional own-card gift or decline; exceptional recipient overflow rejected | Owner gift selector; no victim card name in opponent controls; spent face publicly inspectable | Declines the optional gift | `tests/moritani-entry.test.ts` | Exceptional gift overflow and combined reactions remain unsupported |
| Assassination | One token; source rule distinguishes it from advanced Assassinate Leaders | Reveal automatically selects one living verified ordinary native leader, updates death history and awards strength in spice; Zoal is 3 | Owner sees eligibility/reason before revealing; no victim picker; spent face uses shared inspector | Uses owner-projected reveal eligibility | `tests/moritani-force-leader.test.ts` | Missing/altered native pools, empty living pool, captured/foreign/special custody blocked; advanced Harkonnen tables uniformly blocked to avoid revealing capture state |
| Sneak Attack | One token; reserve entry, storm/occupancy limits and printed Aftermath exception described | Up to min(5, own reserves), using the recorded entry sector; free, without ordinary shipment/movement usage; zero resolves even when positive entry is blocked | Private maximum/reason at offer and resolution; labeled count selector and explicit Send no forces; shared face inspector | Uses projected maximum when allowed, otherwise zero | `tests/moritani-force-leader.test.ts` | Positive entry blocked for unresolved BG arrival reactions and phase-5 Heighliners interactions; exact sector choice and other combined-entry classifications remain limited |
| Sneak Attack | One token; reserve entry, storm/occupancy limits and printed Aftermath exception described | Up to min(5, own reserves), using the recorded entry sector; free, without ordinary shipment/movement usage; zero resolves even when positive entry is blocked | Private maximum/reason at offer and resolution; labeled count selector and explicit Send no forces; shared face inspector | Uses projected maximum when allowed, otherwise zero | `tests/moritani-force-leader.test.ts` | A positive entry in Shipment and Movement now accrues the Heighliners token once for its owner under an explicitly adopted shipment classification; positive entry remains blocked for unresolved BG arrival reactions, and exact sector choice and other combined-entry classifications remain limited |
The common entry record binds the original entrant, territory, sector, cause, turn, phase and continuation. Current isolated paths cover ordinary movement, shipment, Guild cross-transport, accompanying advisors and worm rides; existing Moritani or allied entry does not offer Terror. When the same arrival would already need another response/decision, the engine rejects the complete attempted entry atomically instead of silently selecting a priority. No-Field placement/reveal distinctions remain source guidance until that separate subsystem exists. Worm continuation and temporary Truthtrance overlays have dedicated coverage in `tests/moritani-entry-overlays.test.ts`; they do not establish universal reaction ordering.
+10
View File
@@ -50,6 +50,16 @@ settles, without replaying payment or force transfer. A Terror entry already in
flight and every Ambassador combination still reject. Selected decks/cache,
shared-Duke/capture, force/payment and pending-effect guards remain.
**In progress — Sneak Attack shipment classification.** A positive Moritani
Sneak Attack in Shipment and Movement now accrues the Heighliners token once
for its owner through the ordinary off-planet-arrival helper, under an
**explicitly adopted** shipment classification rather than a retrieved ruling;
a zero-force resolution accrues nothing, and the token still enforces its
working phase, Guild exception and one accrual per turn. Bene Gesserit
spiritual-advisor accompaniment and Intrusion stay gated because their ordering
inherits the unresolved arrival-timing boundary. See
[MORITANI_ASSASSINATION_SNEAK.md](MORITANI_ASSASSINATION_SNEAK.md#adopted-shipment-classification-7-october-2026).
**In progress — Tleilaxu Ambassador force return.** The last unimplemented
Ambassador effect is now wired: a placed Tleilaxu token gives its beneficiary —
the Ecaz owner or its ally — a private decision to return one to four physical
+24
View File
@@ -1,5 +1,29 @@
# Dune implementation status
## 7 October 2026 — Sneak Attack adopts the shipment classification for Heighliners
A positive Moritani Sneak Attack in Shipment and Movement now accrues the
Heighliners token once for its owner through the same `techIncome` helper as an
ordinary off-planet arrival. The token still enforces its working phase, its
printed Guild exception and one accrual per turn, and a zero-force resolution
accrues nothing; the previous phase-5 guard is removed rather than duplicated.
This is an **explicitly adopted implementation interpretation**, not a retrieved
publisher ruling: the printed verb is “Send”, and classifying the expressly
off-planet reserve transfer as a shipment is the supported reading already
recorded in the source note. The Bene Gesserit spiritual-advisor accompaniment
and Intrusion rows remain gated because their ordering inherits the unresolved
arrival-timing boundary, and a Spice Blow worm-ride Sneak Attack stays outside
the token's working phase.
Evidence: `tests/moritani-force-leader.test.ts` asserts the accrual, the
once-per-turn guard, the unchanged zero-force resolution and the altered-sector
rejection; the former "unsupported technology classification" pin was replaced
by the adopted behaviour rather than re-pinned.
`docs/COMPONENT_INVENTORY.md`, the source note and the pending-interpretation
registry record the reduced boundary. No game, seat, saved state or deployment
changes.
## 7 October 2026 — Tleilaxu Ambassador force return wired
The last unimplemented Ambassador effect is now reachable. A placed Tleilaxu
+25
View File
@@ -20,6 +20,31 @@ The proposed core behavior—bounded reserve transfer, no spice charge, no ordin
Therefore neither “Sneak Attack definitely bypasses all shipment reactions” nor “a specific FAQ explicitly orders all these reactions” is supported. An implementation may adopt the shipment composition explicitly, or gate affected combinations pending a ruling. It should not accidentally adopt one by calling or omitting a generic shipment helper.
## Adopted shipment classification, 7 October 2026
The engine now **adopts the shipment composition explicitly for the Heighliners
token**: a positive Sneak Attack in Shipment and Movement calls the same
`techIncome(g, 'heighliners', entrant)` helper used by ordinary off-planet
arrivals, so the token owner accrues its once-per-turn income and collects it
at the phase boundary. The token itself still enforces its working phase, its
printed Guild exception and one accrual per turn, and a zero-force resolution
calls nothing — the earlier phase-5 guard is removed rather than left as a
duplicate check.
This is an **explicit implementation interpretation**, not a retrieved
publisher ruling: the printed verb is “Send”, and the classification of that
off-planet reserve transfer as a shipment is the supported reading recorded in
the table above. The Bene Gesserit spiritual-advisor accompaniment and
Intrusion rows remain **gated** (`Sneak Attack combined with Bene Gesserit
arrival reactions is still being implemented`) because their ordering inherits
the unresolved arrival-timing boundary; adopting the Heighliners row does not
adopt them. A Spice Blow worm-ride Sneak Attack stays outside the token's
working phase and accrues nothing.
Evidence: `tests/moritani-force-leader.test.ts` asserts the accrual, the
once-per-turn guard, the unchanged zero-force resolution and the altered-sector
rejection; `docs/COMPONENT_INVENTORY.md` records the reduced boundary.
## Assassination pool: safe ordinary support
Ordinary live native discs held by the entrant are the straightforward pool. Killing a disc already in the Tanks again, or awarding its strength again, is not supported. Do not award Moritani a player-chosen victim. Zoal's explicit payout must survive any generic strength calculation.
+1
View File
@@ -389,6 +389,7 @@ These are unresolved in the cited records. Do not infer an answer from elapsed t
| Occupied Homeworlds | Entitlement/expiry after departure, replacement or contest; unique powers and shared income. The first-occupier/current-occupier question was already sent. | [Occupation questions](HOMEWORLD_OCCUPATION_RULES.md#questions-the-retrieved-sources-do-not-settle), [lifecycle audit](HOMEWORLD_OCCUPATION_LIFECYCLE_AUDIT.md) |
| Nexus responses and composition | Betrayal private-response timing, partial revival/payment choices, Emperor fewer-than-five, fresh advisor/storm cases, Duke restoration and remaining faction-specific combinations. Tleilaxu Secret Ally force accounting, leader slot/eligibility and force-only use remain unresolved after requested publisher/designer source searches; do not infer answers from native Tleilaxu revival or Ghola. | [Common boundaries](NEXUS_CARD_RULES.md#remaining-source-questions-and-release-boundaries), [Tleilaxu source search](NEXUS_TLEILAXU_RULES.md#source-search-follow-up) and individual faction source/runtime documents |
| Moritani Atomics after alliance change | The publisher's persistent −1 hand-limit text names Moritani and “your ally,” but not whether the penalty follows a later ally, remains on the original ally or affects both. Requested online source searches found no clarification; the alliance-change case remains gated. | [Terror source boundary](MORITANI_TERROR_RULES.md#material-gaps-and-ordinary-compositions) |
| Moritani Sneak Attack entry classification | The printed verb is “Send”; no retrieved ruling classifies the off-planet reserve transfer as a shipment for other arrival powers. The engine now **explicitly adopts** the supported shipment composition for the Heighliners token only — a positive Sneak Attack in Shipment and Movement accrues the token's once-per-turn income for its owner, with a zero-force resolution accruing nothing. Bene Gesserit spiritual-advisor accompaniment and Intrusion stay gated because their ordering inherits the unresolved arrival-timing boundary. This is an implementation interpretation, not a publisher ruling. | [Source boundary and adopted classification](MORITANI_ASSASSINATION_SNEAK.md#adopted-shipment-classification-7-october-2026) |
| Orgiz collection | Basic retains the publisher-p13 per-blow ambiguity and provisional one-transfer-per-positive-deposit mapping. Authorized supplied Advanced rulebook physical24 instead says each time Collection occurs in a territory containing spice: Advanced applies one transfer per actual positive territory Collection, only to a unique rival payer. Multiple source keys do not add transfers. Contested ownership, inconsistent/different payers and Ecaz shared lots still withhold only uncertain transfers; ordinary Collection proceeds. No new publisher ruling on those pending cases is claimed. | [Advanced source cutover and Basic boundary](DISCOVERY_PROTOTYPE.md#authorized-advanced-collection-wording) |
| Jacurutu physical dial | The user question asks whether the losing player should choose the physical normal/elite forces represented by its dial. When legal Advanced allocations produce different rewards, income remains explicitly unpaid; numeric wheel subtraction is not a ruling. | [Discovery interpretations](DISCOVERY_PROTOTYPE.md#interpretations-retained-for-refinement) |
| Testing Station contest/timing | Only sole non-advisor occupation is prototyped. Two-occupant priority/stacking remains unresolved; opening after the ordinary storm-card window is an explicit source-timing inference. Weather Control is excluded by the printed text. | [Discovery interpretations](DISCOVERY_PROTOTYPE.md#interpretations-retained-for-refinement) |
+5 -3
View File
@@ -16951,9 +16951,6 @@ function sneakAttackOptions(
)
blocked =
'Sneak Attack combined with Bene Gesserit arrival reactions is still being implemented.';
if (!blocked && g.phase === 5 && g.techTokens)
blocked =
'Sneak Attack combined with Heighliners technology is still being implemented.';
return { maximum, blocked };
}
function terrorAllianceBlocked(
@@ -17191,6 +17188,11 @@ function decideTerror(g: Game, p: Player, action: Action) {
p.reserves -= amount;
place(p, entry.territory, entry.sector, amount);
observeOccupation(g);
// A positive Sneak Attack transfers Moritani's expressly off-planet
// reserves onto the board, so it is classified as an off-planet
// shipment for the Heighliners token. The token itself enforces its
// working phase, its Guild exception and one accrual per turn.
techIncome(g, 'heighliners', p);
log(
g,
`${p.name} sent ${amount} reserves into ${territory(entry.territory).name} through Sneak Attack.`,
+1 -1
View File
@@ -2892,7 +2892,7 @@ export const RULE_TOPICS: RuleTopic[] = [
'Robbery: choose between taking half the entrant’s spice, rounded up, and drawing the top Treachery Card. If the draw exceeds your hand limit, choose a card to discard afterward; a full hand does not remove the draw option.',
'Sabotage: randomly draw and discard a Treachery Card from the entrant if possible. Then you may give that player a card of your choice from your own hand. Giving a card is optional.',
'Sneak Attack: send up to five of your reserve forces into the triggered territory at no cost, respecting storm and occupancy restrictions. This particular entry is allowed even when Atomics Aftermath is present.',
'Before revealing Sneak Attack, inspect its private available maximum and any reason positive entry is blocked. You may keep it hidden. Revealing spends the token even if you then choose Send no forces. For a supported entry, select zero through the displayed maximum; forces enter the arrival’s territory and sector without consuming your ordinary shipment or movement turn. Zero remains available when positive entry is blocked. Aftermath’s printed exception allows this reserve entry even after Atomics resolves.',
'Before revealing Sneak Attack, inspect its private available maximum and any reason positive entry is blocked. You may keep it hidden. Revealing spends the token even if you then choose Send no forces. For a supported entry, select zero through the displayed maximum; forces enter the arrival’s territory and sector without consuming your ordinary shipment or movement turn. Zero remains available when positive entry is blocked. Aftermath’s printed exception allows this reserve entry even after Atomics resolves. A positive entry during Shipment and Movement is treated as an off-planet shipment for the Heighliners token, which accrues its once-per-turn income for its owner.',
'The random Assassination token is separate from the advanced Assassinate Leaders advantage. Neither ability supplies the other’s selection or timing rules.',
],
related: [
+12 -3
View File
@@ -315,16 +315,25 @@ void test('advanced Harkonnen tables uniformly disable Assassination without exp
rejected(held, { type: 'decision', reveal: true });
});
void test('Sneak Attack rejects an altered client sector and unsupported technology classification while allowing zero', () => {
void test('Sneak Attack rejects an altered client sector and accrues Heighliners once for a positive entry while allowing zero', () => {
const revealed = decide(offered('sneakAttack'), { reveal: true });
rejected(revealed, { type: 'decision', amount: 1, sector: 9 });
const valid = decide(revealed, { amount: 1, sector: 10 });
assert.equal(player(valid, 'm').forces['arrakeen:10'], 1);
const technology = reload(revealed);
technology.techTokens = createTechTokens();
technology.techTokens.heighliners.owner = 'm';
technology.techTokens.heighliners.owner = 'a';
technology.techTokens.heighliners.spice = 2;
rejected(technology, { type: 'decision', amount: 1 });
const accrued = decide(technology, { amount: 1, sector: 10 });
assert.equal(player(accrued, 'm').forces['arrakeen:10'], 1);
assert.equal(accrued.techTokens!.heighliners.triggeredTurn, accrued.turn);
assert.equal(accrued.techTokens!.heighliners.spice, 1);
assert.equal(
accrued.log.some((line) =>
line.text.includes('Heighliners accrued 1 spice for Atreides'),
),
true,
);
const passed = decide(technology, { amount: 0 });
assert.deepEqual(passed.techTokens, technology.techTokens);
assert.deepEqual(passed.players, technology.players);