tests/test_pose_server.gd 用的是**同引擎内的客户端**(Godot WebSocketPeer),而真实
对端是 Android(Kotlin/OkHttp)——同引擎自测会共享同样的假设(超时判定、分包、
文本/二进制边界、关闭语义、子协议协商),于是「测试全绿」不等于「Android 连得上」。
契约 §7 也写明:静默超时要用保活避免,而不是靠重连掩盖;这句话只有用独立实现的
客户端实测才算验过。
新增三个文件:
* build/integration/probe-ws.gd —— 把**包内** PoseServer 跑起来(--main-pack +
只加载包内代码),把连接/控制帧/帧/断开事件汇总成 JSON 报告;自身不做判定
(避免「用被测实现判定被测实现」)。支持 --stop-file 提前收尾。
* build/integration/ws-client.mjs —— Node 实现的契约一致性客户端(用内置
WebSocket,零依赖),逐条跑 §1 §1.1 §2 §3.1-§3.6 §5 §6 §7 的场景。
* build/accept-ws.sh —— 编排:解包 → 起探针 → 等监听 → 跑客户端 → 收报告 →
核对客户端看不到的那一半(frames_dropped / malformed_frames / 控制帧计数 /
device_replaced / 关闭原因 / 静默超时消息带毫秒数与阈值)。
实测(**已发布**的 v0.2.3 资产重新下载后跑):客户端 30 通过 / 0 失败 + 服务端侧
16 项事实全过。关键两条:
* 保活对照:只发应用层 ping 持续 19 秒(> 静默超时 15 秒)连接**仍保持打开**;
* 静默超时:完全不发数据 → close(1001,"timeout"),实测 15011 ms(阈值 15000 ms);
另有:子协议协商、welcome 声明保活参数且 heartbeat(5000) < silentTimeout(15000)/2、
pong 原样回传 sentAtMs、同 deviceId 替换旧连接(1000 "replaced by new connection")、
bye → 1000、协议不匹配 → bye + 1002、72 帧含故意跳号(服务端 frames_dropped=3)
与故意 100 字节非法帧(malformed_frames=1)。
反向验证:新增**故意不合规的服务端** build/integration/probe-ws-bad.gd
(welcome 不声明保活字段、不带 sessionId、收到 ping 不回 pong、不做 deviceId 去重),
对同一客户端 → 14 项 ✗、退出码 1,证明断言不是空转。
踩坑记录(已写入任务文档):
1. --script 模式下从无类型数组取 peer,peer.get_packet() 返回类型推不出来,
var x := … 直接 Parse Error;
2. 复核静默超时消息时写了否定式断言 !includes("静默超时 1"),把正确行为判成失败 ——
断言应写成正向模式匹配;
3. 探针原本只能按固定时长跑,编排脚本得猜时间;改成客户端跑完 touch stop 文件。
顺带:package-release.sh 结尾把三条发布前验收(产物自证 / WS 契约一致性 / 跨端集成)
一次列全。不影响已发布的 v0.2.3 产物,故不新发版本。
123 lines
4.0 KiB
YAML
123 lines
4.0 KiB
YAML
project: opendance-windows-client
|
||
version: 0.2.3
|
||
repository: opendance-windows
|
||
default_branch: main
|
||
engine: Godot 4.7.2
|
||
contracts_version:
|
||
rest-api: 0.5.0
|
||
websocket-keypoints: 0.2.0
|
||
data-models: 0.7.0
|
||
skeleton-topology: 0.2.0
|
||
model-formats: 0.5.0
|
||
database: 0.4.0
|
||
|
||
# 契约变更流程(文档 7.2):
|
||
# 任何跨端契约变更必须先在 opendance-web 修改 contracts/ 并提升版本,
|
||
# 再在本项目创建适配任务。本项目内的 contracts/ 只是只读快照。
|
||
|
||
dependencies:
|
||
- name: opendance-web
|
||
kind: rest-api
|
||
contract: contracts/rest-api.yaml
|
||
usage: 曲目/动作/模型目录与关键点序列
|
||
- name: opendance-android
|
||
kind: websocket-consumer
|
||
contract: contracts/websocket-keypoints.md
|
||
usage: 本端为服务端,Android 主动连入推流
|
||
|
||
tasks:
|
||
- id: T-WIN-001
|
||
file: tasks/001-scaffold.md
|
||
scope: Godot 项目骨架
|
||
status: done
|
||
- id: T-WIN-002
|
||
file: tasks/002-rest-client.md
|
||
scope: 调用 Web 服务端 API
|
||
status: done
|
||
- id: T-WIN-003
|
||
file: tasks/003-websocket-receiver.md
|
||
scope: 接收 Android 关键点帧
|
||
status: done
|
||
- id: T-WIN-004
|
||
file: tasks/004-keypoint-deserialize.md
|
||
scope: 239 字节帧反序列化
|
||
status: done
|
||
- id: T-WIN-005
|
||
file: tasks/005-vrm-loader.md
|
||
scope: VRM 模型加载
|
||
status: done
|
||
- id: T-WIN-006
|
||
file: tasks/006-skeleton-retarget.md
|
||
scope: 关键点 -> VRM 骨骼重定向
|
||
status: done
|
||
- id: T-WIN-007
|
||
file: tasks/007-scoring-dtw.md
|
||
scope: DTW 评分引擎
|
||
status: done
|
||
- id: T-WIN-008
|
||
file: tasks/008-game-ui.md
|
||
scope: 主界面 + 游戏界面 + 结算
|
||
status: done
|
||
- id: T-WIN-009
|
||
file: tasks/009-source-display.md
|
||
scope: 模型/动作来源信息展示
|
||
status: done
|
||
- id: T-WIN-010
|
||
file: tasks/010-about-page.md
|
||
scope: 关于页面 + 开源声明
|
||
status: done
|
||
- id: T-WIN-011
|
||
file: tasks/011-build-script.md
|
||
scope: Windows 打包脚本
|
||
status: done
|
||
- id: T-WIN-012
|
||
file: tasks/012-about-version.md
|
||
scope: 「关于」清单展示当前版本号
|
||
status: done
|
||
- id: T-WIN-013
|
||
file: tasks/013-scene-selection.md
|
||
scope: API 升级 rest-api 0.5.0 + 场景选择 + 物理落地
|
||
status: done
|
||
- id: T-WIN-014
|
||
file: tasks/014-full-package.md
|
||
scope: 发布整包(单个 zip + SHA256SUMS,不拆分卷)
|
||
status: done
|
||
- id: T-WIN-016
|
||
file: tasks/016-aabb-transforms.md
|
||
scope: 场景包围盒沿树累乘变换(修复入树前用 global_transform 导致的 ERROR 与范围偏位)
|
||
status: done
|
||
- id: T-WIN-015
|
||
file: tasks/015-keepalive-dedup.md
|
||
scope: 连接保活 / 设备去重 / 状态机(契约 websocket-keypoints 0.2.0,与 T-AND-011 对齐)
|
||
status: done
|
||
- id: T-WIN-017
|
||
file: tasks/017-pe-version.md
|
||
scope: 发布包 exe 的 PE 版本资源(Windows 属性页显示的文件/产品版本)必须等于发布版本
|
||
status: done
|
||
- id: T-WIN-018
|
||
file: tasks/018-release-acceptance.md
|
||
scope: 发布包级端到端验收(读包内 pck:版本号 / 界面显示值 / 契约表 / 资源可加载)
|
||
status: done
|
||
- id: T-WIN-019
|
||
file: tasks/019-cross-end-integration.md
|
||
scope: 跨端集成验收(包内客户端 × 真实 Web 服务端)+ 补 Motion.thumbnailUrl 契约字段
|
||
status: done
|
||
- id: T-WIN-020
|
||
file: tasks/020-ws-contract-conformance.md
|
||
scope: WebSocket 契约一致性验收(Node 独立客户端 × 发布包内 PoseServer)+ 故意不合规的负例服务端
|
||
status: done
|
||
|
||
deliverable:
|
||
artifact: opendance-windows-v0.2.3.zip
|
||
packaging: Godot 导出脚本(Linux 直接导出 / Windows 兜底)
|
||
release_rules: # 文档 §5.7 硬性要求
|
||
- 单个完整包,禁止 .partN 分卷
|
||
- 同时上传 SHA256SUMS(裸文件名,可直接 sha256sum -c)
|
||
includes:
|
||
- OpenDance.exe
|
||
- OpenDance.pck
|
||
- THIRD_PARTY.md
|
||
- README.txt
|
||
- README.md
|
||
- contracts/ # 当前版本契约快照
|