# DSH 真实红警客户端最终验收报告 日期:2026-08-22 结论:通过,`RA_READY=1`。 ## 1. 验收范围 本报告验证的是 DeepSeek Harness(DSH)外部插件,不是 Codex 插件。验收目标是: - DSH 主页面显示真实红警 2 兼容游戏。 - Chat 控制主页面同一浏览器实例和同一 AI 席位。 - 模型只读取战争迷雾允许的结构化引擎数据。 - 游戏能力按需加载为精确工具。 - 用户自行导入游戏资源,仓库不分发素材。 - DSH 源码 checkout 零写入。 ## 2. 正式运行身份 最终真实 DSH 对局: | 字段 | 值 | | --- | --- | | Profile | `/Users/Four/.dsh/profiles/red-alert-review-20260822` | | session | `session-64166750-0ab0-413d-ae6d-0130f68152ec` | | match | `392aecfa-7a64-47db-b657-b39e71fa2071` | | seat | `Russians` | | map | `mp02t2.map` | | final tick | `5207` | | renderer URL | `http://127.0.0.1:60406/` | | iframe canvas | `2` | session log: ```text /Users/Four/.dsh/sessions/--private-var-folders-j6-3tm8zfn56fn47lfvwstq5y100000gp-T-dsh-readme-media-rjOyf4--/session-64166750-0ab0-413d-ae6d-0130f68152ec/session.jsonl.zstd ``` 页面截图: ```text /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-actions-noop/04-power-placed.png ``` 截图显示 DSH 主页面中的真实地图、战争迷雾、HUD、小地图、苏军建造厂和 NAPOWR。截图只证明视觉结果;精确工具结果以 session log 为准。 ## 3. 用户资源导入 验收使用用户本地选择的最小 7z: | 项目 | 值 | | --- | --- | | 路径 | `/private/tmp/ra2web-d1.aba9YH/minimal-archive.7z` | | 大小 | `138838693` bytes | | SHA-256 | `18b1f878a7efa7cc77c98cd1344e94ec79e8e2b0f1976d45b66b799d1b422b09` | | 内容 | `RA2.MIX`、`LANGUAGE.MIX`、`MULTI.MIX` | 导入日志明确跳过或禁用 theme、Taunts、音乐、电影、`exe` 和 `dll`。归档、解包资源和浏览器缓存都未复制进正式仓库。 ## 4. 主页面和同局控制 ### 4.1 真实画面 浏览器进入真实遭遇战,出现 Three.js 地图、单位、建筑、战争迷雾、HUD、计时器和小地图。最终对局运行到 tick 5207,超过 1500 tick 门槛。 ### 4.2 Chat 控制同一局 最终 session 中完成: 1. Chat 加载 `lobby/setup` 并创建真实 1v1。 2. 加载 `observation`,取得初始 SMCV。 3. SMCV 在同一 match 中部署为 `NACNST`。 4. 加载 `production/economy` 和 `construction`。 5. `red_alert_production` 排队 `NAPOWR`。 6. `red_alert_construction` 在 tick 5093 返回: ```json { "operation": "place", "accepted": true, "placement": { "x": 134, "y": 77 } } ``` 7. tick 5207 的 `red-alert/state` 中,本方对象同时包含: ```json [ { "id": 1045, "unitType": "NACNST", "position": { "x": 134, "y": 79 } }, { "id": 1050, "unitType": "NAPOWR", "position": { "x": 134, "y": 77 } } ] ``` 同一 iframe 在红警和 Chat 标签之间切换后仍保持原对象和原 URL,没有创建第二个游戏实例。 另一次真实 DSH 动作验收中,SMCV 从 `(135,80)` 移动到 `(143,80)`;该次 session 与 match 内部身份同样保持一致。不同验收 session 不混用为一条同局证据。 ## 5. 按需工具 全局策略覆盖 85 个 game-api 公共声明和 19 个 manifest 项。最终 session 的 durable selection 包含: - `lobby/setup` - `observation` - `units/combat` - `production/economy` - `construction` 每条 selection 都是 version 1、`schemaState=loaded`、`outcome=committed`。初始模型 schema 中所有延迟组都不可见,只保留 capability/loader。外交、超武和生命周期组由策略、真实注册集合和专项测试覆盖;本次建造纵切没有为了凑调用数量执行无意义的超武或退出。 旧 `red_alert_act` 不存在。`check:tool-policy` 会在 declaration 漂移、漏工具、重复工具、意外工具或 legacy 工具重新出现时失败。 ## 6. 公平观察 ### 6.1 当前 LOS 兼容客户端 adapter 使用本方和合法盟友的存活视觉来源、sight、transient shroud 和 tile occupation 计算 CurrentLos。renderer 可见性和 bridge 投影共用这项结果。 真实浏览器证据已覆盖: - 首帧隐藏敌人存在于 world,但 renderer visible=false,bridge 不含该对象。 - 敌人进入视野后出现在 `visibleEnemies`。 - 重叠视觉来源减少但仍有一个来源时继续可见。 - 全部视觉来源离开后转为 `lastSeenEnemies`。 - 隐藏期间坐标、生命值和 `observedAtTick` 冻结。 - 断连重连后冻结值保持。 ### 6.2 删除和伪装边界 - 敌人在迷雾外销毁后,last-seen 不因全图存在性扫描被删除或更新。 - 当前可见敌人销毁后,从 `visibleEnemies` 移除并保留最后合法观察。 - 未识破 disguise 在复制字段前完全 omit,不发送真实 id、owner、type、name、tile 或 health。 - 锁定场景没有自然发生 cloak/disguise/detector 转场,因此没有把静态代码检查写成自然玩法通过;对应边界由 fail-closed 实现和专项测试保护。 ### 6.3 离线公平回归 `pnpm run check` 内的 10 局真实 Chrono offline audit: ```text gameCount=10 leakCount=0 ``` 并通过隐藏敌情注入反例阻断、visible enemy 子集、last-seen 冻结和可见性失败关闭。 ## 7. 错误恢复 真实 DSH 中连续 6 次非法建筑放置都返回稳定拒绝,没有超时或卸载 renderer。修复后的合同为: - rejected command 可以不带 `toolResult`,bridge 拒绝当前命令但保持 ready。 - 可恢复 error 且 active match 存在时,Host phase 仍允许 running 精确工具。 - client root 继续接受当前 match identity。 - React view 不因 error 分支换位而 detach iframe。 - 下一条合法建造命令在同一 match 成功。 ## 8. 一键客户端准备 正式补丁: | 项目 | 值 | | --- | --- | | 上游 | `https://github.com/huangkaoya/redalert2.git` | | commit | `8c07f1092b2a9e8d8605ed49ef46d77b6c3ea367` | | 补丁路径数 | `11` | | 解码补丁大小 | `88568` bytes | | 专项测试 | `8/8` | | 构建模块 | `1224` | 从不存在的目录执行: ```sh pnpm prepare:renderer -- /private/tmp/dsh-red-alert-prepared-terminal-final-20260822 ``` clone、SHA 锁定、补丁检查、Bun frozen install、8 个 companion 测试和 Vite build 全部退出 0。新产出的 `dist/` 可直接用于 `RA_RENDERER_DIST_DIR`;正式仓库没有保存该构建或用户资源。 ## 9. 最终自动检查 执行: ```sh pnpm run check ``` 结果: - repository rules:通过,37 个 plugin files、22 个 product files。 - tool policy:通过,game-api 0.75.0、85 declarations、19 manifest entries。 - chrono online contract:通过,且明确记录官方在线能力不支持 two programmatic bots。 - renderer adapter gate:通过。 - lint:通过。 - Host/client 和测试 TypeScript:通过。 - game-host 类型检查:通过。 - build:通过。 - 插件测试:15 files、115 tests 全通过。 - game-host:10 tests 全通过。 - 10 局 fog audit:`leakCount=0`。 - publint strict:通过。 构建只有 `tsdown external deprecated` 警告,退出码为 0。 ## 10. 完成指标 | 指标 | 结果 | 判定 | | --- | --- | --- | | `PROFILE` | 1 | 真实 DSH Profile 外部挂载,未修改 DSH checkout | | `FOG` | 1 | current LOS、冻结、销毁、伪装边界和 10 局审计通过 | | `VISUAL` | 1 | DSH 主页面真实游戏画面,tick 5207 | | `TOOL_COVERAGE` | 1 | 85 declarations、19 manifest、精确 wrapper、危险方法不可见 | | `LAZY_LOAD` | 1 | bootstrap-only 初始面和 durable group loader 通过 | | `SAME_MATCH` | 1 | Chat、transport、bridge、engine、iframe 身份一致 | | `DSH_CONTRACT` | 1 | 官方 SDK、Profile、client handoff、projection、transport 通过 | | `REGRESSION` | 1 | 完整 check 和全新 renderer prep 通过 | ```text RA_READY = min(1, 1, 1, 1, 1, 1, 1, 1) = 1 ``` ## 11. 发布边界 - 没有提交、推送或发布 npm 包。 - 没有修改 DSH 源码、vendor、内置 Profile 或启动器。 - 没有把用户归档、EA 素材或临时第三方 checkout 复制进正式仓库。 - 正式包当前仍为 `private: true` 和 `license: UNLICENSED`;公开发布前需由项目所有者决定顶层许可。 - renderer 补丁按上游 `GPL-3.0-only` 保存。 ## 12. Battlefield-first 页面与真实模型普通 AI 对战 主页面删除了插件自己的“红色警戒”标题、状态、match meta、renderer 标题和协议说明。完整 DSH 截图中,红警标签下方直接进入实际游戏画面;session、match 和 renderer 身份保留在不可见数据属性和协议状态中,不占用战场顶部空间。 真实模型终局验收使用 DSH 页面显示的 `DeepSeek-V4-Flash`、`High`,session log 的模型来源为 `deepseek-official/deepseek-v4-flash`。对手为兼容客户端内置普通 AI,不是 noop 或固定脚本。 | 字段 | 值 | | --- | --- | | session | `session-06449a85-f85a-4c70-99fb-ae76b144a2cd` | | match | `366d50ec-0151-47bd-aafe-5ffcde83f96f` | | seat | `Russians` | | map | `mp02t2.map` | | terminal tick | `5099` | | terminal status | `finished` | | self defeated | `true` | 模型在同一局中部署 SMCV、排队并放置 `NAPOWR`,随后普通 AI 的 E2 步兵群进入合法视野并摧毁基地。tick 4284 的最后活动观察包含本方 `NACNST#1052` 和 9 个当前可见 E2;tick 5099 的终局回执为 `status=finished`、`self.defeated=true`、`ownUnits=[]`。结果是模型失败,不把完成一局误写成获胜。 终局前的正式截图保存在: ```text /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-real-model-full-match-final/01-opening-game.png /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-real-model-full-match-final/02-phase-1-12s-game.png /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-real-model-full-match-final/04-phase-1-42s-dsh.png /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-real-model-full-match-final/05-phase-1-57s-dsh.png /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-real-model-full-match-final/06-phase-1-72s-dsh.png ``` 前一场同模型、同普通 AI 配置的真实对局结算页保存在: ```text /private/tmp/ra2web-d1.aba9YH/playwright-evidence-dsh-real-model-full-match-retry2/02-phase-1-game.png ``` 该结算页显示模型方失败、地图“岛屿之战 (2)”、用时 `0:01:19`。它只用于补充真实结算页视觉证据;终局状态回传以本节列出的最终 session log 为准。 兼容客户端在 GameScreen 进入自然结算时冻结最后一份公平观察和 finished 快照。引擎解绑后,observe 仍可读取冻结终局,其他命令全部拒绝。DSH client 对 finished 对局保留既有 iframe,因此后续自然结算会继续显示真实计分页,不再立即替换为占位提示。