Prototype voluntary seat handover with durable private retries

Let a current owner issue, cancel or replace a private 24-hour one-time offer.
Recipients accept the same faction and saved game while old browser sessions,
recovery keys and entry receipts lose authority. Preserve exact claim retries
across refresh, restart and later offers, with private tab-scoped continuation.

Fence every claim mutation to its winning transaction. Add durable receipts
and additive backfill for already-issued offers without changing game JSON or
existing seat authority. Block competing navigation during unresolved owner
operations; remove invalidated owner kits on confirmed recovery.

Record the pending CHOAM Nexus after-victory secrecy/window decision without
inventing the unresolved gameplay or opening mode/publication gates.

Validation: types/lint and 4,364 offline tests passed; production build passed;
43 HTTP tests passed. Added 19 offline and 3 HTTP regressions. Independent
privacy/persistence review passed, including deterministic CAS interleavings,
rollback, legacy migration and exact receipt restoration. Browser room 2EMYG4CY
retained private setup choices after handover/refresh and continued into Storm;
follow-up recovery removed its invalid offer with cards/forces/spice unchanged.
All 218 opening rooms preserved (291 after QA and both broad runs). The opening
456 seat, 49 recovery-key, 56 recovery-receipt and 106 entry-receipt rows were
also verified unchanged. Server reused; no restart or recurring automation.

Final private report: ~/.local/share/dune/checkpoints/20260913-seat-handover/
verification-final/report.json. Source fingerprint:
8949cdf58eb8bc8bd33f2657c6b21352b3ee5e17e2a556c684a89073015632f4.
Check/build/HTTP duration: 140565/6689/24835 ms. The earlier broad run passed;
a final recovery-UI review fix required the second source-bound run.
Goal aggregate counter 64,301,976 -> 65,031,751 before Git (729,775) for this
bounded capability and its concurrency/recovery review; full goal remains active.
This commit is contained in:
Quintine committed 2026-09-13 15:28:14 +10:00
1 parent f0d3d9c464
commit 7dfd6b3048
24 files changed
+3570 -24

No files matched your search

+3 -1
View File
@@ -57,13 +57,15 @@ restoration after necessary restarts. No recurring automation is installed.
| Six-faction Advanced | Genuine offline setup across 456 configurations; four-profile full-game simulations and JSON continuations. | Base gaps plus provisional special-Karama outcomes, remaining timing audits and authentic multiplayer/browser acceptance. Public starts remain disabled. |
| Twelve factions and optional modules | Many bounded faction, card, Homeworld and Nexus slices have controls, bots and recovery evidence; Discovery includes free entry, Cistern, carried flight and bounded Jacurutu, Testing Station and Shrine effects. | Every unfinished effect and interaction, occupation entitlement, Orgiz, mixed physical dial allocation and contested Discovery benefits and complete combined games. Inventory or fixture coverage does not enable a module. |
| AI difficulty | Four profiles consume private legal views; recorded Basic and Advanced studies complete. | Demonstrate a consistent Medium → Hard → Brutal strength ordering, improve strategic gaps, and repeat targeted studies after relevant policy/rule changes. |
| Multiplayer | Versioned writes, saved seats, owner recovery kits, uncertain-request retry and voluntary own-seat AI control. | Intentional transfer, unprepared abandoned-seat recovery, unattended continuation and remaining network-failure acceptance. Preserve privacy and existing games. |
| Multiplayer | Versioned writes, saved seats, owner recovery kits, uncertain-request retry, voluntary own-seat AI control and a [voluntary seat handover prototype](SEAT_HANDOVER.md). | Broader handover/disconnection acceptance, unprepared abandoned-seat recovery, unattended continuation and remaining network-failure acceptance. Preserve privacy and existing games. |
| Player experience | Internal component inspectors and many desktop/phone feature journeys verified. | Complete end-to-end games, accessible controls, responsive layout, clear rules/errors and recovery across all supported combinations. |
The [base/Advanced audit](BASE_ADVANCED_READINESS_20260907.md) includes historical missing-feature rows. Its follow-ups supersede the Fremen cancellation and BG setup findings; [genuine setup](ADVANCED_SETUP_TEST_SEAM.md) and the [Advanced study](AI_ADVANCED_SETUP_CALIBRATION_20260907.md) supersede the old Basic-then-flip testing concern. They do not settle the remaining rules.
Likewise, the [Truthtrance readiness audit](TRUTHTRANCE_NONBATTLE_READINESS_20260907.md) predates [spice facts](TRUTHTRANCE_SPICE_FACTS.md), [card-count facts](TRUTHTRANCE_CARD_COUNT.md) and [Basic shipment promises](TRUTHTRANCE_SHIPMENT_PROMISES.md). Current `TruthFact` already includes these facts; do not rebuild them. Typed preparation and BG conversion now support the active reserve-shipment scope in base Advanced without Guild or optional modules. Broader facts, earlier-phase promises, remaining Advanced/expansion commitment scope and freeform interpretation remain incomplete.
The voluntary [seat handover prototype](SEAT_HANDOVER.md) connects private one-time offers, recipient controls, exact saved retry proof and active-token custody fencing. It preserves existing game state and revokes previous owner recovery authority. Full disconnected-seat acceptance remains open. CHOAM Nexus after-victory inspection awaits the [private-window decision](NEXUS_CHOAM_SECRET_ALLY.md#after-victory-inspection-audit); development continues independently.
## Next milestone: rapid functional coverage
The first connected batch is the [Ixians & Tleilaxu prototype](IX_PROTOTYPE.md):
+2 -2
View File
@@ -59,9 +59,9 @@ Normal waiting for a temporarily disconnected player is legitimate; it should no
- Seven passing persisted tests cover the scenarios above, not all valid player counts, official module combinations, every sealed interaction, or full release readiness.
- No server, engine, or existing test file was modified during this audit. The new test must be included in the coordinating agent's multiplayer test command.
## Proposed disconnected-seat contract (design only)
## Proposed disconnected-seat contract (historical design)
This proposal changes operational control of a seat, not board-game rules. It is not implemented or included in the passing test count. Preserve the same player ID, faction, resources, hand, traitors, promises, submitted plans, decision ownership and history throughout every transition. Never restart setup or reveal a sealed plan merely because its controller changes.
This broader proposal changes operational control of a seat, not board-game rules. Owner recovery and [voluntary handover](SEAT_HANDOVER.md) now have bounded implementations using exact active-token fencing. The separate generation/delegation schema below is historical design and has not been adopted; unattended or host-driven substitution remains unfinished. The passing test count above predates these additions. Preserve the same player ID, faction, resources, hand, traitors, promises, submitted plans, decision ownership and history throughout every transition. Never restart setup or reveal a sealed plan merely because its controller changes.
### Distinguish three cases
+38
View File
@@ -40,6 +40,44 @@ combinations remain part of the later integration pass.
server restart is required. Recovery validates the already-paid outcome and
retires the discard; it never credits spice a second time.
## After-victory inspection audit
The other printed Secret Ally choice applies only after its holder wins a
battle. It inspects exactly one random Treachery Card held by the opposing
combatant that the opponent did not use in that battle. Normal and traitor
wins qualify. Mutual-traitor and Lasgun-shield explosion results have no winner
and do not. “Used” is the physical set already produced by the battle quote for
the opponent, including a Cheap Hero, cards played in weapon or defense slots
and a late Portable Snooper. A used card remains excluded if another effect
later retains it. The effect neither transfers nor discards the inspected card.
The battle engine must preserve the opposing used-card IDs with the resolved
battle event before mandatory loser disposal. The existing Auditor candidate
filter is reusable because it removes exact physical used IDs from the current
opposing hand. The Nexus effect still needs its own one-card sampler and receipt;
it must not borrow Auditor survival, payment or cancellation behavior. A
successful use discards the held CHOAM Nexus card once, records the sampled
snapshot once and projects the face only to its holder. The public chronicle may
name the use, winner and opponent, but not the inspected face.
The safe continuation point is the existing final `finishBattle` board boundary:
after mandatory and optional battle-card cleanup, Moritani retention, battle
income, technology, capture, Auditor, Face Dance and Caladan reinforcement, and
before another battle or phase begins. No existing choice occurs at that point
for every possible winner. Opening a pause only when the winner secretly holds
the CHOAM Nexus card would reveal that hidden identity. Precommitting a
conditional use before the result would remove the printed after-victory choice.
A universal use-or-pass window would preserve secrecy and the full choice, but
would also ask winners without the card to pass. The user has been asked which
product exception to adopt; no timing policy is implemented while that answer
is pending.
The retrieved Nexus sources neither establish an ordinary Karama response to
this Secret Ally play nor grant blanket Nexus immunity. The Collection trade is
currently direct and this inspection must not inherit the native Auditor's
Karama/payment window by analogy. Cancellation remains an explicit later audit
boundary rather than an invented prototype rule.
## Focused evidence and remaining scope
Run `npm test -- nexus-choam-trade`. Focused cases cover Basic/Advanced payment,
+1
View File
@@ -34,6 +34,7 @@ These are unresolved in the cited records. Do not infer an answer from elapsed t
| Orgiz collection | User question pending: take one spice per positive board pile collected, or leave the effect pending? The publisher does not clarify stacked Spice Blows. The draft quote remains opt-in and is not enabled by the engine. Contested Cistern income also remains outside the ordinary sole-occupant prototype. | [Discovery interpretations](DISCOVERY_PROTOTYPE.md#interpretations-retained-for-refinement) |
| 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) |
| CHOAM Secret Ally battle timing | The printed after-victory inspection is optional and the Nexus identity stays secret. No existing postbattle choice covers every winner: a pause only for a holder leaks ownership, precommitment removes the after-win choice, and a universal window makes nonholders pass. The product-exception question has been sent; no timing policy is implemented pending the answer. Ordinary Karama cancellation is also not established by the retrieved sources. | [After-victory inspection audit](NEXUS_CHOAM_SECRET_ALLY.md#after-victory-inspection-audit) |
| Discovery prototype inferences | Free entry uses storm order and ordinary source-storm restrictions; these are general-rule inferences. Great Maker currently follows ordinary first-turn worm skipping and Sandtrout suppression; an exhausted token type creates no replacement token. These preserve current source interpretation and physical inventory but are not separately confirmed rulings or complete combined-module certification. | [Interpretations for refinement](DISCOVERY_PROTOTYPE.md#interpretations-retained-for-refinement) |
| Other Homeworld combinations | Population/force splitting, removal custody, replacement shortages, income accounting and placement ordering remain local to their detailed contracts. | [Homeworld rules](HOMEWORLD_RULES.md), [occupation](HOMEWORLD_OCCUPATION_RULES.md) and the effect documents above |
+63
View File
@@ -0,0 +1,63 @@
# Voluntary seat handover prototype
13 September 2026. This is an operational multiplayer feature, independent of
board-game rules and mode gates. The current human owner can hand their own seat
to another browser with a private one-time kit. No host takeover, inactivity
inference or delegation by another player is authorized by this feature.
## Player flow
- In the table, **Pass your seat to another player** creates a private offer.
Share its complete kit only with the intended recipient. It expires 24 hours
after server creation. Ordinary play can continue until acceptance.
- **Cancel handover** invalidates the current offer. A confirmed replacement
invalidates an older kit. If an owner operation is uncertain, retry it exactly;
replacing uncertain work requires an explicit acknowledgement.
- The recipient chooses **Accept a seat handover** on the home page, reads the
kit and confirms the target room and seat. An active cookie for another seat
in that room is rejected; use a separate browser profile.
- Acceptance preserves the player ID, faction, name, cards, resources, private
commitments, AI-control setting and game history. It revokes all previous
browser sessions and recovery authority for that seat. The new owner should
create their own recovery kit after acceptance.
Offers and exact recipient retry proof remain in private tab-scoped browser
storage across refresh. Claim proof is written and read back before any request
is sent. A dedicated screen retains it while the outcome is unknown and excludes
competing create/join/recovery controls. An exact receipt response and a matching
cookie-authorized read must both confirm the seat. The room URL is anchored before
the proof is removed. Closing the tab or clearing its storage can lose this proof;
explicit abandonment explains that it cannot undo a completed claim.
## Server boundary
The existing `/api/rooms/:code/control` endpoint supports `createSeatHandover`,
`revokeSeatHandover` and `claimSeatHandover`. Only an authenticated seat may issue
or revoke its own offer. The server uses 256-bit client secrets, hashed storage,
a server expiry and room-version comparisons with active-session checks inside
the atomic write. Recovery invalidates an unclaimed offer by revoking its issuing
session. Plaintext secrets never enter game JSON, projected views, URLs or history.
The additive offer and receipt tables preserve existing games and credentials.
The second additive migration also copies existing claimed-offer receipts without changing game or seat authority. Claims alter custody and room version while keeping stored game JSON byte-identical.
Exact claim retries reissue the same session; creating a later offer does not
consume that receipt. A later successful claim or recovery revokes the session
and prevents replay. Invalid proofs reveal no private view. Transport retains
origin checks, bounded bodies, no-store and room-scoped HttpOnly cookies.
## Evidence and remaining acceptance
`tests/seat-handover-client.test.ts` covers kit/proof validation, refresh identity,
storage failures and receipt/read confirmation. `tests/seat-handover-store.test.ts`
executes production SQL against in-memory SQLite for custody, private saved state,
rollback and concurrent ownership changes. `tests/seat-handover-http.test.ts`
exercises the real HTTP boundary, exact retries, revoked cookies/recovery,
cross-origin rejection and competing-seat protection.
Required checkpoint results belong in the verified commit and compact report.
Browser QA in new room `2EMYG4CY` confirmed offer restoration, acceptance with the same four private traitor choices, refresh, and continued play through starting placement and the initial card deal. The recipient reached Storm with Crysknife, Lady Jessica, ten forces in Arrakeen and ten spice. A follow-up created a recovery key and new offer, recovered the same seat, and verified that the invalidated offer was removed from the owner controls while cards, forces and spice stayed intact. This was a bounded desktop journey; existing human game authority was not used. All 218 opening rooms and their 456 seat, 49 recovery-key, 56 recovery-receipt and 106 entry-receipt records remained unchanged after migration and targeted QA.
Full disconnection acceptance across all decisions, unattended continuation,
unprepared abandoned-seat recovery and comprehensive hosted acceptance remain
unfinished. The historical generation/delegation design in
[MULTIPLAYER_AUDIT](MULTIPLAYER_AUDIT.md) remains a broader proposal; current
handover uses exact active-token fencing instead of a separate generation field.