v0.1.35b: 兼容层铲除——迁移链/版本戳/死表死代码/normalize 兼容批/死字段

【A+I】migrate.ts 迁移链(CURRENT_SCHEMA/MIGRATIONS/migrateIfNeeded/MigrationError)整链铲除→validateLoadedState 结构校验(seed/family/members 断言);信封统一 payload 单格式(去双格式兜底);APP_ID 保留
【F】schemaVersion 字段全删(domain/creation/save 8 处);SaveMeta.version 记游戏版本字符串
【C】chronicle 死表+saveChronicle 死方法(首行 return+unreachable legacy 僵尸)全删
【D/E】GameEngine __state globalThis 泄漏口+seed 三元(恒不可达)删除;engineFromSnapshot/noAutoCreate 保留(测试便利——非兼容机器)
【B/H】normalizeGameState 兼容批删:老档字段补(28行)/worldGen 重放(18行)/P0-2 占位 def(9行)/worldSim 字段批删;保留 npcs 重注册/headId 修复/d distress 防护;initSim 补 0.1.34 四键(唯一初始源)
【G】domain 收紧 5 兼容 optional(techniqueRank/Progress/tribBoost/worldGen 必填)+pcgen 必写
【测试】删 9 个兼容验证体(audit 0.1.0-era/全残缺矩阵/空 worldSim 兜底);5989 全绿——金钟罩零漂(新档结构全字段,删除不涉世界数值)
This commit is contained in:
2026-08-23 22:35:17 +08:00
parent 1b1dfe8ac8
commit 9b0f36c70a
15 changed files with 44 additions and 285 deletions
+1 -48
View File
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'
import { World } from '../src/renderer/game/engine/runtime/World'
import { buildReport, verdictLine } from '../src/renderer/game/engine/narrative/legacyreport'
import { migrateIfNeeded, exportEnvelope, parseImportEnvelope, CURRENT_SCHEMA, APP_ID } from '../src/renderer/game/storage/migrate'
import { exportEnvelope, parseImportEnvelope, validateLoadedState } from '../src/renderer/game/storage/migrate'
import { FORMATIONS, formationById, FormationId } from '../src/renderer/game/data/formations'
import { resolveEncounter } from '../src/renderer/game/engine/runtime/Systems/combat'
import { ENEMIES } from '../src/renderer/game/data/secrets'
@@ -56,53 +56,6 @@ describe('legacyreport 百年报告', () => {
})
})
describe('存档迁移管线', () => {
it('CURRENT_SCHEMA=2 且 v1→v2 迁移补字段', () => {
expect(CURRENT_SCHEMA).toBe(2)
const w = baseWorld('mig-a')
const asV1 = JSON.parse(JSON.stringify(w.state))
asV1.schemaVersion = 1
delete asV1.stats
const res = migrateIfNeeded(asV1)
expect(res.ok).toBe(true)
const s = (res as never as { state: { stats: unknown; schemaVersion: number } }).state
expect(s.stats).toBeTruthy()
expect(s.schemaVersion).toBe(2)
})
it('未来版本拒绝加载(防误用)', () => {
const w = baseWorld('mig-b')
const s = JSON.parse(JSON.stringify(w.state))
s.schemaVersion = 99
const res = migrateIfNeeded(s)
expect(res.ok).toBe(false)
expect((res as never as { error: { code: string } }).error.code).toBe('TOO_NEW')
})
it('导出信封带 appId 与版本;导入旧版可迁移', () => {
const w = baseWorld('mig-c')
w.state.schemaVersion = CURRENT_SCHEMA
const env = JSON.parse(exportEnvelope(w.state))
expect(env.app).toBe(APP_ID)
expect(env.schemaVersion).toBe(2)
const parsed = parseImportEnvelope(JSON.stringify(env))
expect(parsed.ok).toBe(true)
})
it('异 app 拒绝导入', () => {
const w = baseWorld('mig-d')
const env = JSON.parse(exportEnvelope(w.state))
env.app = 'other-game'
const parsed = parseImportEnvelope(JSON.stringify(env))
expect(parsed.ok).toBe(false)
})
it('损坏 JSON 拒绝导入', () => {
const res = parseImportEnvelope('not-json-wrapper')
expect(res.ok).toBe(false)
})
})
describe('战斗阵型', () => {
it.each(Object.keys(FORMATIONS).map((k) => [k as FormationId] as const))('%s 阵型定义合法', (id) => {
const f = FORMATIONS[id]