Files
Dune/docs/JUICE_OF_SAPHO_ENGINE_AUDIT.md
T
2026-09-08 07:37:52 +10:00

18 KiB

Juice of Sapho: ordering and continuation audit

7 September implementation follow-up: JUICE_OF_SAPHO_RUNTIME.md records bounded first/last auction and movement handlers. This earlier audit remains the source/timing baseline; battle aggressor and other timing modes remain unfinished.

Audited 6 September 2026. Source and code review only. No runtime, card activation, AI or component changes were made. This plan covers all three printed modes; the existing isolated Once Around helper is not full implementation.

Verified instructions and sources

The canonical physical card is richese-juice-of-sapho, Special. I visually reread /tmp/dune-rules/choam-sapho-reading.png, derived from the component photograph whose provenance and hash are recorded in RICHESE_COMPONENTS.md. Photographer, upload date and complete printing history remain unverified; this is evidence of visible publisher text, not retailer rules commentary.

The face permits one choice: become the aggressor in a battle, go first in a phase/action requiring turn order, or go last in one, explicitly ahead of Guild's claim to last position. Play occurs in the applicable phase when intervening, followed by discard. It does not change storm location, seating circles, the identity of eligible participants or the number of actions/bids granted.

Fresh official-domain search corroborated the CHOAM/Richese FAQ, p11: Sapho can put a player last in a Richese Once Around auction. Local publisher-authored mirror /tmp/dune-rules/choam-lelekan-mirror.pdf/.txt also supplies p5: each bidder gets one opportunity; Richese must outbid, not match, the high bidder. Silent bidding is simultaneous, with storm-order ties. Page6 separately controls the subsequent normal-auction opener after Black Market. No retrieved primary answer gives Sapho a second bid, changes Silent tie priority or lets Richese reclaim last position after Sapho.

The base Guild sheet/rules p20 grants one combined shipment/movement turn, optionally between other players' turns, leaving everyone else's sequence intact. The same rulebook's battle section gives the aggressor ties. These ordinary rules compose with a local Sapho exception; they do not support permanently rewriting storm order. The November 2020 FAQ p8 gives storm order for simultaneous Truthtrance claims, but is not a general Sapho-versus-every-card precedence ruling. Fresh searches found no additional official Sapho-specific answer.

Core model: scope the exception, preserve completed work

Keep g.order as physical storm order. It is consumed by too many unrelated systems to serve as an editable Sapho queue. Bind one use to an explicit scope/event and one mode, and discard the exact activating card atomically with the accepted change. Never reinsert a completed turn, erase an accepted bid, reset a once-per-turn shipment flag, refund a settled payment or replay phase initialization.

Recommended action shape: {type:'card',card,mode:'first'|'last'|'aggressor',scope,event}. Derive owner and eligible participants on the server. A battle scope must identify an existing actual battle; a bidding scope identifies the current lot; phase-scoped changes have a fresh phase event. An optional sub-action event may identify a separately ordered unresolved queue. Reject unknown or expired scopes without consuming the card. Do not silently broaden an action-level request into a phase-long effect.

Use a shared immutable ordered-opportunity model containing stable event, eligible IDs, remaining IDs, completed IDs, current actor and whether the current unit has begun. Movement/Once Around can then express moving an uncompleted participant to the beginning/end of the remaining sequence. Normal auctions need a cyclic adapter; simultaneous actions need no artificial ordering adapter. Store an accepted override until its scope completes, then remove it. JSON recovery must preserve both the override and the original continuation.

“Go first” after others already completed an action cannot undo them. A defensible forward-only interpretation is first among remaining opportunities. Whether the broad face permits interrupting a partly completed player's combined shipment/movement turn is materially different and not settled by the retrieved source; see the boundary below.

All printed modes and applicable systems

Mode / context Required behavior and implementation boundary
Aggressor in an actual battle Set that battle's aggressor to the card holder, who must be one of its combatants. Preserve territory, opponent, committed plans, battle event and all preparation/response state. The change is local to this battle; it does not grant the right to schedule all remaining battles first.
First/last for Shipment and Movement Reorder the still-uncompleted combined turns in movementRemaining. Preserve all shipped/moved counters, current card movement allowances, No-Field events and arrival reactions. This grants sequence priority, not free shipping or another group. The last override remains last even if Guild subsequently chooses to wait.
First/last for Battle phase scheduling Maintain a separate battle-phase priority order for unresolved eligible combatants and derive the next chooser from it. This is distinct from the single-battle aggressor mode. Do not repeat already resolved battles or move a spectator into a battle. Storm-based pair orientation and the chosen battle's aggressor must be decoupled where necessary.
First/last in a Once Around lot Reorder eligible, not-yet-acted bidders in that lot. The existing moveRicheseBidderLast covers the confirmed last case and correctly allows it after Richese. Add the symmetrical first operation. Do not restore owner-last after the card acts. The bidder still has exactly one raise/pass opportunity.
First/last in normal bidding A normal auction is cyclic, not one pass around the table. At an unopened lot, a changed opener/local cycle is straightforward. During an open lot, define a finite current bidding opportunity/circuit before moving a bidder; preserve high bid, bidder, passes, funding and subsequent bidder rotation. Do not treat “last” as an irrevocable final purchase right. Mid-cycle duration is a material source boundary below.
First/last for the Bidding phase The phase contains declaration, optional Black Market, Ix inspection, separate lots and purchase reactions. A phase-level bidder-order override must persist across its intended lots without displacing mandatory faction procedures. Do not reinterpret this as moving the Richese cache-first/cache-last declaration or Black Market prelude; those order lots/effects, not the holder's player turn. Scope duration versus ordinary opener rotation needs a deliberate contract.
Silent auction Its submitted packets may arrive sequentially online, but the actual bids are simultaneous. There is no ordinary first/last bidding opportunity to move, and no authorized look at earlier bids. Do not change its separate storm tie order or reveal bids early. Block a no-effect first/last choice with an explanation rather than consume Sapho.
Other ordered phases/actions Route each genuinely ordered participant queue through the same scope adapter: for example, a future storm-ordered Extortion payer sequence. Eligibility and ownership remain unchanged. Single-owner powers, physical storm sector traversal, simultaneous dials, ordinary ready acknowledgements and unordered simultaneous settlement are not extra player turns that Sapho creates. No claim of full mode coverage is justified until every implemented ordered action is inventoried.

Existing hook hazards

Movement and Guild

beginPhase copies g.order into movementRemaining. movementTurn opens guildTiming before assigning the next actor; chooseGuildTiming(false) currently appends Guild to the entire remaining array. That append would overtake a Sapho-last holder unless it explicitly inserts Guild before the protected last participant. guildTiming's next/following, the response's take, guildTimingGranted and guildTimingLocked are persisted and cannot be reset as if Guild had not chosen.

Represent Sapho's last position as a scoped constraint, not a one-time array move. Preserve Guild's ability to act at earlier allowed boundaries. The face explicitly settles last versus Guild; it does not explicitly settle a first-priority conflict between Sapho and Guild. Do not silently treat the special last clause as a total cancellation of Guild's power.

endMovement removes the current ID and uses the remaining queue to enforce old allied cooccupation evacuation. Reordering must preserve that actual completed-turn history; using the original storm order for “second mover” afterward would be wrong. Ornithopter continuation, active shipping Karama, pending Ix/CHOAM movement, Guild shipment stop, BG arrival/intrusion and Richese allied No-Field opportunity belong to the current committed turn and must complete exactly once.

Auctions

game/richese-auction.ts keeps order, acted, passed, active, sealed bids and tieOrder separately. This is a useful separation. The last helper validates event, Once Around method, eligibility and not-yet-acted status. It cannot supply a second opportunity after the owner has already bid. Preserve free/remove outcome handling and the normal strict-raise rule.

The common auction still reads g.order directly in auctionNext, rotating opener, pool initialization and sale continuation. Add a local order/opener identity; a stored numeric index into storm order is unsafe after a local reorder. Black Market normal bidding has its own local order and must resume the subsequent normal sale according to its existing source rule. The Sapho scope must state whether it ends with that lot or intentionally covers the phase; it must not leak into unrelated auctions by accident.

A played Sapho may free one hand slot. Recompute legal capacity using exact current custody/reservations, including outstanding purchases and ally funding, rather than an old eligibility array alone. But do not reopen a finished all-full lot or return a card already sold. While Silent bids are sealed, maintain existing funding-decrease guards and keep opponents' values private.

Battle aggressor

battles(g) derives both scheduling and attacker orientation from g.order; chooseBattle copies that pair into the battle. Many consumers interpret battle.attacker as aggressor: resolveBattle ties, AI scores, views, and future Stone Burner tie comparisons. The safer change is an explicit battle.aggressor defaulting to the original attacker, then a single shared tie helper used by every ordinary/special comparison. Avoid swapping attacker/defender while responses and player-keyed plans already exist.

Sapho's face does not restrict this mode to before plans are sealed. A live unresolved battle is the defensible scope, including after revelation but before the outcome commits. Preserve the full-plan/prescience target, Voice target, CHOAM funding, KH/elite reactions, Residual pre-leader stage, Tooth/Stone choices, Portable defense, traitor declarations and Truth promises. An automatic outcome cannot be retroactively changed during winner cleanup or Face Dance. A deterministic aggressor change needs no additional acknowledgement, but the server must leave a usable intervention opportunity before automatic resolution.

Reactions, simultaneous intent and privacy

Do not overwrite g.decision or g.response with an order change and lose the suspended operation. Prefer accepting a scoped declaration into a pending override and applying it at the next valid boundary, while retaining the exact current continuation. If simultaneous decisions can materially affect ordering, use a public eligibility-independent priority window. Existing phaseOpening is currently an Ix/Amal window and cannot simply be reused by enabling it only for a secret Sapho holder.

All three modes require ordinary card custody/commitment guards. Preserve Truthtrance obligations, sealed/prescience cards, auction reservations and paid Box priority. Queue windows must depend on public available modules/action rules, not hidden possession or a private hand scan. Owner projection can show the held card, legal scopes and block reasons; others see an order change and the spent card only after play. A logged/submitted override must not expose a private auction face, sealed bid or unrelated battle plan.

Sapho is played as a separate special action, not a card committed in the Battle Plan. Its discard on accepted use is therefore not the Mirror/Portable winning-plan retention question. Do not add the spent card to winner keep/discard or Moritani retention candidates.

Material decisions before claiming complete support

  1. Partly completed turns: first/last can safely reorder unstarted remaining turns. The source does not clearly prescribe suspending another player's move after their shipment, or separating a holder's completed shipment from their still-unperformed movement. Define this intervention boundary explicitly; no refund, replay or bonus move is justified.
  2. Normal-auction cycles and phase scope: first at a fresh opener is clear, but “last” needs a finite scope in a cyclic auction. Confirm whether an intervention reorders one circuit, the whole current lot, or the phase's opener sequence. Do not present one convenient implementation as the printed answer. Once Around last is independently confirmed and does not depend on this ruling.
  3. Sapho first versus Guild timing: only the last override explicitly supersedes Guild. Preserve a guard for an actual competing first declaration until precedence is settled; do not block nonconflicting Basic movement.
  4. Competing/nested first or last claims: a single verified physical Sapho prevents two simultaneous owners, but recovery via other card effects and other ordering powers can create sequential conflicts. Bind each accepted use to exact custody/event and retain earlier completed actions. The Truthtrance-specific simultaneous rule is insufficient evidence for every possible competing power.

Verification plan and honest coverage

Pure queue tests: first/last at every position; no duplicates/lost IDs; no completed-action resurrection; already-first/last no-op policy; protected last versus repeated Guild waits; exact events and immutable inputs. Auction tests: both physical Once Around directions, owner and nonowner, higher-than bid requirement, all-pass/free/remove, acted bidder rejection, current funding/hand capacity, normal cyclic/high-bid preservation after its scope ruling, Black Market resumption, and byte-equivalent Silent secrecy/tie priority.

Engine tests: each printed mode in Basic/Advanced; battle ties in both orientations, unchanged sealed IDs and all power targets; full-plan/No-Field boundaries; no repeated payments/arrivals/casualties; persisted continuation through Guild/CHOAM/Ix/BG/Richese reactions; atomic expired requests; public window independence from Sapho possession; takeover/reconnect during an unresolved scope. AI must understand the projected scope and revised effective order without reading hidden hands; all four profiles need finite complete-action tests. Browser tests should show current and resulting order, exact scope, card inspection, disabled reasons and restoration.

Five facets remain partial: source/contract audit is present, the pure Once Around last helper exists, but the full authoritative effect, controls, AI and integrated verification remain unimplemented. Do not label the whole card complete after implementing only its confirmed auction shortcut.