feedback5: the co-op browser test reads phase, funds, price, free refreshes and shop slots in one store snapshot when it checks the R refresh — two page reads could straddle the m.private that answers R and pair the new slots with the old funds, failing "host: refresh cost 6 !== 5" under the full pass's load (1 of 4 in full020c; the same check passes alone, "funds 6 → 5"); golden: unchanged (test only)

This commit is contained in:
sganggs committed 2026-10-07 06:28:50 +08:00
1 parent 2802a368c3
commit 13b52450d6
1 file changed
+15 -9
+15 -9
View File
@@ -193,23 +193,29 @@ async function levelUp(c, { shot = null } = {}) {
}
async function refreshKey(c) {
const s = await c.st();
if (s.funds < s.refreshPrice) return false;
const shop = () => c.page.evaluate(() => { const sh = globalThis.__SP__.store.get().match.private.shop; return { ids: JSON.stringify(sh.slots.map((x) => x && x.id)), free: sh.freeRefreshes }; });
// phase, funds, price, free counter and slots from ONE store snapshot: the m.private that answers R carries them all,
// and two separate reads could straddle it — the new slots with the old funds, a false "refresh cost" under load
const shop = () => c.page.evaluate(() => {
const st = globalThis.__SP__.store.get();
const priv = st.match.private;
const sh = priv.shop;
return { phase: st.match.public?.phase ?? null, funds: priv.funds, price: sh.refreshPrice, free: sh.freeRefreshes, ids: JSON.stringify(sh.slots.map((x) => x && x.id)) };
});
const before = await shop();
if (before.funds < before.price) return false;
await c.page.mouse.click(c.w / 2, c.h * 0.3); // focus the page (not a text field)
await c.page.keyboard.press('KeyR');
// a free refresh (机变 补给 …) changes the free counter, a paid one the funds; the slots are rerolled either way
const t0 = Date.now();
let after = null; let now = null;
let now = null;
while (Date.now() - t0 < 6000) {
after = await c.st(); now = await shop();
if (after.phase !== 'PREP' || after.funds !== s.funds || now.free !== before.free || now.ids !== before.ids) break;
now = await shop();
if (now.phase !== 'PREP' || now.funds !== before.funds || now.free !== before.free || now.ids !== before.ids) break;
await sleep(150);
}
assert.ok(after.funds !== s.funds || now.free !== before.free || now.ids !== before.ids, `${c.label}: R refreshed the shop`);
if (s.refreshPrice > 0) assert.equal(after.funds, s.funds - s.refreshPrice, `${c.label}: refresh cost`);
c.note(`refresh (R) ${s.refreshPrice ? `funds ${s.funds} → ${after.funds}` : `free (${before.free} → ${now.free})`}, slots ${before.ids === now.ids ? 'same ids' : 'rerolled'}`);
assert.ok(now.funds !== before.funds || now.free !== before.free || now.ids !== before.ids, `${c.label}: R refreshed the shop`);
if (before.price > 0) assert.equal(now.funds, before.funds - before.price, `${c.label}: refresh cost`);
c.note(`refresh (R) ${before.price ? `funds ${before.funds} → ${now.funds}` : `free (${before.free} → ${now.free})`}, slots ${before.ids === now.ids ? 'same ids' : 'rerolled'}`);
return true;
}