Commit Graph

286 Commits

Author SHA1 Message Date
7121c93914 test: update replay command assertions after ReplayCode rename
49aacb0 renamed ReplayMoveCommand -> ReplayMove (and siblings); sync the two stale expectations in data-state/src/replay/commands.test.ts (constructor names + core.ts source assertions).
2026-09-17 13:15:30 +08:00
0c6812fcda test(07-10): 末步 set 用例改为断言 paramUsed 的外部可观测偏移
- paramUsed 为私有成员,其正确性只能通过下一条命令参数的写入偏移观测
- 增长与缩短两条末步用例补充参数缓冲区原始字节断言,使「末步起点回退」子缺陷在未修复时可直接失败
2026-09-17 12:59:24 +08:00
5b26539b00 docs(07-10): WR-03 录像参数格式改为类型码只增不改的追加式约定
- 按 Q6=B 不加格式版本字段:array.ts 的类型码表注释写明只增不改约定(新语义必须分配新码,禁止复用),并记录 5/6/7/8 与短字符串基址的一次性重新分配
- types.ts 的 IReplaySystemSave.paramArray 与 IReplayArray.getParamArray jsDoc 同步该约定,并写明不承诺读回旧格式录像
- array.test.ts 新增类型码映射锚定用例(5/6/7/8/9/短字符串基址 9)
- system.ts 无改动(未引入版本字段)
2026-09-17 12:55:50 +08:00
35d4ad6f1c fix(07-10): 编解码自洽 —— bigint 长度字节守卫与参数计数取截断后长度
- WR-01:normalizeParam 的 bigint 分支按长度字节的真实容量(255 字节 = 2^2040)判定,|值| >= 2^2040 触发告警 152 并丢弃该参数;normalizeParamList 过滤被丢弃项,不保留占位
- WR-02:add/insert/set 写入的命令参数计数一律取标准化后的 normalizeParam.length,与 normalizeParamList 的 255 截断一致
- logger.json 的 warn 152 文案改为与真实可表示范围(2^2040 - 1)一致,并写明溢出参数会被忽略
- array.test.ts 新增 bigint 长度字节边界往返、超界丢弃后命令计数/读流对齐、256/300 参数截断计数回归
2026-09-17 12:53:27 +08:00
1f9fb18cf5 fix(07-10): 写入路径越界校验与读流跨读档过期
- insert/delete/set 在 disabled 早退后、任何缓冲读写前校验 index,越界不修改任何缓冲区并告警新码 179(携带操作名/索引/当前长度)
- insert(index === length) 判为合法追加,按 add 语义写入(paramUsed 起、indexArray[length] = paramUsed),insert 合法区间变为 [0, length]
- setReplayArray 在 rebuildIndexArray 后补 expireStreams(),活跃读流跨 ReplaySystem.loadState 标记过期(#06-17-3 / 审计 H)
- types.ts 的 insert/delete/set jsDoc 写明合法区间与越界契约
- logger.json 新增 warn 179(当前最大 warn 码 178 之后)
- array.test.ts 新增 5 条边界回归(含越界前后逐字节不变量);saveLoad.test.ts 新增活跃读流跨读档告警 156 回归
2026-09-17 12:50:45 +08:00
9ae28c68cc fix(07-10): CR-01 ReplayArray.set 索引回退起点与末步终点对齐
- set() 改用 getParamRange(index) 取 [start, end),末步终点取 paramUsed,不再直读未初始化的 indexArray[index + 1]
- 索引回退循环起点由参数字节偏移 paramStart + 1 改为命令索引 index + 1,与 delete() 同口径
- types.ts 的 IReplayArray.set jsDoc 写明允许参数编码长度变化及其后步骤索引平移
- array.test.ts 新增 6 条 CR-01 回归:中间步增长/缩短、末步增长/缩短、读流遍历(IN-03 场景)
2026-09-17 12:42:48 +08:00
fe595b7983 refactor: 存档系统应处于渲染层 2026-09-16 21:54:12 +08:00
49aacb087a refactor: 调整录像命名 2026-09-16 21:51:19 +08:00
513a9c354c fix: 读档的 executor 未执行 2026-09-16 21:44:52 +08:00
5317b2f1e3 test(06-18): add whole-map critical timing and total/avg summary table
Adds a third metric that calls the real calculateCritical for every monster on
the merged map and fully consumes the generator, plus a second console.table
with monsters / total ms (sampled median of one full-map sweep) / avg ms.
avg ms equals total ms divided by the monster count.
2026-09-16 20:39:45 +08:00
c193c4e9a9 test(06-18): add merged real-map scenario perf for buildup and map damage
Merges the first 1/5/13 real 13x13 maps into one grid-tiled map
(13x13, 39x26, 52x52 with 11/79/204 monsters), builds the scene from a real
CoreState (real converters/reducer/calculator/final effect), assigns 12 real
Enemy prefabs (3 CommonAura ranges + GuardAura) via a seeded mulberry32, and
records buildup + map damage build timings with performance.mark/measure.
Zero assertions.
2026-09-16 20:33:18 +08:00
6c4d3709d3 test(06-18): migrate 5 existing perf files to performance.mark/measure
- measureCase sampling loop now pairs mark(startTag)/mark(endTag) with
  measure(measureName, startTag, endTag) and clears marks/measures per sample
- tag names derive from caseName+scale so they never collide across cases
- WARMUP_RUNS/SAMPLE_RUNS/median/min/p95/toFixed(3)/columns unchanged
2026-09-16 20:26:42 +08:00
b2626bd438 fix(07-09): keep hero attribute instance stable and clear generic variance
- HeroAttribute.loadState replaces its private base object; the HeroAttribute wrapper identity is preserved so equipment/combat references stay valid across load (#06-17-1/#06-17-2).

- Clone the incoming base attribute in the constructor so the shared HERO_DEFAULT_ATTRIBUTE is no longer mutated across CoreState instances.

- Use any for the hero position in combat handler/aura/enemy-view generics to clear the 45 new type errors introduced by HeroAttribute implementing ISaveableContent.
2026-09-16 19:35:54 +08:00
940e31f293 test(07-09): #06-17-2 combat-side same-reference hero attribute regression
- migrate the top-level snapshot assertion to heroSave.attribute.values.hp
- add CoreState enemyContext.getBindedHero() regressions: same live attribute before/after load, no rebinding, across all compressions
2026-09-16 18:47:39 +08:00
1f0af69004 fix(07-09): #06-17-1 load hero attribute in place and keep equipment bonuses
- IHeroStateSave.attribute becomes IHeroAttributeSave<THero>; top-level modifiers removed
- HeroState.attribute is readonly and loadState delegates to attribute.loadState (never reassigns)
- delete attachAttribute from IHeroState and HeroState, and its only test case
- thin-delegate registerModifier/createModifier/createAndInsertModifier to the attribute registry
- loadEquipEffect mounts equipment modifiers with save=false so equipment bonuses only return via re-equip
- add #06-17-1 regressions: same attribute instance, bonuses kept, no double-count when type is registered
2026-09-16 18:43:33 +08:00
6a60476531 feat(07-09): make HeroAttribute own its save state in place
- add IHeroAttributeSave<THero> and have IHeroAttribute extend ISaveableContent
- move the modifier factory registry into HeroAttribute with registerModifier/createModifier/createAndInsertModifier
- implement in-place saveState/loadState (values deep copy, save-enabled modifier enumeration, registry-driven rebuild)
- carry registry entries into clone() output
- introduce IHeroModifierOwner so modifier owner typing stays assignable for generic attributes
- add attribute.test.ts same-reference save/load regressions across all compressions
2026-09-16 18:37:54 +08:00
a44c5d8918 test(06-17): stage 3 complete Low/High compression and reach 27 rows
- expand COMPRESSIONS to NoCompression / LowCompression / HighCompression so the matrix is 3 map counts x 3 compressions x 3 timing items = 27 rows
- keep measureCase, fixture build order, side load and 06-16 files untouched; still zero assertions
- one full run: 5 perf files / 45 tests passed, 0 WARNING/ERROR codes, saveablesReal.perf.ts (27 tests) in 379ms -- no case approaches the 30000ms testTimeout
2026-09-16 16:21:26 +08:00
4476e19805 test(06-17): stage 2 add fixed real side load and map scales 1/5/13
- seed 50 flags, 20 item kinds (3 equipment + 17 consumables), 4 equipped instances on slots 0..3, 20 modifiers (4 from equipped items + 16 manual), 1000 mixed replay steps and an unmodified enemy baseline
- keep addTile -> itemStore.addItem -> equipment.add ordering and a single one-shot compareWith after all maps exist
- 9 rows (1/5/13 x NoCompression x save|load|round trip), zero assertions, zero warn/error codes
2026-09-16 16:10:10 +08:00
63485e93ca test(06-17): stage 1 real 13x13 map fixture and map-only save/load perf rows
- move root floors.json into packages-user/data-state/test/fixtures/ (byte-identical) and delete the root copy
- add saveablesReal.perf.ts: toFlat/clearCodes/registerTiles/createRealMapFixture with a one-shot compareWith baseline
- seed the minimum 1 equipment instance so HeroEquipsStore.loadState does not raise error 58
- 3 rows: save / load / round trip for 1 map x NoCompression, zero assertions
2026-09-16 16:02:58 +08:00
374274a4bb test(06-16): add CoreState save/load perf suite across item scales and compressions
- saveables.perf.ts: 9 cases = 10/100/1000 items x No/Low/High compression
- each sample round-trips all 5 registered saveables through saveState/loadState
- synthetic item definitions via addTile -> itemStore.addItem -> equipment.add/addItem
- warmup 3 + 20 samples, median/min/p95 via console.table, no assertions
2026-09-16 15:06:58 +08:00
3c59f31e6f test(06-16): add enemy context buildup and hero attribute perf suites
- context.perf.ts: 3 cases (50/200/1000 enemies), fixed 10 global auras + 5 special codes, cached aura topology, one buildup per sample
- attribute.perf.ts: 3 cases (10/100/1000 modifiers over 10 attributes), 1000 recalc rounds per sample via markModifierDirty + getFinalAttribute
- warmup 3 + 20 samples, median/min/p95 via console.table, no assertions
2026-09-16 15:02:57 +08:00
37bf89bc94 test(06-16): add isolated perf channel and critical calculation perf
- vitest.perf.config.ts: include only *.perf.ts, mirror vite.config.ts aliases, 30s timeouts
- package.json: add test:perf script (test/test:ci untouched)
- damage.perf.ts: 3 cases (1000/10000/50000) warmup 3 + 20 samples, no assertions
2026-09-16 14:56:28 +08:00
0224c2e67e docs(07): align replay param type table with the renumbered codes 2026-09-16 13:27:38 +08:00
2f148c900c test(07-08): #06-07-1 bind the event layer in the teleport playback test
- createSmallMapScene returns map (additive; existing callers ignore it)
- target case binds state.pathfinding.finder.useMapLayer(map.eventLayer) after floor activation
- teleport target changed to (2,0) to avoid self-target empty-path early return; asserts x=2/y=0
- un-skip and rename to reflect test-side event layer binding; neutral leading comment
2026-09-16 13:02:46 +08:00
1ff22dd07d feat: 寻路系统接线 2026-09-15 21:28:52 +08:00
95ea6609c6 fix(07-07): #06-09-5 warn code 178 for unloaded save keys
- core.ts loadState: 差集方向改为 loaded.difference(total),178 = 存档出现但未加载的 key
- saveablesRoundTrip.test.ts:322-334 改写为「缺 key 不触发 178、仍触发 177」负向见证并更名
- saveablesRoundTrip.test.ts:337-349 取消 it.skip,承担「多出 key 触发 178」正向见证
2026-09-15 21:10:33 +08:00
9f058650c1 fix(07-06): #06-08-1 keep backward steps on the same axis
- Special 后退分支基准由 getCurrentDirection() 改为 this.faceDirection,避免被本步写入的反方向改写而在多步之间摆动
- 前进分支保持既有 getCurrentDirection() 语义不变
- 同步 IObjectMover.backward jsdoc 与 getCurrentDirection/prepareStep 注释措辞(D-11)
- 取消 mover.test.ts 多步后退用例的 it.skip,断言一字未改(D-10)
2026-09-15 20:57:13 +08:00
620382cc5f fix(07-05): #06-06-1 warn code 128 for an out-of-map dynamic transfer
- transferToDynamic 越界分支由 131 改为 128,对齐两个 transferToStatic* 兄弟分支
- 取消 mapLayer.test.ts 的码 128 用例 skip
2026-09-15 20:45:01 +08:00
3b1b9f1d5c fix(07-05): #06-09-3 restore the dynamic tile num on load
- loadState 先 this.set(save.num),再恢复存档事件
- 取消 saveLoad.test.ts 的 num 恢复用例 skip
2026-09-15 20:43:20 +08:00
2d2855c394 chore(07-04): #06-05-3 annotate the retained 147 skip and close windows 25/26
- D-06: equipment.test.ts code-147 case stays it.skip with a Chinese note that 147 is a reserved code, currently unreachable by design; no production code touched
- WINDOWS.md ids 25/26 marked fixed (open_count 13 -> 11); no new ledger entries
2026-09-15 20:34:03 +08:00
2452711edb fix(07-04): #06-05-2 prefer the first empty named slot
- getCouldEquipSlot tests empty === -1 so the first empty named slot wins instead of always replacing the first match
- un-skip the named-slot empty-preference case; canEquipTo string branch untouched
2026-09-15 20:30:32 +08:00
04943416a5 fix(07-04): #06-05-1 refresh final attributes without modifiers
- recalculateAttribute writes the base value into finalAttribute when no modifier is attached
- un-skip the base-only-change case; catchCalculateProgress is intentionally left untouched
2026-09-15 20:29:27 +08:00
02786047d2 fix(07-04): #06-09-2 deep copy the equipment save snapshot
- saveState returns new Map(this.equips) and [...this.slots] so the snapshot is decoupled from the live state
- un-skip the independent-snapshot and container round-trip cases
2026-09-15 20:27:57 +08:00
e7f341095d fix(07-04): #06-09-1 restore equipment modifiers from split save tables
- loadNoCompression reads value entries from state.value instead of state.percentage
- loadDiff seeds this.value/this.percentage from the item.equip base definition before applying save diffs
- un-skip the four correct-expectation EquipmentState round-trip cases (Low/High percentage, NoCompression value, compressed unchanged value)
2026-09-15 20:26:45 +08:00
40824cc10b fix(07-03): #06-04-4 shift replay params in the insert direction
- Move paramArray bytes to paramStart + length so later steps keep their data
- Move indexArray entries to index + 1 so get(i) sees the inserted step
- Un-skip both insert order cases
2026-09-15 18:50:30 +08:00
45dde1cb1c fix(07-03): #06-04-3 shift param indexes from the command index on delete
- Add a private getParamRange helper using paramUsed as the last-step sentinel
- Roll back indexArray from the command index instead of the param byte offset
- Un-skip the middle-step delete cases
2026-09-15 18:45:31 +08:00
965e002476 fix(07-03): #06-04-2 round-trip multi-byte and negative bigint parameters
- Encode bigint bytes by bit-shift mask instead of the broken accumulator
- Decode the bigint length prefix and payload bytes unsigned
- Encode negative bigint as dedicated type 8 with magnitude payload
- Un-skip the multi-byte and heterogeneous bigint cases, add focused cases
2026-09-15 18:37:21 +08:00
528b8c91a5 fix(07-03): #06-04-1 round-trip negative int64 and renumber param type codes
- Correct the int64 decode multiplier to 2147483648
- Encode negative int64 as dedicated type 5 with magnitude payload
- Shift float/bigint/long-string/short-string type codes to 6/7/9/length+9
- Un-skip the int64 round-trip case and add negative int64 focused cases
2026-09-15 18:35:18 +08:00
b70ccbd5f6 fix(07-02): #06-03-1 resolve the reuse mapping in enemy creation
- createEnemy/createEnemyById now resolve prefabs through internalGetPrefab,
  matching getPrefab/deletePrefab/modifyPrefabAttribute behaviour
- add a Chinese invariant comment above createEnemyById covering all
  code/id prefab entry points
- un-skip the two correct-expectation reuse mapping cases in manager.test.ts
  (assertions unchanged) and sync their Chinese comments
2026-09-15 17:16:44 +08:00
650b96059d fix(07-01): #06-01-3 abandon the battle only when before returns false
- read the before result into proceed and abandon only on falsy, matching the
  ICombatScript.before contract in types.ts
- un-skip the correct-expectation case and correct the three existing cases that
  encoded the inverted semantics (explicit truthy beforeResult, complementary
  truthy-branch assertion, synced FakeScript comment)
2026-09-15 17:02:57 +08:00
24534fbca6 fix(07-01): #06-01-2 clear enemy-sourced map damage on delete
- register viewStore/damageStore reverse indexes when sourced damage is written
  and re-register them after a refreshIndex recompute (route A)
- deleteEnemy now finds and removes the enemy-sourced damage instead of leaving
  stale entries behind
- un-skip the correct-expectation case in mapDamage.test.ts (#06-01-2)
2026-09-15 17:00:44 +08:00
8225ef129c fix(07-01): #06-01-4 reset enemy views before a full buildup
- reset every EnemyView before a full buildup so repeated builds start from
  the base enemy instead of compounding on the previous result
- un-skip the correct-expectation cases in damage.test.ts (#06-01-4) and
  context.test.ts (#06-15-1)
2026-09-15 16:55:36 +08:00
9e96df4c3b fix(07-01): #06-01-1 align critical info with the yielded next value
- move targetInfo assignment into the damage < referenceDamage branch so the
  reported critical info matches the yielded next value
- un-skip the correct-expectation case in damage.test.ts (#06-01-1)
2026-09-15 16:53:50 +08:00
65251f5f42 test(06-15): cover deleteAura via correct-expectation skip and register #06-15-1
- add pplies a global aura after addAura and stops applying it after deleteAura (it.skip, D-05)
- reuse in-file createContextFixture/createEnemy/FakeAura/FakeConverter, no new helpers
- register finding #06-15-1 in 06-TEST-FINDINGS.md (same root cause as #06-01-4)
- unskip-verified: addAura applies (atk 2 -> 5) but deleteAura + buildup stays 5, expected 2
2026-09-15 13:15:51 +08:00
25e8c0662a test(06): normalize CRLF line endings for enemy comparer/special tests 2026-09-15 13:00:04 +08:00
83dc4fdaf6 test(06-14): register blocked delete/insert heterogeneous stream order (G-06-04-C) and map coverage
- add correct-expectation it.skip for the heterogeneous route after delete(1) (anchor #06-04-3)
- add correct-expectation it.skip for the heterogeneous route after insert(2, 9, [true, 5]) (anchor #06-04-4)
- add file-inline expectRouteStream helper (stream-only typed reads with index 1..N and terminal null)
- append the create-or-append 06-14 section to 06-COVERAGE-MAP.md; existing 5 skips unchanged
2026-09-15 11:50:30 +08:00
2cffe3ef6c test(06-14): strengthen stream assertions with types, index progression and expiry (G-06-04-C/B)
- rewrite expectHeterogeneousRead to assert per-param typeof + value, stream index i+1, terminal null and stream.index === length
- add per-param typeof/value and stream.index progression to the sequence and expand stream cases
- add 'expires a read stream after the heterogeneous route is mutated': add() expires the old stream (warn 155) and a fresh stream reads the new 7-step order
2026-09-15 11:47:25 +08:00
8ae4588ba4 test(06-14): verify a heterogeneous route exclusively through a read stream (G-06-04-C/A)
- add file-inline expectParamTyped/expectStepTyped helpers asserting typeof + toBe per parameter
- add a 7-command complex route (param counts 1/2/0/1/4/2/3, boolean/int8/int32/float/bigint/string)
- read it only through createReadStream: per-step command, per-param type/value, index 1..7, terminal null
- add a middle-start variant (createReadStream(3) -> indexes 4..7, createReadStream(6) -> index 7)
2026-09-15 11:44:38 +08:00
992ca9d585 test(06-13): assert all CoreState key states and varied 10-step replay (G-06-09-A/B)
- seedState/mutateState/assertRestored now cover every key state: hero base attrs + modifier final atk + location, flags score/coins/stage, map two blocks + active status, enemy hp/atk, replay steps
- Replay seeded with 10 @system/replay steps mixing Up/Right/Down/Left/Teleport/UseItem/Equip/Unequip and varied param types, asserted per step
- New container test loops flags and replay through CoreState across the three compression tiers
- Append 06-13 create-or-append section to 06-COVERAGE-MAP.md; existing #06-09-1..5 skips unchanged
2026-09-15 11:27:57 +08:00
8a7cda95ae test(06-13): tier map tile save/load across all compressions (G-06-09-B)
- StaticTile covered-event round trip looped over NoCompression/LowCompression/HighCompression
- DynamicTile covered-event round trip looped over the three tiers, keeping the tile num assertion
- Existing #06-09-3 it.skip unchanged
2026-09-15 11:24:08 +08:00