Files
ChronicleOfTheImmortalClan/tests/clock.test.ts
T
thzxx be6f2f5fe7 v0.1.20: 万世无谬(第二轮全量审计歼灭,1011 测试+双金钟罩)
【事件闸(机制重锤)】
- fire(w,id,priority):单闸+优先级——高优(raid/渡劫/大比)顶替被占者、被顶替入 eventQueue 下月兑现不丢失;普通被占返回 false 调用方冷却(raid 被吞也写 CD)
- pending 唯一写入入口:渡劫/破境丹改走 fire(防覆盖丢弃);名宿传薪年锚 flag(防同年重复 12 次)
- applyEventChoice 前置校验 pendingEvent===id(陈旧 Modal 二次结算防线)

【世界模型四修(真·活世界)】
- era 延续档:flow 权重和<1(留白=续任)——盛世能撑 30 年而非固定 25
- 潮汐供给符号修正:灵涨万物丰(原实现反了)+tide 双界 clamp
- driftMarket 弱锚定:rebalance 0.1→0.025——供需/era/灾年真实撬动价格(原五池被锚死±5%)
- 断供/池底单常量 poolFloorPct=0.35(消灭禁买暗雷带)

【知识防线(审计虫洞修复)】
- 指纹扩展:era/stance/prosperity/relationsWithOthers/calamityLeft/pendingEvent 全入 hash
- 第二金钟罩 GOLDEN_RESOLVED:自动 resolve 长跑锁“现实”世界(原指纹锁的只是“事件流冻结”世界)

【性能与存储】
- 存档节流(疾12/常6/缓4,手动即时)+ saveChronicle O(N)→O(1) 单查增量写(2160 月档告别每 tick 数千 OPFS)
- battles≤220/chronicle≤520 截断(stringify 线性膨胀止血);startNewGame/openState 停 timer 摘旧 bus

【杂项】actDirect 对齐 ACT_CATALOG 全 24 项;about 三版本统一 0.1.20;kernel.bus 死总线删;seed 改 RngHub.rollSeed;normalize 补 eraStartYear/overflux/distress;WorldPanel 买卖条件反转修复;音效与视效同闸

【测试】1011 全绿(42 套件):audit-0.1.20 9 例(事件闸/传薪/二次结算/era延续/潮汐符号/断供一致/弱锚定/指纹敏感)
2026-08-23 15:14:28 +08:00

57 lines
2.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { stateFingerprint, longRun } from './fingerprint.helper'
import { World } from '../src/renderer/game/engine/runtime/World'
/**
* 金钟罩:固定种子长跑 560 月的状态指纹。
* 任何改动(重构日程/调平衡/加系统)若改变了确定性序列或结果,此测试立刻报红。
* 更新规则:仅当**有意**变更序列逻辑时,三枚 seed 指纹同版更新并注明原因。
*/
// 0.1.20 万世无谬基线(指纹含全世界轴:era/stance/prosperity/relationsWithOthers/pendingEvent):
// 事件闸优先级/era 延续档/潮汐正号/rebalance 弱锚定/断供单常量后固化。
const GOLDEN: Record<string, Record<number, string>> = {
'bell-seed-1': { 560: '3b784f49', 1200: 'b62fada2', 2160: '999782cc' },
'bell-seed-2': { 560: '0f73bffb', 1200: '454eedc9', 2160: '426c967f' },
'bell-seed-3': { 560: '0bf7ec62', 1200: '06cf0213', 2160: '51feb3ee' }
}
/** 第二金钟罩:自动 resolve 长跑("现实"世界——每 tick 处理待决事件;
* 锁事件闸/事件流全程,防"冻结世界"指纹漏锁)。 */
const GOLDEN_RESOLVED: Record<string, Record<number, string>> = {
'bell-seed-1': { 560: 'b28b99f9', 1200: 'ffd53c37', 2160: 'd7eadca0' },
'bell-seed-2': { 560: 'c712ad0f', 1200: '2304c1c4', 2160: '76519353' },
'bell-seed-3': { 560: '6878460d', 1200: '6633cdde', 2160: 'f285188f' }
}
const TIERS = [
[560, '47 年(4 个十年)'],
[1200, '100 年'],
[2160, '180 年']
] as const
describe('金钟罩 · 长跑确定性指纹(三档:47/100/180 年)', () => {
for (const [seed, tiers] of Object.entries(GOLDEN)) {
for (const [months, label] of TIERS) {
it(`${seed} ${label}指纹 === ${tiers[months]}`, () => {
const w = run(seed, months)
expect(stateFingerprint(w.state)).toBe(tiers[months])
})
}
}
it('同 seed 两次长跑指纹一致(无状态污染)', () => {
const a = stateFingerprint(longRun('bell-seed-1').state)
const b = stateFingerprint(longRun('bell-seed-1').state)
expect(a).toBe(b)
})
})
function run(seed: string, months: number): ReturnType<typeof longRun> {
const w = World.create({ seed, surname: '钟', familyName: '钟家', motto: 'm', difficulty: 'normal' })
for (let i = 0; i < months; i++) {
if (w.state.gameOver) break
w.advanceMonth()
}
return w
}