Keep forced Silent bids indistinguishable in notices
This commit is contained in:
1 parent
b64c657c1d
commit
4690200f59
6 files changed
+41
-7
No files matched your search
@@ -20,6 +20,13 @@ open mode gates.
|
|||||||
Keep identified Basic-function gaps ahead of Advanced and wider interactions.
|
Keep identified Basic-function gaps ahead of Advanced and wider interactions.
|
||||||
Prototype labels and final acceptance gates remain.
|
Prototype labels and final acceptance gates remain.
|
||||||
|
|
||||||
|
**Silent automatic submission notice — 27 October.**
|
||||||
|
A full hand's forced Silent submission now uses the same public text as a
|
||||||
|
manual sealed bid and a neutral animation tag, instead of announcing the
|
||||||
|
reason for a forced zero. Public hand counts can still allow inference. The
|
||||||
|
existing native reveal and automatic settlement remain unchanged. Five focused
|
||||||
|
files pass 54/54; type/lint passed before the intervening test-only CI fix.
|
||||||
|
|
||||||
**Richese Silent Truthtrance bid — 27 October. Prototyped / Partial.**
|
**Richese Silent Truthtrance bid — 27 October. Prototyped / Partial.**
|
||||||
The event-bound Richese question also supports one sealed Silent submission.
|
The event-bound Richese question also supports one sealed Silent submission.
|
||||||
Yes requires a qualifying bid; No permits zero or a lower bid. Feasibility uses
|
Yes requires a qualifying bid; No permits zero or a lower bid. Feasibility uses
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# Dune implementation status
|
# Dune implementation status
|
||||||
|
|
||||||
|
## 27 October 2026 — Silent automatic notice
|
||||||
|
|
||||||
|
Use the same public text for forced and manual sealed submissions, and a
|
||||||
|
neutral automatic tag, so the notice itself does not identify a full hand or a
|
||||||
|
zero bid. Public hand counts can still permit inference. Basic/Advanced cases
|
||||||
|
compare real manual and forced events while retaining sealed views, promise
|
||||||
|
receipts and conserved physical cards; the full-hand setup is controlled.
|
||||||
|
Five focused files pass 54/54; type/lint passed before the intervening test-only
|
||||||
|
CI fix. Private reports are `20261027-silent-neutral-notice-proof-v1/` and
|
||||||
|
`20261027-silent-neutral-notice-proof-v2/`. No browser or deployment result is claimed.
|
||||||
|
|
||||||
## 27 October 2026 — Richese Silent bid Truthtrance
|
## 27 October 2026 — Richese Silent bid Truthtrance
|
||||||
|
|
||||||
Extend the current public-event bid question to a single sealed Silent
|
Extend the current public-event bid question to a single sealed Silent
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ The answer and guide use only the respondent's actual available funds and aid,
|
|||||||
not other sealed amounts. All eligible submissions retain native escrow and
|
not other sealed amounts. All eligible submissions retain native escrow and
|
||||||
reveal simultaneously in original tie order; only the winner pays. When a hand
|
reveal simultaneously in original tie order; only the winner pays. When a hand
|
||||||
becomes full, the native automatic zero releases an impossible Yes or completes
|
becomes full, the native automatic zero releases an impossible Yes or completes
|
||||||
No. Its public text and action tag do not announce the amount before reveal.
|
No. Its public text matches a manual sealed submission and its action tag is neutral. Public hand counts can still allow inference of a forced zero. Five focused
|
||||||
|
files pass 54/54; type/lint passed before the intervening test-only CI fix.
|
||||||
|
|
||||||
The [GF9 November 2020 FAQ p8](https://www.gf9games.com/dune/wp-content/uploads/2020/11/Dune-FAQ-Nov-2020.pdf#page=8)
|
The [GF9 November 2020 FAQ p8](https://www.gf9games.com/dune/wp-content/uploads/2020/11/Dune-FAQ-Nov-2020.pdf#page=8)
|
||||||
supports action commitments while possible, but does not supply this specific
|
supports action commitments while possible, but does not supply this specific
|
||||||
|
|||||||
+4
-2
@@ -18581,8 +18581,10 @@ function finishAutomaticDecision(g: Game): boolean {
|
|||||||
const player = getPlayer(g, full);
|
const player = getPlayer(g, full);
|
||||||
log(
|
log(
|
||||||
g,
|
g,
|
||||||
`${player.name} automatically ${lot.method === 'silent' ? 'submitted a sealed bid' : 'passed'} because their hand became full before bidding.`,
|
lot.method === 'silent'
|
||||||
{ faction: player.faction, name: lot.method === 'silent' ? 'Full hand: sealed submission' : 'Full hand: no bid' },
|
? `${player.name} submitted a sealed bid; its amount remains concealed until every eligible bidder submits.`
|
||||||
|
: `${player.name} automatically passed because their hand became full before bidding.`,
|
||||||
|
{ faction: player.faction, name: lot.method === 'silent' ? 'Sealed bid' : 'Full hand: no bid' },
|
||||||
);
|
);
|
||||||
if (lot.method === 'silent' && g.richeseAuction.outcome)
|
if (lot.method === 'silent' && g.richeseAuction.outcome)
|
||||||
log(
|
log(
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ void test('restored full hands automatically submit zero or remove an unbid cach
|
|||||||
assert.equal(g.players[0].spice, 22);
|
assert.equal(g.players[0].spice, 22);
|
||||||
assert.equal(g.players[0].hand.length, 4);
|
assert.equal(g.players[0].hand.length, 4);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
g.log.some((entry) => entry.text.includes('automatically submitted a sealed bid')),
|
g.log.some((entry) => entry.text.includes('submitted a sealed bid; its amount remains concealed')),
|
||||||
);
|
);
|
||||||
let unbid = cache();
|
let unbid = cache();
|
||||||
for (const id of ['h', 'e', 'r']) unbid = bid(unbid, id, 0);
|
for (const id of ['h', 'e', 'r']) unbid = bid(unbid, id, 0);
|
||||||
|
|||||||
@@ -113,6 +113,15 @@ for (const advanced of [false, true]) for (const answer of ['yes','no'] as const
|
|||||||
}
|
}
|
||||||
assert.deepEqual(inventory(harmed),f.originalCards);
|
assert.deepEqual(inventory(harmed),f.originalCards);
|
||||||
assert.equal(Object.hasOwn(harmed.richeseAuction!.sealed,f.target),false);
|
assert.equal(Object.hasOwn(harmed.richeseAuction!.sealed,f.target),false);
|
||||||
|
// Compare the automatic notice to an actual manual submission from the
|
||||||
|
// same public game state. The original Yes can bid 4; No can submit zero.
|
||||||
|
const manualBefore = bound.log.at(-1)?.seq ?? 0;
|
||||||
|
const manual = act(bound,f.target,{type:'richeseBid',event:f.lot,
|
||||||
|
amount:answer === 'yes' ? 4 : 0,allyPayment:0});
|
||||||
|
const manualNotice = manual.log.find(entry => entry.seq > manualBefore &&
|
||||||
|
entry.text.includes('submitted a sealed bid')); assert.ok(manualNotice);
|
||||||
|
assert.equal(viewGame(manual,f.owner).richeseAuction?.revealedBids,null);
|
||||||
|
assert.deepEqual(inventory(manual),f.originalCards);
|
||||||
const beforeSequence = harmed.log.at(-1)?.seq ?? 0;
|
const beforeSequence = harmed.log.at(-1)?.seq ?? 0;
|
||||||
const settled = normalizeAutomaticGame(harmed);
|
const settled = normalizeAutomaticGame(harmed);
|
||||||
const receipt = settled.richeseBidPromises!.find(row => row.player === f.target); assert.ok(receipt);
|
const receipt = settled.richeseBidPromises!.find(row => row.player === f.target); assert.ok(receipt);
|
||||||
@@ -123,9 +132,13 @@ for (const advanced of [false, true]) for (const answer of ['yes','no'] as const
|
|||||||
assert.equal(observer.ownBid,null); assert.equal(observer.revealedBids,null);
|
assert.equal(observer.ownBid,null); assert.equal(observer.revealedBids,null);
|
||||||
assert.ok(observer.submitted.includes(f.target));
|
assert.ok(observer.submitted.includes(f.target));
|
||||||
const fresh = settled.log.filter(entry => entry.seq > beforeSequence);
|
const fresh = settled.log.filter(entry => entry.seq > beforeSequence);
|
||||||
assert.ok(fresh.some(entry => entry.text.includes('submitted a sealed bid')));
|
const automaticNotice = fresh.find(entry => entry.text.includes('submitted a sealed bid')); assert.ok(automaticNotice);
|
||||||
assert.ok(fresh.every(entry => !/revealed together|zero|0 spice|no bid/i.test(`${entry.text} ${entry.automatic?.name ?? ''}`)),
|
assert.equal(automaticNotice.text,manualNotice.text,
|
||||||
'Automatic public notices must not disclose the sealed zero before reveal');
|
'Forced and manual submissions use the same public notice before reveal');
|
||||||
|
assert.ok(!automaticNotice.automatic || automaticNotice.automatic.name === 'Sealed bid',
|
||||||
|
'An optional automatic-action tag must use a neutral name');
|
||||||
|
assert.ok(fresh.every(entry => !/revealed together|zero|0 spice|no bid|full hand|hand became full/i.test(`${entry.text} ${entry.automatic?.name ?? ''}`)),
|
||||||
|
'Automatic public notices and tags must not directly disclose the forced-zero reason before reveal');
|
||||||
assert.deepEqual(inventory(settled),f.originalCards);
|
assert.deepEqual(inventory(settled),f.originalCards);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user