diff --git a/audit/contracts/movement.keyboard-motion.md b/audit/contracts/movement.keyboard-motion.md index dd5fac71..0f950460 100644 --- a/audit/contracts/movement.keyboard-motion.md +++ b/audit/contracts/movement.keyboard-motion.md @@ -86,7 +86,7 @@ | 项目 | 状态 | 备注 | |---|---|---| | Preconditions | PARTIAL | active/失焦/按键残留、锁门、私店、情绪和锁门 held WASD 已覆盖;同步、受击、死亡和传送门未全覆盖 | -| Branch structure | PARTIAL | W/S、A/D、八方向、释放顺序和 `m_isCmrRot` 相机跟随已覆盖;Paralysis/Faint/Sleep 未接入移动门 | +| Branch structure | PARTIAL | W/S、A/D、八方向、释放顺序和 `m_isCmrRot` 相机跟随已覆盖;Paralysis/Faint/Sleep 已调查——Paralysis 死代码、Sleep 已被 `stunned` 门覆盖、Faint 证据不足,均非差异 | | Algorithms/formulas | PARTIAL | 方向优先级、归一化和相机跟随的 fold-to-±90/rate 公式一致(`movement.keyboard.motion/camera-auto-follow-rotation`);固定 300 像素 Dst 与根运动仍被连续速度替代 | | State transition order | PARTIAL | 输入状态、锁门/移动技能恢复、PlayerController、NetPlay 入口已定位;资源事件与网络事件的完整顺序未证实 | | Constants/units | PARTIAL | 角度/旋转阈值和 0/300/100ms 节流已记录;米/厘米、移动速度和目标距离不同 | @@ -101,15 +101,11 @@ - 补充死亡/传送/受击以及私店、情绪、移动技能和普通锁定的多门叠加顺序;各单门 held WASD 恢复已覆盖基础路径。 - 继续对照 `.msa` 的 motion event、`AccumulationMovement` 根运动和当前 `get_move_motion_speeds` fallback,决定是否需要根运动适配层。 - 真实角色模型在 W/S 快切时根节点/骨骼姿态不翻转的模型级测试仍缺。 -- **新增(2026-09-22 发现,未修复)**:`CPythonPlayer::__CanMove()` 还委托 - `CActorInstance::CanAct()`,后者在 `IsParalysis()/IsFaint()/IsSleep()` 时也拒绝移动 - (`ActorInstanceBattle.cpp` `CanAct`/`CanMove`)。当前端 `net_play.gd::_can_process_network_state()` - 只挡 `dead`/`stunned`/`knock_down`,没有 Paralysis/Faint/Sleep 三个状态的移动门。 - 三者的触发源分别是萨满技能 `__Shaman_SetParalysis`(`InstanceBaseEffect.cpp:821`)、 - Python 侧 `SetFaint`(`PythonCharacterModule.cpp:1094/1101`)和效果可见性绑定的 - `SetSleep`(`InstanceBaseEffect.cpp:933`),当前端尚未定位这些触发源对应的服务端 - affect/状态位,需要先把三者映射到现有 affect 管线再决定移动门怎么接,属于比本轮 - camera 分支更大的独立子项,留给后续轮次。 +- ~~`CanAct()` 的 Paralysis/Faint/Sleep 移动门~~ **已调查关闭(2026-09-22, + `movement.keyboard.motion/canact-paralysis-faint-sleep-gate`,见下方调查轮次)**: + Paralysis 是可达代码中的死代码(唯一 setter 零调用点);Sleep 在实际运行中是 + AFFECT_STUN 的别名,已被当前端 `stunned` 移动门覆盖;Faint 的可达性在现有 40250 + 检出材料下无法证明或证伪,evidence-blocked。三者均非需要修复的移动等价差异。 ### Audit round 2026-09-21 @@ -222,3 +218,59 @@ 改为已闭合(见上表),`Remaining` 移除相机副作用项、新增 Paralysis/Faint/Sleep 移动门 子项(见上)。合同整体仍为 `PARTIAL`——根运动/资源事件/同步受击门/Paralysis-Faint-Sleep 仍未闭合。 + +### 调查轮次 2026-09-22T — `movement.keyboard.motion/canact-paralysis-faint-sleep-gate` + +本轮对上条 Remaining 中「`CanAct()` 的 Paralysis/Faint/Sleep 三个移动门未接入」逐一做 +可达性追踪(`grep -arn`,因大量 `UserInterface/*.cpp` 注释含 CP949 字节,需要 `-a` 才能 +正确匹配),结论:三者均不构成需要修复的移动等价差异,逐项证据如下。 + +- **`IsParalysis()`/`m_isParalysis`**:全部可达源码中唯一的写入点是 + `CInstanceBase::__Shaman_SetParalysis`(`InstanceBaseEffect.cpp:821-823`,直接调用 + `m_GraphicThingInstance.SetParalysis(...)`,`m_GraphicThingInstance` 声明为 + `CActorInstance`,`InstanceBase.h:999`,确认改的是 `CanAct()` 读的同一个标志位)。 + 对 `__Shaman_SetParalysis`/`SetParalysis`/`Paralysis` 在整个 `40250/ClientVS22/source` + 树(`UserInterface`+`GameLib`+其余全部模块)做穷举 grep,**零调用点**——没有任何脚本、 + 网络包处理器或技能逻辑调用它。结论:Paralysis 分支在可达代码中是死代码,40250 + Windows 客户端实际运行中 `IsParalysis()` 恒为 false。当前端不接入此门是正确等价 + (无对应行为可对照),不是差异。 +- **`IsSleep()`/`m_isSleep`**:`InstanceBaseEffect.cpp` 的 `SetAffect()` 分支表中 + `AFFECT_SLEEP` 分支已被注释掉(死代码);唯一存活的写入路径是 + `AFFECT_STUN: m_GraphicThingInstance.SetSleep(isVisible);`(约行 932-933)。即 + `IsSleep()` 在实际运行中就是 AFFECT_STUN 的别名,不是独立信号。当前端 + `entity_store.h:119` 的 `stunned` 字段本就注释为对应 `AFFECT_STUN` + (`InstanceBaseEffect.cpp:932`),`net_play.gd::_can_process_network_state()` 已经在 + `dead`/`stunned`/`knock_down` 上阻止移动——即 Sleep 对应的移动门已经被现有 `stunned` + 门覆盖,不需要新增单独的 Sleep 门。 +- **`IsFaint()`/`m_isFaint`**:唯一写入点是 `chrFaintTest()` + (`PythonCharacterModule.cpp:1087-1105`),Python 绑定名 `"FaintTest"` + (同文件 1305 行),与另一个调试方法 `chrtestRestoreRenderMode`/`"RestoreRenderMode"` + (1072/1319 行)并列在同一张绑定表里,且操作对象是 `GetSelectedInstancePtr()` + (更像选人/预览界面而非在线主控角色)。当前可用的 40250 检出只有 8 个 `.py` + 文件、没有 root/ 下的任何 UI/任务脚本,因此无法从现有材料证明或证伪是否有在线 + 脚本会调用 `char.FaintTest()`。结论:证据不足,按 SKILL.md 的「不要在没有可达性证据 + 时把未验证代码当作产品行为来追」原则,本项目前不作为移动门差异处理,标记为 + evidence-blocked。 + +**过程中新发现(已移交,非本合同范围)**:追踪 `IsStun()` 时发现 +`CActorInstance::Stun()` 唯一调用者 `CInstanceBase::Stun()` +(`InstanceBaseBattle.cpp:683-688`)本身只被 `RecvStunPacket()` +(`PythonNetworkStreamPhaseGame.cpp:1556-1578`)调用,且该函数显式区分: +`if (GetMainInstancePtr()==pkInstSel) pkInstSel->Die(); else pkInstSel->Stun();`—— +主角收到 `GC_STUN` 走的是 `Die()`(`InstanceBaseBattle.cpp:691` → `ActorInstance.cpp:365` +`m_isRealDead=TRUE`+播放 NAME_DEAD 动作),只有非主角远端 actor 才真正调用 `Stun()`/ +置位 `IsStun()`。当前端 `entity_store.cpp` 的 `GC_STUN` 处理器对任意 vid(含主角)统一 +置 `stunned=true`,没有这个主角分流。**但这不是 movement.keyboard.motion 的差异**: +`CanAct()` 对 `IsDead()`/`IsStun()` 的移动阻断效果相同,而 `net_play.gd` +`_can_process_network_state()` 已经对 `dead`/`stunned` 同等阻止移动——即无论主角 +`GC_STUN` 走死亡路径还是眩晕路径,当前端的**移动阻断结果**已经正确等价。 +`Die()`/`Stun()` 分流只影响死亡系统本身(`m_isRealDead`、EXP 掉落、尸体/复活流程等), +这是 `combat.death.exp_drop`(或 `combat.affect_status`,见其合同 Remaining #2、 +分支矩阵第 63/67 行已经记录 `native GC_STUN` 目前只置 `stunned=true` 缺解除路径)的 +范围,不在此重复登记。 + +**结论**:本轮不改动实现代码——三个候选门中两个(Paralysis/Sleep)是死代码/已被现有 +`stunned` 门覆盖,第三个(Faint)证据不足;衍生发现的 GC_STUN 主角分流差异经核实对 +移动阻断结果无影响,已移交 `combat.affect_status` 既有条目,不重复登记。`Remaining` +中对应条目标记为已调查关闭。合同状态维持 `PARTIAL`(根运动/资源事件/同步受击门等 +仍未闭合),Branch structure 行的 Paralysis/Faint/Sleep 备注移除。 diff --git a/audit/history.jsonl b/audit/history.jsonl index 4c66ae83..378610e1 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -481,3 +481,4 @@ {"time":"2026-09-21T17:01:24Z","event":"implementation_fix_round","result":"PARTIAL","ids":["network.login.phase_flow/auth-game-phase-matrix/phase-dead-noop-time-sync"],"files":["extension/src/net/classic/classic_session.cpp","extension/tests/net_classic_session_test.cpp","audit/contracts/network.login.phase-flow.md","audit/remediation-roadmap.md","audit/manifest.json","audit/history.jsonl","audit/reports/coverage.md"],"tests":["40250 reference source inspection (PASS: PythonNetworkStream.cpp RecvPhasePacket(PHASE_DEAD) has an explicit empty branch and returns true without a phase setter)","pre-fix build-debug/extension/net_classic_session_test (FAIL: PHASE_DEAD enabled time-sync and changed the next handshake response; 1 check)","post-fix build-debug/extension/net_classic_session_test (PASS)","cmake --build build-debug -j4 (PASS)","ctest --test-dir build-debug --output-on-failure -j2 (PASS; 23/23)","ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 build-asan/extension/net_classic_session_test (PASS)","MT_PROTOCOL=classic godot --headless --path project --script app_flow_lifecycle_test.gd (PASS)","MT_PROTOCOL=classic godot --headless --path project --script p10_test.gd (PASS)","MT_PROTOCOL=classic godot --headless --path project --script netplay_test.gd (PASS)","MT_PROTOCOL=classic godot --headless --path project --script disconnect_world_reset_test.gd (PASS)","audit_phase_dispatch.py (PASS; no payload differences)","audit_packet_registry.py (PARTIAL; only approved HDR_GC_SYMBOL_DATA adaptation)","audit_sequence_table.py (PASS; 32768 entries identical)","audit_source_coverage.py (PASS; 0 unowned behavior candidates)","audit_ledger.py refresh --write/report --write/validate (PASS; 45 contracts)","manifest/history JSON validation (PASS)","git diff --check (PASS)"],"reason":"按 40250 RecvPhasePacket(PHASE_DEAD) 的空操作语义,移除当前端错误打开 time-sync mode 的副作用,保持重复握手使用普通 HANDSHAKE 回包。未修改飞行物、技能、战斗、角色名编码或 UI;真实 Windows/服务器主动 PHASE_CLOSE、空角色 live、完整跨阶段 retry、GC_WARP 失败回退和可选安全 runtime仍未闭合,合同保持 PARTIAL。"} {"time":"2026-09-21T17:08:09Z","event":"implementation_fix_round","result":"PARTIAL","ids":["network.login.phase_flow/auth-game-phase-matrix/phase-dead-noop-time-sync"],"files":["extension/src/net/classic/classic_session.cpp","extension/tests/net_classic_session_test.cpp","audit/contracts/network.login.phase-flow.md","audit/remediation-roadmap.md","audit/manifest.json","audit/history.jsonl","audit/reports/coverage.md"],"tests":["40250 reference source inspection (PASS: PythonNetworkStream.cpp RecvPhasePacket(PHASE_DEAD) is an explicit empty branch; only real phase setters clear the close owner)","pre-fix build-debug/extension/net_classic_session_test (FAIL: PHASE_DEAD cleared the explicit PHASE_CLOSE owner marker; 1 check)","post-fix build-debug/extension/net_classic_session_test (PASS: plain HANDSHAKE response and PHASE_CLOSE marker are both preserved)","cmake --build build-debug -j4 (PASS)","ctest --test-dir build-debug --output-on-failure -j2 (PASS; 23/23)","ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 build-asan/extension/net_classic_session_test (PASS)","MT_PROTOCOL=classic godot --headless --path project --script app_flow_lifecycle_test.gd (PASS)","MT_PROTOCOL=classic godot --headless --path project --script p10_test.gd (PASS)","MT_PROTOCOL=classic godot --headless --path project --script netplay_test.gd (PASS)","MT_PROTOCOL=classic godot --headless --path project --script disconnect_world_reset_test.gd (PASS)","audit_phase_dispatch.py (PASS; no payload differences)","audit_packet_registry.py (PARTIAL; only approved HDR_GC_SYMBOL_DATA adaptation)","audit_sequence_table.py (PASS; 32768 entries identical)","audit_source_coverage.py (PASS; 0 unowned behavior candidates)","audit_ledger.py refresh --write/report --write/validate (PASS; 45 contracts)","manifest/history JSON validation (PASS)","git diff --check (PASS)"],"reason":"在同一分支的进一步等价审计中补齐 PHASE_DEAD 的第二个无副作用约束:通用 phase != PHASE_CLOSE 条件会清除显式关闭 owner,修复为仅真实 phase setter 清除 m_phase_closed。此为同一稳定分支的实质性实现补充,不是重复修复。未修改飞行物、技能、战斗、角色名编码或 UI;真实 Windows/服务器主动 PHASE_CLOSE、空角色 live、完整跨阶段 retry、GC_WARP 失败回退和可选安全 runtime仍未闭合,合同保持 PARTIAL。"} {"time": "2026-09-22T00:00:00Z", "event": "implementation_fix_round", "result": "PARTIAL", "ids": ["movement.keyboard.motion/camera-auto-follow-rotation"], "files": ["project/player_controller.gd", "project/keyboard_motion_timeline_test.gd", "audit/contracts/movement.keyboard-motion.md", "audit/remediation-roadmap.md", "audit/manifest.json", "audit/history.jsonl"], "tests": ["40250 reference source inspection (PASS: PythonPlayerInput.cpp:445-491 CPythonPlayer::NEW_MoveToDirection m_isCmrRot branch folds fDirRot to fSigDirRot/fRotRat and applies CCamera::Roll(-m_fCmrRotSpd*fElapsedTime*fRotRat/90) every frame a direction key is held and the movement gates pass)", "pre-fix keyboard_motion_timeline_test.gd (FAIL by construction: camera.yaw never written by _keyboard_wish/_process, new directional assertions would fail)", "post-fix godot --headless --path project --script keyboard_motion_timeline_test.gd (PASS)", "godot --headless --path project --script test_wasd_steering_parity.gd (PASS)", "godot --headless --path project --script test_no_auto_move_regression.gd (PASS)", "godot --headless --path project --script game_camera_test.gd (PASS)", "godot --headless --path project --script movement_parity_test.gd (PASS)", "godot --headless --path project --script player_move_test.gd (PASS)", "godot --headless --path project --script mouse_controller_test.gd (PASS)", "godot --headless --path project --script test_alignment_parity.gd (PASS)", "git diff --check (PASS)", "audit_ledger.py refresh --write/report --write/validate (PASS)", "cmake --build build-debug -j4 / ctest (BLOCKED: pre-existing stale CMakeCache.txt from a different checkout path, unrelated to this GDScript-only change; not run)", "godot --headless --path project --script player_motion_test.gd (BLOCKED: pre-existing parse error, GDScriptNativeClass.clear_texture_cache() not found in this Godot 4.7.1 build; file untouched this round, last changed in a prior commit)"], "reason": "按 40250 CPythonPlayer::NEW_MoveToDirection 的 m_isCmrRot 分支,在 player_controller.gd 新增 _camera_auto_rotate():按住方向键且通过 frozen/locked/private_shop_open/processing_emotion 门后,每帧按方向相对相机的方位角折算 fRotRat(正前/正后 0,正左右 ±90 最大速率,对角线减半),以 m_fCmrRotSpd=20.0 的速率持续把 camera.yaw 转向新朝向。D3D CCamera::Roll 与 Godot yaw 的转向手性相反,增量对 fRotRat 取正号(参考实现取负号),作为显式记录的平台适配,用『按住方向时相机朝该方向收敛、正前后不转、从不越界』的不变式核验,而非逐位对照 D3D 数值。未修改飞行物、技能、战斗、UI 或根运动/资源事件路径;Paralysis/Faint/Sleep 未接入移动门(新发现,记录于 Remaining,未修复)、根运动/AccumulationMovement、同步/受击门恢复顺序、真实模型姿态测试仍未闭合,合同保持 PARTIAL。"} +{"time": "2026-09-22T01:30:00Z", "event": "audit_round", "result": "PARTIAL", "ids": ["movement.keyboard.motion/canact-paralysis-faint-sleep-gate"], "files": ["audit/contracts/movement.keyboard-motion.md", "audit/manifest.json", "audit/history.jsonl"], "tests": ["40250 reference source reachability audit (exhaustive grep -arn across UserInterface/ + GameLib/ for SetParalysis/Paralysis, AFFECT_SLEEP/SetSleep, SetFaint/FaintTest, Stun/RecvStunPacket)"], "reason": "Investigated the movement.keyboard-motion.md Remaining item \"CActorInstance::CanAct() Paralysis/Faint/Sleep movement gates not wired into net_play.gd\" (flagged unfixed by the prior round). Findings: (1) IsParalysis()/m_isParalysis has exactly one setter in the whole reachable 40250 source, CInstanceBase::__Shaman_SetParalysis (InstanceBaseEffect.cpp:821-823), which itself has zero callers anywhere in the tree -- Paralysis is dead code, never true in live gameplay, so not wiring it is correct parity, not a gap. (2) IsSleep()/m_isSleep: the AFFECT_SLEEP case in SetAffect()s switch is commented out (dead); the only live setter is the AFFECT_STUN case (m_GraphicThingInstance.SetSleep(isVisible), ~InstanceBaseEffect.cpp:932-933) -- IsSleep() is functionally just an alias for AFFECT_STUN in practice, which the current clients Entity.stunned field already represents (entity_store.h:119) and net_play.gd::_can_process_network_state() already gates movement on (dead/stunned/knock_down) -- already covered, not a gap. (3) IsFaint()/m_isFaint: only setter is chrFaintTest() (PythonCharacterModule.cpp:1087-1105), a Python-bound debug helper (\"FaintTest\", registered alongside chrtestRestoreRenderMode) operating on GetSelectedInstancePtr(); the available 40250 checkout has no root/ Python UI/quest scripts to prove or disprove live-gameplay reachability -- evidence-blocked, left unresolved per SKILL.md do-not-audit-unreachable-code-as-product-behavior rule, no fix attempted. Byproduct finding while tracing IsStun(): CActorInstance::Stun() is only reachable via RecvStunPacket() (PythonNetworkStreamPhaseGame.cpp:1556-1578), which explicitly routes GC_STUN to Die() for the main character and to Stun() only for remote actors; verified this does NOT create a movement.keyboard.motion discrepancy because CanAct() blocks movement identically on IsDead() and IsStun(), and net_play.gd::_can_process_network_state() already blocks movement identically on dead and stunned -- the movement-blocking outcome is already correct parity regardless of which reference path fires. The Die()-vs-Stun() distinction only affects death-system semantics (m_isRealDead, EXP drop, corpse/respawn flow), which is combat.death.exp_drop/combat.affect_status territory and is already tracked there (combat.affect-status.md Remaining #2, equivalence rows 63/67: native GC_STUN only sets stunned=true with no dedicated clear path) -- not re-logged as a new finding to avoid duplicate tracking. No code changed this round; removed the resolved Remaining bullet from manifest.json and movement.keyboard-motion.md, replaced with investigation evidence and citations. Contract stays PARTIAL (root-motion/resource-event-source/sync-hit-death-gate-stacking/real-model-bone-flip items remain open)."} diff --git a/audit/manifest.json b/audit/manifest.json index ee45b897..bffd0b07 100644 --- a/audit/manifest.json +++ b/audit/manifest.json @@ -279,8 +279,7 @@ "OnMove/OnMoving/OnWaiting/OnStop 与当前每帧 signal、NetPlay 节流的事件源逐项证明", "同步、私店、受击、死亡、传送、情绪以及多种锁门叠加顺序;移动技能/普通锁定/私店/情绪的 held WASD 恢复已覆盖基础路径", "真实角色模型/骨骼在快速反向输入时不翻转的模型级测试", - "输入事件到移动请求、停止请求和网络包的完整时间线", - "CActorInstance::CanAct() 的 Paralysis/Faint/Sleep 三个移动门未接入当前端 net_play.gd 的移动状态判定(新发现,2026-09-22,未修复,见合同 Remaining)" + "输入事件到移动请求、停止请求和网络包的完整时间线" ], "fingerprints": { "reference": "20c74407914aba18dde8f76f7b86917372a56cc7333b2ca8bfeee76c39e357e4", diff --git a/audit/remediation-roadmap.md b/audit/remediation-roadmap.md index e2a79492..6d378d0f 100644 --- a/audit/remediation-roadmap.md +++ b/audit/remediation-roadmap.md @@ -273,6 +273,35 @@ Paralysis/Faint/Sleep 移动门和真实模型姿态测试仍未闭合,下一 继续(`AccumulationMovement` 根运动差异或 Paralysis/Faint/Sleep 移动门是其中两个具体、 无需真实服务端/客户端证据即可推进的候选)。 +### 2026-09-22T01:30Z:`movement.keyboard.motion/canact-paralysis-faint-sleep-gate` 调查关闭(无需修复) + +对上一轮标记的两个候选之一(`Paralysis/Faint/Sleep` 移动门)做完整可达性追踪后确认它是 +**假阳性**,不是代码可执行的差异,本轮未改动 GDScript/C++ 实现: + +- Paralysis:唯一 setter `__Shaman_SetParalysis`(`InstanceBaseEffect.cpp:821`)在整个可达 + 40250 源码树中零调用点,是死代码,40250 客户端实际运行时 `IsParalysis()` 恒为 false。 +- Sleep:`SetAffect()` 的 `AFFECT_SLEEP` 分支已被注释掉,唯一存活路径是 + `AFFECT_STUN → SetSleep()`(`InstanceBaseEffect.cpp:932`),即 `IsSleep()` 实际上是 + AFFECT_STUN 的别名,已被当前端 `entity_store.h:119` 的 `stunned` 字段和 + `net_play.gd::_can_process_network_state()` 的 `dead/stunned/knock_down` 门覆盖。 +- Faint:唯一 setter `chrFaintTest()`(`PythonCharacterModule.cpp:1087`)是与 + `chrtestRestoreRenderMode` 并列的调试用 Python 绑定,作用于 `GetSelectedInstancePtr()`; + 现有 40250 检出没有 root/ Python 脚本可证明/证伪在线可达性,evidence-blocked,未修复。 + +调查过程中发现的衍生项(`IsStun()` 的 `RecvStunPacket()` 对主角 `GC_STUN` 走 `Die()` +而非 `Stun()`)核实后确认**不是** `movement.keyboard.motion` 差异——`CanAct()` 对 +`IsDead()`/`IsStun()` 的移动阻断效果相同,当前端 `_can_process_network_state()` 也已对 +`dead`/`stunned` 同等阻断,移动结果已正确等价;`Die()`/`Stun()` 分流只影响死亡系统本身 +(EXP 掉落/尸体/复活),已在 `combat.affect-status.md` Remaining #2、分支矩阵第 +63/67 行登记,不在本合同重复记录。详见 +`audit/contracts/movement.keyboard-motion.md` 的「调查轮次 2026-09-22T」小节。 +**该分支已关闭,不要在没有新 live 证据的情况下重新调查 Paralysis/Faint/Sleep 或 +GC_STUN 主角分流。** + +`movement.keyboard.motion` 下一轮候选收窄为:`AccumulationMovement` 固定 300cm +根运动/连续速度替代差异、`OnMove/OnMoving/OnWaiting/OnStop` 资源事件源、同步/受击/ +死亡/传送门叠加顺序、真实模型骨骼快切不翻转的模型级测试——四者均仍未闭合。 + `network.login.phase_flow` 的下一主候选仍保持文件前面记录的 `network.login.phase_flow/auth-game-phase-matrix/live-package-order/server-initiated-phase-close`: 本地结构和 owner 分支均已覆盖,只等新的真实服务端/Windows fixture;在没有新 fixture 前不要 diff --git a/audit/reports/coverage.md b/audit/reports/coverage.md index 2b7d1ef6..077fa321 100644 --- a/audit/reports/coverage.md +++ b/audit/reports/coverage.md @@ -24,8 +24,8 @@ Total contracts: 45 ## Pending branch items -- Total: 225 -- P0: 94 +- Total: 224 +- P0: 93 - P1: 118 - P2: 13 - P3: 0