Connect Richese final-cache and provisional full-hand acquisition
This commit is contained in:
1 parent
451ecc950c
commit
66e061ccca
10 files changed
+83
-45
No files matched your search
@@ -19,6 +19,7 @@ export function RicheseSpecialKarama({
|
||||
const [selection, setSelection] = useState('');
|
||||
const purchase = game.richeseSpecialKarama;
|
||||
if (!purchase) return null;
|
||||
const me = game.players.find(player => player.id === game.me);
|
||||
const karama =
|
||||
purchase.karamas.find((card) => card.id === activation) ??
|
||||
purchase.karamas[0];
|
||||
@@ -51,6 +52,15 @@ export function RicheseSpecialKarama({
|
||||
its separate response. The remaining Richese card effects are still
|
||||
being implemented; inspect a card before choosing it.
|
||||
</p>
|
||||
{me && me.hand?.length === me.handLimit && (
|
||||
<p className="notice">
|
||||
Provisional full-hand exchange: spending the held Karama frees the
|
||||
slot for one cache card in this action, leaving the final hand at
|
||||
its limit. The acquisition/discard timing is not an adjudicated
|
||||
publisher ruling. The final cache card may be acquired under the
|
||||
resolved exhausted-cache rule.
|
||||
</p>
|
||||
)}
|
||||
{purchase.karamas.length > 0 && (
|
||||
<>
|
||||
<label htmlFor={`${id}-activation`}>Karama to spend</label>
|
||||
|
||||
@@ -166,6 +166,14 @@ 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.
|
||||
|
||||
**Richese acquisition edges connected.** Final-cache special purchase now
|
||||
follows the resolved exhausted-cache rule and reaches native ordinary Bidding.
|
||||
Full-hand purchase uses a visible provisional spent-Karama exchange, keeping
|
||||
final capacity and separate Emperor income. Three native edge smokes and live
|
||||
owned React purchase/income controls prove hand4/cache0, one fee/card/once-use.
|
||||
No broad suite, recovery campaign or deployed acceptance was run.
|
||||
Types/lint and the three-file acquisition union pass **21/21**.
|
||||
|
||||
**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
|
||||
|
||||
@@ -13,13 +13,37 @@ Targeted searches found discussion titles concerning full hands and alliance can
|
||||
|
||||
## 1. Advanced special Karama purchase
|
||||
|
||||
### Full-hand/final-cache follow-up — 8 October 2026
|
||||
|
||||
The 7 October exhausted-cache ruling also permits spending special Karama
|
||||
to acquire the final cached card. The subsequent native Bidding opening
|
||||
uses its ordinary pool without an unavailable compulsory cache lot.
|
||||
The currently offered/reserved auction card remains ineligible.
|
||||
|
||||
**Provisional full-hand policy:** spend the physically held Karama and
|
||||
acquire one cache card in the same action, leaving the final hand within
|
||||
its current limit. The executor already discards the activation before
|
||||
placing the acquisition. This is a visibly qualified first version,
|
||||
not a numerical user ruling or publisher timing clarification. An already
|
||||
over-limit hand is not eligible. Funds, commitments, once-use, private
|
||||
identity and the separate Emperor-income response retain their safeguards.
|
||||
|
||||
Three native before/after smokes cover last-card, full-hand and combined
|
||||
edges. Easy submits the actual purchase, one Karama leaves, three spice
|
||||
settle to Emperor when allowed, and the combined result is hand4/cache0.
|
||||
Both exhausted-cache positions enter native ordinary Bidding afterward.
|
||||
In Chromium, live owned controls show the provisional notice and reach
|
||||
hand4/cache0/spice7; the independent income acknowledgement then produces
|
||||
Emperor13 without another purchase. No broad suite or deployed proof.
|
||||
|
||||
|
||||
**Directly supported.** Richese's once-per-game special Karama use spends a Karama and three spice to choose one card secretly from its own remaining cache. The new power is advanced-only; ordinary Karama acquisition cannot buy cache lots or Black Market lots. The special rule is its own exception and is not an auction. The selected card enters Richese's hand, not an ally's. The played Karama is discarded normally. The updated Karama face expressly prevents using Karama to cancel another special Karama power. This does not waive a separate prohibition on playing a Karama, such as an applicable CHOAM effect.
|
||||
|
||||
**Normal composition, with provenance.** The special paragraph does not name the payment recipient. B19 p19 sends payments by another faction for a Treachery Card to Emperor instead of the bank, and this special power explicitly purchases a card. Apply that general rule: three to Emperor when present and eligible, otherwise bank. This is a general-rule composition, not a Richese-specific FAQ answer. Do not silently treat it as the bank-only activation fee explicitly printed on Box. Any distinct Emperor-income cancellation must affect that income only, never cancel or repeat the special purchase.
|
||||
|
||||
Richese itself is the buyer. Harkonnen's extra-card-on-purchase power therefore does not trigger, including when Harkonnen is the ally. An ensuing hand gift is not a Harkonnen purchase either. Ixian allied replacement requires a bidding purchase and R2 expressly excludes direct-cache acquisitions; this purchase neither creates an auction nor changes its acquisition origin. Do not trigger Ixian allied replacement. Ordinary bidding aid does not automatically authorize spending an ally's funds on this separate action; use Richese's spendable spice unless a separately verified payment permission applies.
|
||||
|
||||
**Still unresolved:** B19's hand cap applies at all times, while special Karama is discarded after play. Neither retrieved special paragraph supplies a full-hand exception or specifies whether spending the Karama frees a slot before the new card arrives. The ordinary free-purchase Karama explicitly disallows a full hand, but that clause cannot simply be asserted to govern the different special power. A first implementation may require a pre-existing free slot and label the full-hand case unsupported, pending a ruling. Do not certify that guard as a printed prohibition. The special purchase also changes the remaining compulsory auction cache: a reserved/offered card cannot simultaneously be purchased, and taking the final card can enter the already documented empty-cache/count boundary.
|
||||
**Timing remains unresolved:** the retrieved paragraphs do not specify full-hand acquisition/discard precedence. The current visibly provisional exchange policy above supersedes the earlier spare-slot guard; it is not a publisher answer. The final-cache boundary is resolved by the 7 October exhausted-cache ruling. Reserved auction custody remains binding.
|
||||
|
||||
**Atomic contract.** Validate advanced Richese ownership, unused special power, exact owned Karama, exact unreserved cached identity, funds, capacity policy and timing before paying or consuming either card. Persist a normalized intent if an independent response is required. Apply the purchase, discard and once-per-game flag once; resume the original phase/auction checkpoint without rebuilding pools. Project the selected face only to the entitled owner; other players do not receive the cache list or selected identity through pending intent, validation errors or logs. Cache/hand counts may update without naming the acquired face.
|
||||
|
||||
@@ -45,10 +69,10 @@ Distrans itself as the gifted card is not resolved by the face's give-then-disca
|
||||
|
||||
## 4. Nullentropy Box
|
||||
|
||||
**8 October Basic runtime amendment:** Nullentropy Box now supports a visibly
|
||||
provisional full-hand atomic exchange, preserving the final limit and discarding
|
||||
the used Box last. This does not settle the printed intermediate-capacity
|
||||
question; Advanced remains guarded. [Current Box contract](NULLENTROPY_BOX_ENGINE_AUDIT.md).
|
||||
**8 October runtime amendment:** Nullentropy Box supports a visibly
|
||||
provisional full-hand atomic exchange in Basic and Advanced, preserving
|
||||
the final limit and discarding the used Box last. Intermediate capacity is
|
||||
not adjudicated. [Current Box contract](NULLENTROPY_BOX_ENGINE_AUDIT.md).
|
||||
|
||||
**Exact printed sequence, in original prose:**
|
||||
|
||||
@@ -75,7 +99,7 @@ Semuta's response to the final Box discard, multiple discard triggers, deck recy
|
||||
|
||||
## Bounded special-purchase integration checkpoint
|
||||
|
||||
The engine's existing SpecialKaramaIntent now has a Richese branch, with a separate Emperor purchase-income response. The owner-only `richeseSpecialKarama` projection supplies legal cache choices, spendable activating Karamas, a blocked reason and the payment recipient. Full-hand and final-cache acquisition remain guarded. This does not activate gifts, Distrans or Box.
|
||||
SpecialKaramaIntent has a Richese branch and separate Emperor income. The owner-only projection supplies legal cache choices, spendable Karamas, availability and payee. Full-hand exchange and final-cache acquisition are connected above. Gift, Distrans and Box remain separate effects with their own current contracts.
|
||||
|
||||
`components/richese-special-karama.tsx` is integrated beside the private hand's other faction tools. It has separate activation/cache selectors and enlarged inspectors, a three-spice/once-per-game explanation, payment recipient and authoritative unavailable reason. It sends the exact activating and acquired physical IDs. There is no acknowledgement step or public cache projection. `game/reference.ts` adds `richese-acquisition` with all five checklist facets and source-boundary explanations.
|
||||
|
||||
@@ -85,8 +109,8 @@ Four named scenarios in `tests/richese-acquisition-bots.test.ts` pass across all
|
||||
|
||||
## Integrated purchase checkpoint
|
||||
|
||||
The special Karama branch is now wired through the authoritative normalized-intent validator/executor. It validates exact canonical cache custody, unused Advanced Richese power, spendable owned Karama and three uncommitted own spice. A currently offered cache card cannot be taken out of its auction. Full-hand activation and acquiring the final cache card remain explicit unresolved development guards.
|
||||
The normalized-intent validator/executor checks canonical cache custody, unused Advanced Richese power, spendable held Karama and three uncommitted own spice. An offered cache card stays reserved. Full-hand exchange uses the provisional final-capacity policy; final-cache purchase follows the resolved exhausted-cache rule.
|
||||
|
||||
The completed purchase discards the activating Karama, moves the selected physical card to the hand and consumes the once-per-game power atomically. Its identity is absent from public response state and logs. An independent Emperor-income response preserves the exact parent response, decision and pending Bene Gesserit conversion; payment goes to Emperor or the bank after that response, without an auction bonus or Ixian replacement. Restored continuations never replay the acquisition.
|
||||
|
||||
Private controls and all four AI profiles are integrated. Current AI conservatively buys only the functional canonical Karama and retains spice; the other nine effects remain unfinished. Eight primary engine tests, nine independent review tests, four AI scenarios and two additional persisted concurrency/restart scenarios pass. A real desktop browser purchase and fresh-tab seat restoration across the controlled server restart passed in QPNV5XJJ. The broader full-hand/final-cache boundaries, gift, Distrans and Box remain unfinished; no full Richese game is certified.
|
||||
**Historical initial checkpoint:** eight engine, nine review, four AI and two persisted concurrency/restart scenarios plus QPNV5XJJ desktop purchase/restoration established the earlier bounded flow. Those dated results do not verify today's capacity/exhaustion changes. Current full-hand/final-cache behavior and separate gift/Distrans/Box contracts supersede the old absence claims; full Richese certification remains open.
|
||||
@@ -36,6 +36,11 @@ Turn-end set-aside is supplied text; one-battle loan release remains the
|
||||
explicit provisional implementation policy. Existing exceptional custody and
|
||||
Advanced Harkonnen guards remain. [Current Duke grant contract](ECAZ_DUKE_ACQUISITION.md).
|
||||
|
||||
Richese special Karama may now buy its final cached card under the 7 October
|
||||
exhausted-cache ruling. Its full-hand spent-Karama exchange uses an explicitly
|
||||
provisional final-capacity policy, not a numerical user ruling. Separate
|
||||
income and reservation safeguards remain. [Acquisition contract](RICHESE_ACQUISITION_RULES.md).
|
||||
|
||||
Advanced Richese ordinary mixed battles, Guild/active-Karama allied prices
|
||||
and full-hand Box now share the visibly qualified Basic prototype policies.
|
||||
Native Advanced support and shipment prevention remain separate. These are
|
||||
|
||||
+2
-2
@@ -2908,8 +2908,8 @@ function policyActions(g: GameView): Action[] {
|
||||
richesePurchase.karamas.length &&
|
||||
(me.spice ?? 0) >= [6, 7, 8, 8][level]
|
||||
) {
|
||||
// Until the other cache effects are enabled, acquire only the usable
|
||||
// canonical Karama. Keep a spice reserve and never inspect a hidden cache.
|
||||
// Minimal legal participation prefers reusable canonical Karama.
|
||||
// Keep a spice reserve and never inspect another player's hidden cache.
|
||||
const choice = richesePurchase.cards.find(
|
||||
(card) => richeseCardDefinition(card)?.card.effect === 'karama',
|
||||
);
|
||||
|
||||
+2
-6
@@ -26808,8 +26808,8 @@ export function prepareSpecialKaramaIntent(
|
||||
'The Karama reserved for Black Market cannot activate another effect.',
|
||||
);
|
||||
requireRule(
|
||||
p.hand.length < handLimit(p),
|
||||
'Special Richese Karama with a full hand awaits a ruling on acquisition and discard order.',
|
||||
p.hand.length <= handLimit(p),
|
||||
'The final exchanged hand must not exceed its hand limit.',
|
||||
);
|
||||
requireRule(
|
||||
uncommittedSpice(g, p) >= 3,
|
||||
@@ -26831,10 +26831,6 @@ export function prepareSpecialKaramaIntent(
|
||||
g.richeseAuction.cardId !== acquire,
|
||||
'The card already offered for auction must remain in that auction.',
|
||||
);
|
||||
requireRule(
|
||||
g.richeseCache!.length > 1,
|
||||
'Buying the final cache card awaits the empty-cache Bidding rule implementation.',
|
||||
);
|
||||
return { ...base, kind: 'richese', acquire };
|
||||
} else if (p.faction === 'choam') {
|
||||
requireRule(
|
||||
|
||||
+3
-2
@@ -558,6 +558,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
title: 'Richese special Karama purchase',
|
||||
category: 'Advanced & expansions',
|
||||
coverage: 'Partial',
|
||||
developmentStage: 'Prototyped',
|
||||
summary:
|
||||
'Spend a Karama and three spice once per game to choose a private cache card for your own hand.',
|
||||
steps: [
|
||||
@@ -566,7 +567,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
'A Karama cannot cancel the special purchase itself. Emperor income has a separate response: canceling that income does not undo the purchase or restore the spent special power.',
|
||||
'The separate Richese Nexus Betrayal preview connects ordinary public self-cache auctions, not this private special acquisition. The native Karama cancellation exception above is not authority for deciding whether Nexus Betrayal applies to a special purchase.',
|
||||
'The private hand panel provides both card selectors and enlarged inspection. It shows the payment recipient and the server’s current availability reason. A reserved auction card cannot be taken from that lot. Spending pledged or already committed funds is not allowed.',
|
||||
'Full-hand activation is guarded pending a ruling on when the spent Karama leaves the hand. Buying the final cached card is also guarded pending the empty-cache auction rule. Pending interactions may need to finish first. These development limits are not claimed as printed prohibitions.',
|
||||
'Full-hand activation now has a visibly provisional exchange policy: spend the held Karama and acquire one cache card, leaving the final hand within its actual limit. This is not a publisher timing clarification or numerical user ruling. Buying the final cached card is legal under the resolved exhausted-cache auction rule; subsequent Bidding restores the ordinary pool. Reserved cards, over-limit hands and pending commitments remain ineligible.',
|
||||
'All four AI profiles can choose the canonical Richese Karama when the projection allows it and enough spice remains. They leave other cache effects to future implementation and give pending responses, decisions and Truthtrance priority.',
|
||||
'Richese ally gifts, Distrans transfer and Nullentropy Box search have their own hand-panel controls and rules topics. These are separate from special Karama purchase and retain their own capacity, timing and private-custody boundaries. Selectable Richese and combined advanced starts remain disabled.',
|
||||
],
|
||||
@@ -584,7 +585,7 @@ export const RULE_TOPICS: RuleTopic[] = [
|
||||
area: 'Implementation',
|
||||
status: 'Partial',
|
||||
detail:
|
||||
'Private cache acquisition, once-per-game consumption and separate Emperor income are integrated in development fixtures. Full-hand, final-cache and further transfer/search cases remain guarded or unfinished.',
|
||||
'Private cache acquisition, once-use and separate Emperor income are integrated. Full-hand exchange is a visibly provisional final-capacity policy; final-cache acquisition reaches the resolved ordinary Bidding continuation. Further timing and transfer/search compositions remain open.',
|
||||
},
|
||||
{
|
||||
area: 'Player controls',
|
||||
|
||||
@@ -90,7 +90,7 @@ void test('all four profiles acquire only usable canonical Karama and settle onc
|
||||
}
|
||||
});
|
||||
|
||||
void test('all profiles decline unavailable, used, basic, full-hand and low-budget purchases', () => {
|
||||
void test('all profiles decline unavailable, used, basic and low-budget purchases', () => {
|
||||
for (const difficulty of DIFFICULTIES) {
|
||||
for (const change of [
|
||||
(g: Game) => {
|
||||
@@ -102,9 +102,6 @@ void test('all profiles decline unavailable, used, basic, full-hand and low-budg
|
||||
(g: Game) => {
|
||||
g.players[0].spice = 3;
|
||||
},
|
||||
(g: Game) => {
|
||||
g.players[0].hand.push(...g.deck.splice(0, 3));
|
||||
},
|
||||
(g: Game) => {
|
||||
g.players[0].hand = [];
|
||||
},
|
||||
|
||||
@@ -279,16 +279,8 @@ void test('special purchase cannot spend sealed bid funds or take the already of
|
||||
rejected(g, { ...action, acquire: offered }, /offered for auction/);
|
||||
});
|
||||
|
||||
void test('full-hand, final-cache and noncanonical selections remain explicit atomic unsupported or invalid cases', () => {
|
||||
let g = fixture();
|
||||
const action = command(g);
|
||||
g.players[0].hand.push(...g.deck.splice(0, 3));
|
||||
rejected(g, action, /full hand.*ruling/);
|
||||
g = fixture();
|
||||
const last = command(g);
|
||||
g.richeseCache = g.richeseCache!.filter((c) => c.id === last.acquire);
|
||||
rejected(g, last, /final cache.*implementation/);
|
||||
g = fixture();
|
||||
void test('noncanonical cache selections remain invalid before any purchase cost', () => {
|
||||
const g = fixture();
|
||||
const fake = command(g);
|
||||
g.richeseCache!.find((c) => c.id === fake.acquire)!.name =
|
||||
'Invented replacement';
|
||||
|
||||
@@ -156,19 +156,24 @@ void test('private options validate exactly and do not mutate state or expose ca
|
||||
g.richeseCache![0].name = 'Forged face';
|
||||
assert.throws(() => purchase(g), /verified card/);
|
||||
});
|
||||
void test('full-hand and last-cache capacity edges remain explicit atomic implementation guards', () => {
|
||||
const g = fixture();
|
||||
g.players[0].hand.push(...g.deck.splice(0, 3));
|
||||
const before = JSON.stringify(g);
|
||||
assert.throws(() => purchase(g), /awaits a ruling/);
|
||||
assert.equal(JSON.stringify(g), before);
|
||||
assert.match(
|
||||
viewGame(g, 'r').richeseSpecialKarama!.blocked!,
|
||||
/awaits a ruling/,
|
||||
);
|
||||
g.players[0].hand.splice(1);
|
||||
g.richeseCache = g.richeseCache!.slice(0, 1);
|
||||
assert.throws(() => purchase(g), /empty-cache/);
|
||||
|
||||
void test('full-hand special purchase exchanges the spent Karama and may exhaust the cache under the resolved auction rule', () => {
|
||||
const start = fixture();
|
||||
start.players[0].hand.push(...start.deck.splice(0, 3));
|
||||
const spent = start.players[0].hand.find(card => card.effect === 'karama')!.id;
|
||||
const chosen = start.richeseCache!.find(card => card.id === 'richese-ornithopter')!;
|
||||
start.richeseRemoved!.push(...start.richeseCache!.filter(card => card.id !== chosen.id));
|
||||
start.richeseCache = [chosen];
|
||||
const held = start.players[0].hand.filter(card => card.id !== spent).map(card => card.id);
|
||||
const result = purchase(start, chosen.id);
|
||||
assert.equal(result.players[0].hand.length, 4);
|
||||
assert.ok(held.every(id => result.players[0].hand.some(card => card.id === id)));
|
||||
assert.ok(result.players[0].hand.some(card => card.id === chosen.id));
|
||||
assert.equal(result.discard.filter(card => card.id === spent).length, 1);
|
||||
assert.equal(result.richeseCache!.length, 0);
|
||||
assert.equal(result.players[0].spice, 7);
|
||||
assert.equal(result.players[2].spice, 13);
|
||||
assert.equal(result.players[0].specialKaramaUsed, true);
|
||||
});
|
||||
void test('insufficient or pledged spice, Basic mode, used power and committed Karama are rejected atomically', () => {
|
||||
for (const configure of [
|
||||
|
||||
Reference in new issue
Block a user