Keep forced Silent bids indistinguishable in notices

This commit is contained in:
Quintine committed 2026-10-27 18:09:16 +11:00
1 parent b64c657c1d
commit 4690200f59
6 files changed
+41 -7

No files matched your search

+7
View File
@@ -20,6 +20,13 @@ open mode gates.
Keep identified Basic-function gaps ahead of Advanced and wider interactions.
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.**
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
+11
View File
@@ -1,5 +1,16 @@
# 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
Extend the current public-event bid question to a single sealed Silent
+2 -1
View File
@@ -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
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
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)
supports action commitments while possible, but does not supply this specific
+4 -2
View File
@@ -18581,8 +18581,10 @@ function finishAutomaticDecision(g: Game): boolean {
const player = getPlayer(g, full);
log(
g,
`${player.name} automatically ${lot.method === 'silent' ? 'submitted a sealed bid' : 'passed'} because their hand became full before bidding.`,
{ faction: player.faction, name: lot.method === 'silent' ? 'Full hand: sealed submission' : 'Full hand: no bid' },
lot.method === 'silent'
? `${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)
log(
+1 -1
View File
@@ -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].hand.length, 4);
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();
for (const id of ['h', 'e', 'r']) unbid = bid(unbid, id, 0);
+16 -3
View File
@@ -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.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 settled = normalizeAutomaticGame(harmed);
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.ok(observer.submitted.includes(f.target));
const fresh = settled.log.filter(entry => entry.seq > beforeSequence);
assert.ok(fresh.some(entry => entry.text.includes('submitted a sealed bid')));
assert.ok(fresh.every(entry => !/revealed together|zero|0 spice|no bid/i.test(`${entry.text} ${entry.automatic?.name ?? ''}`)),
'Automatic public notices must not disclose the sealed zero before reveal');
const automaticNotice = fresh.find(entry => entry.text.includes('submitted a sealed bid')); assert.ok(automaticNotice);
assert.equal(automaticNotice.text,manualNotice.text,
'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);
});
}