diff --git a/components/recruits.tsx b/components/recruits.tsx index eb4afb12..c68f95b9 100644 --- a/components/recruits.tsx +++ b/components/recruits.tsx @@ -23,6 +23,7 @@ export function Recruits({ game, act, busy }: { : 'Play this card to double every faction’s free revival rate and raise the ordinary force limit to seven for this turn. Factions with unlimited revival keep that advantage.'}

Already completed revivals still count. Paid forces retain their normal prices, and special-force revival limits still apply.

+

Provisional late-play accounting: prior paid revivals keep their payments and count toward the total force limit, but only recorded free returns consume the doubled free allowance. No refund or retroactive reclassification. This is a first-version policy, not a publisher clarification or numerical user ruling.

diff --git a/docs/CURRENT_STATUS.md b/docs/CURRENT_STATUS.md index bdf13a18..298db408 100644 --- a/docs/CURRENT_STATUS.md +++ b/docs/CURRENT_STATUS.md @@ -158,6 +158,14 @@ Types/lint and the affected five-file union pass **33/33**. The sole initial failure was an erroneous unsupported-Shield fixture row, removed before the focused repair and union rerun; runtime code was not weakened. +**Late-paid Recruits first version connected.** Recorded free usage now allows +play after paid ordinary returns. The visible provisional policy retains +payment and total counters, without refund: Atreides' two-free/one-paid may +take two additional free forces. Missing ledgers and pending/rate/replay +guards remain. Two native Basic/Advanced smokes and live owned React controls +prove exact usage/payment/card results; no broad suite or deployed proof. +Types/lint and two targeted late-accounting/remaining-guard cases pass. + **7 October 2026 — five pending rulings resolved by the user.** The user answered five recorded questions; each is now recorded in [the decision index](RULE_DECISIONS.md#user-rulings--7-october-2026) and diff --git a/docs/RECRUITS_RULES.md b/docs/RECRUITS_RULES.md index bea4d8ca..546f816f 100644 --- a/docs/RECRUITS_RULES.md +++ b/docs/RECRUITS_RULES.md @@ -2,6 +2,13 @@ Audit: 2026-09-06. Scope: the Recruits card interacting with prior revivals, existing unlimited/expanded allowances, prevention, Fremen ally grants and pending declarations. No runtime changes. This supplements [ECAZ_TREACHERY_RULES.md](./ECAZ_TREACHERY_RULES.md), which contains the original component figure and card-face provenance. +**Runtime follow-up — 8 October 2026:** the content-first prototype now uses +recorded actual free usage after paid returns, preserving payments and total +returns without refund. This is an explicitly provisional implementation choice, +not an answer to the publisher/user question below. See [the current runtime +contract](RECRUITS_RUNTIME.md#provisional-late-paid-activation--8-october-2026). + + ## Primary evidence | Source | Relevant verified rule | diff --git a/docs/RECRUITS_RUNTIME.md b/docs/RECRUITS_RUNTIME.md index da92d8dc..4c2b9c12 100644 --- a/docs/RECRUITS_RUNTIME.md +++ b/docs/RECRUITS_RUNTIME.md @@ -3,8 +3,30 @@ 14 September 2026. **Prototyped, not full card-variant acceptance.** The independent Ecaz & Moritani Treachery Cards variant is included before genuine Basic or Advanced faction setup. All three physical cards are present exactly once. -Recruits has connected controls, AI and saved continuation; Reinforcements and -Harass & Withdraw remain unfinished. Public starts and publication remain gated. +Recruits, bounded Reinforcements and Harass & Withdraw have connected controls, +AI and saved continuation; full interactions and public starts remain gated. + +## Provisional late-paid activation — 8 October 2026 + +The content-first pass now permits Recruits after recorded paid ordinary +returns, once the current transaction has finished. **Provisional policy:** +prior payments are retained; only actual recorded free returns consume the +doubled free rate, while all returns consume the total allowance. No refund, +reset or retroactive reclassification is performed. This is not a numerical +user ruling or a newly retrieved publisher answer. + +Thus Atreides' actual two-free/one-paid return retains its two-spice payment +and three total returns; after Recruits it may take two additional free +forces under the seven total cap. Missing or inconsistent free-use ledgers, +pending declarations, later rate changes and same-turn replay remain guarded. +The owned before-play panel and public active panel name this interpretation. + +Basic/Advanced before/after native smokes use a genuinely dealt card, an +actual three-force return and useful allied Easy activation, then two free +returns: total5/free4, unchanged paid spice and one card disposal. Live React +controls in Chromium produce the same available2/remaining4 quote and preserve +spice18/total3/free2 at activation. No broad suite, recovery or deployed proof. + ## Rules contract @@ -17,11 +39,11 @@ Fresh publisher/designer-linked PDF fetches on 14 September returned HTTP 403; this follow-up uses the earlier recorded primary-source audit and independent source review. No newly retrieved late-paid ruling is claimed. -The connected scope permits clean activation before normal returns or after only -exactly recorded free normal returns, once existing priority windows and transactions -have finished. Earlier paid returns, unknown legacy usage, later Fremen grants, -same-turn replay after recovery and additional optional modules remain guarded. -Those guards identify unfinished cases; they are not new printed timing rules. +The scope permits activation before returns or after consistently recorded +free/paid normal returns, once priority windows and transactions finish. +Unknown legacy usage, later Fremen grants, same-turn replay after recovery +and additional optional modules remain guarded. These are unfinished cases, +not new printed timing rules. Already-ready players retain their Revival opportunity while phase four is open. Atreides doubles two to four, Fremen three to six, and Guild one to two. Native @@ -35,10 +57,10 @@ inference from independent effects, not a direct combined publisher FAQ.** A Tleilaxu limit response is not opened merely for crossing three under Recruits; other qualifying price/prevention responses retain their original purposes. -The user has been asked about Atreides taking two free plus one paid return before -Recruits: preserve the gate, provide two further free returns without refund, or -provide one further free return without refund. No answer is assumed. The source -audit also records the refund alternative and later changing-rate ambiguity. +The earlier user question about one versus two further free Atreides returns +remains unanswered. The 8 October first version uses the visibly provisional +two-further-free policy above; it does not claim that question was adjudicated. +The source audit retains the alternatives and later changing-rate ambiguity. ## Connected path and persistence diff --git a/docs/RULE_DECISIONS.md b/docs/RULE_DECISIONS.md index 08040abb..013ee22e 100644 --- a/docs/RULE_DECISIONS.md +++ b/docs/RULE_DECISIONS.md @@ -464,7 +464,7 @@ These are unresolved in the cited records. Do not infer an answer from elapsed t | Bureaucrat / Emperor gifts | Whether an allied gift is a qualifying payment and whether its threshold may be revealed. Existing gift amounts are private to payer/recipient; the card and retrieved primary sources do not explicitly settle this combination. The user question is pending; no answer or exact-amount disclosure is assumed. | [Gift classification review](BUREAUCRAT_PAYMENTS.md#21-september-gift-classification-review) | | Reinforcements cost | The user question still asks whether to keep the card disabled, always transfer three reserve forces on every outcome, or waive only a sole traitor-call winner's cost; no answer is assumed. The bounded classic and Ecaz/Moritani prototype provisionally charges on all revealed outcomes, chooses normal reserves before elite and counts the transfer as battle losses. Those are product interpretations, not a ruling. Same-plan Harass/Stone Burner remain gated; opposing Harass is supported. Eligibility never depends on concealed matching Traitors. | [Source cost review](ECAZ_TREACHERY_RULES.md#14-september-reinforcements-cost-review) · [Bounded runtime](REINFORCEMENTS_RUNTIME.md) | | Harass / Stone Burner | A user question has been sent: keep the combination gated or compare forces remaining after withdrawal. No answer is assumed. The Richese card-family configuration is guarded publicly; hidden Stone Burner custody never controls eligibility. Ambiguous physical allocations and other optional modules remain unfinished. | [Current boundaries](HARASS_WITHDRAW_RUNTIME.md#current-boundaries) | -| Recruits late accounting and rates | A user question has been sent for two free plus one paid Atreides return before Recruits: keep the disputed case gated, or one/two further free returns without refund. No answer is assumed. Late-changing free rates, pending repricing and same-turn recovered-card replay also stay gated. The connected clean-case preview retains the independent seven-force cap after faction-advantage cancellation as an explicit inference, not a direct combined FAQ. | [Source audit](RECRUITS_RULES.md), [runtime scope](RECRUITS_RUNTIME.md) | +| Recruits late accounting and rates | The earlier one/two-further-free question remains unanswered. The content-first prototype now preserves paid spice, deducts recorded actual free usage from the doubled rate and all returns from the total cap: two-free/one-paid Atreides can take two more free. This is visibly provisional, not a numerical user ruling. Unknown ledgers, pending repricing, late rate changes and same-turn replay remain guarded. | [Source alternatives](RECRUITS_RULES.md), [provisional runtime](RECRUITS_RUNTIME.md) | | Sapho remaining timing | First versus unspent Advanced Guild priority, partly completed combined turns, cyclic auction duration and later battle timing stay guarded. The existing pre-plan opportunity supports [early aggressor](SAPHO_AGGRESSOR.md). Prior questions remain unanswered. | [Source audit](JUICE_OF_SAPHO_SOURCE_UPDATE.md), [battle review](JUICE_OF_SAPHO_BATTLE_REVIEW.md) | | Semuta Drug | Full-hand exchange is user-approved; neutral all-seat acknowledgements remain the explicit application policy. Other discard producers, nested continuation coverage and full-game acceptance remain unfinished. | [Source update and selected exchange](SEMUTA_SOURCE_UPDATE_20260907.md), [privacy review](SEMUTA_PRIVACY_REVIEW.md) | | Leader Skills edge cases | Capture/replacement eligibility, Banker escrow custody, Smuggler modifier/allocation boundaries, Mentat empty-hand fallback, late/mirror/numeric Diplomat defenses and simultaneous optional timing remain source gaps. Printed alternate/hybrid defense roles now have a connected, explicitly interpreted copy path. The bounded Diplomat retreat prototype chooses printed/copied strength and surviving-loser retreat before casualties; this is not an official priority clarification. | [Material boundaries and retreat](LEADER_SKILLS_RULES.md#bounded-diplomat-retreat-interpretation), [Defense limits](DIPLOMAT_DEFENSE.md#evidence-and-remaining-scope) | diff --git a/game/engine.ts b/game/engine.ts index 9c78639c..2bced55e 100644 --- a/game/engine.ts +++ b/game/engine.ts @@ -12455,8 +12455,6 @@ function recruitsPlayBlock(g: Game, owner: Player, card: Card): string | null { return 'Normal force revival history is inconsistent; Recruits cannot safely reprice it.'; if (player.revived > 0 && player.freeForcesRevived === undefined) return 'Earlier normal force revival history is incomplete; Recruits cannot safely reprice it.'; - if (player.revived > (player.freeForcesRevived ?? 0)) - return 'Recruits after a paid normal force revival awaits a rules ruling.'; } return null; } diff --git a/game/reference.ts b/game/reference.ts index 641b492a..d5b041a6 100644 --- a/game/reference.ts +++ b/game/reference.ts @@ -4762,15 +4762,15 @@ export const RULE_TOPICS: RuleTopic[] = [ 'The separate three-card variant includes Recruits, Reinforcements and Harass & Withdraw. It does not require the Ecaz faction. A development preview includes all three physical cards before setup; Recruits, bounded Reinforcements and Harass & Withdraw controls are connected.', 'The holder may play Recruits from its Revival panel. Discard the card once, then all players use the increased rates while this Revival phase remains open, including players who had already marked themselves ready. Completed returns still count toward their turn totals.', 'Atreides rises from two free forces to four; Fremen from three to six; Guild from one to two. The ordinary force limit becomes seven. Native unlimited CHOAM and Tleilaxu allowances remain unlimited, and their free rates become zero and four. Paid prices and separate elite limits still apply.', - 'Free-revival prevention still prevents free returns. A Fremen ally grant completed before Recruits doubles from three to six. A later grant, play after a paid ordinary return, unresolved transactions and a second use in the same turn remain guarded pending their rules decisions.', + 'Free prevention still prevents free returns. Prior paid ordinary returns now have a visibly provisional policy: preserve payment, deduct only recorded free returns from the doubled free allowance and all returns from the total cap. Two free plus one paid Atreides may take two more free without refund; this is not a numerical user ruling. Missing/inconsistent ledgers, later Fremen grants, pending transactions and same-turn replay remain guarded.', 'The preview supports Basic or Advanced classic-faction games without additional optional modules. Public activation and complete combined-game acceptance remain unfinished.', ], related: ['revival', 'ecaz-modules', 'expansion-faction-games', 'implementation-checklist'], checklist: [ - { area: 'Implementation', status: 'Partial', detail: 'Genuine independent three-card setup, physical Recruits play/discard, public turn effect, shared revival quotes, preserved use and guarded timing are connected. Harass and Reinforcements have separate bounded battle prototypes; complete variant interactions remain gated.', evidence: ['game/ecaz-cards.ts', 'game/recruits.ts', 'game/revival.ts', 'game/engine.ts'] }, + { area: 'Implementation', status: 'Partial', detail: 'Genuine independent three-card setup, physical Recruits play/discard, public turn effect and shared revival quotes are connected. Recorded late-paid activation uses a provisional no-refund/free-use policy; unknown ledgers and other timing guards remain. Harass/Reinforcements have separate bounded battle prototypes; complete variant interactions remain gated.', evidence: ['game/ecaz-cards.ts', 'game/recruits.ts', 'game/revival.ts', 'game/engine.ts'] }, { area: 'Player controls', status: 'Implemented', detail: 'The owned physical card has full inspection, a Revival action and explicit unavailable reasons. All seats see the effective public rates after play.', evidence: ['components/recruits.tsx', 'components/game-table.tsx', 'game/card-presentation.ts'] }, { area: 'AI', status: 'Partial', detail: 'All four profiles use the same legal owned offer for useful own or allied revival, then existing authoritative revival choices. Complete card strategy and calibration remain unfinished.', evidence: ['game/bots.ts'] }, - { area: 'Documentation', status: 'Implemented', detail: 'The card guide records examples, current prototype limits and the independent-cap inference; late-paid and late-rate questions remain explicit.', evidence: ['docs/RECRUITS_RULES.md', 'docs/RECRUITS_RUNTIME.md'] }, + { area: 'Documentation', status: 'Implemented', detail: 'The guide records examples, limits, independent-cap inference and the visibly provisional late-paid policy; source alternatives and late-rate questions remain explicit.', evidence: ['docs/RECRUITS_RULES.md', 'docs/RECRUITS_RUNTIME.md'] }, { area: 'Verification', status: 'Partial', detail: 'Focused rules, controls, AI and authenticated recovery checks cover the bounded preview. Sample and browser evidence is recorded separately; full variant acceptance remains open.', evidence: ['tests/recruits.test.ts', 'tests/recruits-engine.test.ts', 'tests/recruits-controls.test.tsx', 'tests/recruits-recovery.test.ts', 'tests/prototype-room.test.ts'] }, ], }, diff --git a/tests/recruits-engine.test.ts b/tests/recruits-engine.test.ts index 2523a389..3b42a8e5 100644 --- a/tests/recruits-engine.test.ts +++ b/tests/recruits-engine.test.ts @@ -107,6 +107,30 @@ void test('the accepted card changes the authoritative normal revival quote and rejectUnchanged(g, player.id, { type: 'revive', amount: 4, elite: 0 }); }); +void test('provisional late-paid Recruits preserves payment and permits only the remaining recorded free allowance', () => { + for (const advanced of [false, true]) { + let g = settleRevival(applyAction(recruitsGame(advanced), 'at', { type: 'revive', amount: 3, elite: 0 })); + const before = g.players.find(player => player.id === 'at')!; + assert.equal(before.revived, 3); + assert.equal(before.freeForcesRevived, 2); + assert.equal(before.spice, 18); + const reserves = before.reserves, tanks = before.tanks; + g = applyAction(g, 'ch', play); + assert.equal(viewGame(g, 'at').revival.freeRemaining, 2); + assert.equal(viewGame(g, 'at').revival.forcesRemaining, 4); + assert.equal(g.players.find(player => player.id === 'at')!.spice, 18); + g = settleRevival(applyAction(g, 'at', { type: 'revive', amount: 2, elite: 0 })); + const after = g.players.find(player => player.id === 'at')!; + assert.equal(after.spice, 18); + assert.equal(after.revived, 5); + assert.equal(after.freeForcesRevived, 4); + assert.equal(after.reserves, reserves + 2); + assert.equal(after.tanks, tanks - 2); + assert.equal(viewGame(g, 'at').revival.freeRemaining, 0); + assert.equal(g.discard.filter(card => card.id === play.card).length, 1); + } +}); + void test('free prevention remains zero and canceled unlimited faction caps compose to seven', () => { const g = recruitsGame(); g.revivalRules = { @@ -145,12 +169,11 @@ void test('prior settled Fremen ally grant is doubled, while a grant after activ rejectUnchanged(active, 'fr', { type: 'grantRevival' }); }); -void test('activation rejects pending, prior paid, unknown and inconsistent revival histories without consuming the card', () => { +void test('activation rejects pending, unknown and inconsistent revival histories without consuming the card', () => { const cases = [ (g: Game) => { g.decision = { kind: 'revivalStop', player: 'at', recipient: 'at', revival: 'forces' }; }, - (g: Game) => { const p = g.players[0]; p.revived = 2; p.freeForcesRevived = 1; }, (g: Game) => { const p = g.players[0]; p.revived = 1; delete p.freeForcesRevived; }, (g: Game) => { const p = g.players[0]; p.revived = 1; p.freeForcesRevived = 2; }, ];
Current revival rates
FactionFree rateForce limit