11 KiB
11 KiB
决策日志 (DECISIONS)
| 日期 | 决策 | 背景 | 理由 |
|---|---|---|---|
| 2026-07-24 | 以 Web 上位机 JS 为协议第一证据源 | 三条证据线:Web JS / APK / 固件 | Web Bluetooth JS 通常未重度混淆,可读性最高,可 fastest path 拿到 UUID 与命令格式,再与 APK/固件互证 |
| 2026-07-24 | CLI 用 Python+bleak | 本地化+agent 化需求 | bleak 跨平台、无需 root 以外依赖;JSON I/O 便于 agent 编排;Pillow 覆盖全部抖动算法 |
| 2026-07-24 | 项目纳入 git 管理 | 治理规则要求 | 原始目录非 git 仓库;逆向产物多、需频繁提交与回溯 |
| 2026-07-24 | 倒计时前缀位图帧不复刻 JS 的 off-by-one | timedjs2.js:206-224 循环 i < len-1 丢末字节 |
判定为 JS 端笔误(设备缓冲兼容完整帧);CLI 发完整 n*32 字节,避免在末字符右下角丢 8 像素 |
| 2026-07-24 | 倒计时日期/休眠小时采用 BCD 编码 | timedjs2.js:242-243 / ble.js:4013-4015 均为十进制字符串直拼后经 hexToBytes | 实测 JS 证据:month=12 → 字节 0x12,hour=23 → 0x23;与 setTime 的真 hex(intToHex)不同,需注意区分 |
| 2026-07-24 | 固件头格式确认(magic 'pQ'/flags 0x01AA/长度/CRC32(body)/64B 头/0x20 填充 0x00) | 以 zlib.crc32 反推验证 CRC 字段 = body 的 CRC32,重打包字节级往返一致 | fw_pack 可生成与原镜像格式一致的文件,是固件可控(G4)的基础 |
| 2026-07-24 | 中英混排 0.5 单位的倒计时前缀在 CLI 拒绝 | JS '0'+charCount 遇 3.5 生成非法 hex "03.5" |
属于上游 bug 路径,CLI 显式报错优于发送畸形帧 |
| 2026-07-28 | 真机测试阻塞定责:USB/IP 透传链路(hci0=vhci_hcd,源 192.168.61.35:3240 Intel AX200)在 BLE 连接数据窗口 ~3s 后硬停 | btmon 两次复现:连接建立成功→MTU 交换成功(设备 RX MTU 512)→服务发现推进→~19 个 ACL 包后悬崖式断流→Disconnect 0x08;对照设备(小米温湿度计 RSSI -27)同样失败 | 排除设备与协议软件问题(扫描/连接建立/ATT 初期均正常);属 usbip-host 中断端点饥饿类故障;需在 usbip 源机原生运行或修 usbip,详见 PROGRESS.md 阻塞节 |
| 2026-07-28 | 结论修正:根因 = 大 MTU GATT 流量触发链路断流(非此前判断的"中断端点饥饿"),具体归因于 usbipd-win/VBoxUSB/VHCI/AX200 固件链中某一环,无法唯一归因 | 熠管家在 Windows 侧排查:76B 响应完整到达 guest、下一请求已被 AX200 接收;ATT MTU=23 时全部服务+22 个 characteristic 发现成功、无监督超时;usbipd-win 5.3.0 + Ubuntu 6.8.0-136 均为最新 | 不能全局降 MTU(EPD 图像帧 244B > MTU23),故转向 bridge 架构:BLE 在 host-win 原生执行,guest 经 RPC 调用(见下条) |
| 2026-07-28 | 引入 bridge 能力:host-win 原生跑 bleak(WinRT) 并以 JSONL/TCP 暴露 RPC,ubuntu-openclaw 的 ppclock 经 BridgeTransport 远程调用 | usbip 链路无法承载大 MTU GATT;Windows 原生 BLE 无此问题;NFS 仓库两边可达 | 交付:tools/bridge_server.py(单文件服务端)+ src/ppclock/bridge.py(与 BLETransport 同接口)+ CLI --via bridge://host:port / PPCLOCK_VIA 环境变量 |
| 2026-07-28 | RXTX 命令通道 = 331f(非 web 文档的 1f1f) | 实机 GATT 诊断(bridge services op):1f1f(h=53) 仅 write 无 notify,写入 ATT-ACK 但设备不执行;331f(h=57) notify+write+read,经其实测 EFEF/模式/倒计时/停车牌全部生效 | ppclock 全栈切换(protocol.RXTX_CHAR_UUID=331f、BLETransport/BridgeTransport 写路径);保留 1f1f 为 legacy 常量 |
| 2026-07-28 | 设备 ID 反解参数序实机校正:snprintf 实参序为 MAC5,MAC4(非固件代理读的 MAC4,MAC5) | 实机 ID '81233F3C267112' 仅按 MAC5 在前才能反解出广播地址 18:BC:5A:5D:BF:28(NVDS 反转序);按原序则掩码矛盾 | protocol.recover_mac_from_device_id 已修正并锁定实机向量测试;firmware-analysis §4.2 对应行以本条为准 |
| 2026-07-28 | 设备睡眠行为适配:广播窗口短(约 30-60s),连接态保持清醒 | 实测:空闲即停广播;单连接 batch 可在窗口内跑完全部命令 | 现场测试统一用 ppclock batch 单连接;唤醒守候循环(每 15-20s 重试)跨窗口执行 |
| 2026-07-29 | SUOTA 状态码 8/16 = 会话信息码而非失败(仅本固件) | 反汇编 MEM_DEV handler(0x07FCB6F8):type 0x13 命中 bit4 位测试 → 发状态 16 且 SPOTA 状态保持(0x07FCB770-0x07fcb772);type 0x12 → 状态 8 并清会话(0x07FCB780);空镜像探针与正式烧录均先收 16 后流程完好 | bridge ota 对 8/16 记录并继续,块确认只认 2;APK 错误表未覆盖 16,以固件证据为准 |
| 2026-07-29 | bridge OTA 大请求需显式 StreamReader limit | asyncio 默认 64KiB 行限制,OTA 镜像 hex 请求 ~144KB 永不可达(三轮"静默停滞"根因);空镜像探针 0.6s 全通证明管线无恙 | build 9: start_server(limit=4MiB);教训:大载荷 RPC 协议设计必须考虑传输层帧限 |
| 2026-07-29 | SUOTA 状态码分两类:会话信息码(8/16)与流程错误码;16=MEM_DEV type 0x13 位测试应答(固件 0x07FCB770),状态保持 | 反汇编 MEM_DEV handler + 三轮烧录对照(16 恒在 MEM_DEV 后 ~1s 到达,块未受影响) | bridge 对 8/16 记录继续、块确认只认 2;APK 表未覆盖 16,固件证据为准 |
| 2026-07-29 | SUOTA 状态 22/20 根因分层:22=0x38000 产品头读电气失败(GPIO_MAP 引脚错);20=读成功但非 'pR'(引脚有效、0x38000 疑为空) | GPIO 探针(max_blocks=2 安全模式):A{00,00,06,05}→22、B{40,00,06,05}→22、C{05,06,00,40}→20;C=APK 整数 0x05060040 的 BE 字节,为唯一电气有效候选 | GPIO_MAP 采用 C(BE 序);剩余阻断=0x38000 产品头('pR')缺失/无效,见下条 |
| 2026-07-29 | 0x38000 产品头阻断为 vendor 级问题:固件在首 0x200 缓冲处理时校验 0x38000 的 'pR' 产品头(0x07FCB4AA),无效则发 20 并中止该缓冲处理;本机疑以裸 'pQ' 直启(无产品头) | 反汇编完整校验链;固件镜像内 0x3A19 处的 70 52 系代码巧合非真产品头;MEM_INFO 读回 00000000 | 强推 END 有变砖风险(END 会写 0xAA 标志+复位,裸启兜底可恢复但需 JTAG 兜底方案);暂缓强推,先与用户决策 |
| 2026-07-29 | vendor 固件目录实证:qbsg.top /api/firmware/catalog 免认证开放,PP_da14585_4.2_CH.img 与本地镜像 sha256 完全一致(vendor OTA 镜像=本镜像,无产品头附加);NEW 变体同样引用 0x38000 检查 | 下载比对(analysis/apk/vendor_catalog.json + vendor_PP_CH/NEW.img) | 排除"vendor 镜像含产品头"假设;阻断确在设备端 0x38000 内容,非镜像差异 |
| 2026-07-29 | 全量烧录实证安全性论证:产品头校验失败时所有缓冲处理在写 flash 前中止(state[0x70] 恒 0),END 仅写 0xAA 于 [state[0x60]+2]=0x0002 而该字节原本就是 0xAA(无操作),复位后裸启原固件 | 反汇编 END 路径(0x07FCB7C6-0x07FCB7E4)与缓冲写路径(0x07FCB514 依赖中止的头部处理产物 state[0x74]) | 全量跑 OTA 的最坏结果=安全空转+复位;若中途校验通过则自然转正为真实烧录。用户授权下可执行 |
| 2026-07-29 | 用户明确授权全量烧录(301 块+END+复位,gpio_map=BE 序 C),要求全程记录与 review | 用户原话:"授权 注意做好记录和review"(此前已授权"做一下审慎测试后刷机") | 执行范围:fw_tst.img(DIS 版本串 3 字符差异);留证:状态流日志 docs/suota-flash-log.jsonl;事后验证:scan/connect/DIS 读 |
| 2026-07-29 | G4 固件可控路径选型:B(免线刷软件利用),放弃 UART 线刷恢复工厂布局(路径 A 文档保留备查) | 用户原话:"肯定是B";B 路径已具备:图像 flash 持久化写(0x2E000)、EF 激活 flash 写(0x3Fxxx)+ 离线 keygen、全部 BLE 功能可控、SUOTA 工具链就绪(工厂布局设备可直接复用) | 任务说明目标3 以 B 路径达标;A 路径(线刷 .bin + UART)作为可选增强留存 docs/firmware-layout.md |
| 2026-07-30 | MCP 连接管理选型方案 C:按需连接 + 空闲保持 + 串行锁 + 掉线重连一次 | 三方拉扯:设备长睡眠(广播窗口仅 30-60s)vs agent 连续操作体验(每操作重连会撞睡眠窗口)vs 电池(常连使设备保持清醒耗电) | 首次操作守候连接(窗口覆盖 30-60s 广播),操作后保持连接、空闲 --idle-timeout(默认 300s)自动断开让设备睡眠;一把 asyncio.Lock 串行全部操作;操作中掉线重连重试一次再向上抛;退化配置:--idle-timeout 0(每操作即断,最省电)或大值(近常连,体验最佳);详见 docs/superpowers/specs/2026-07-30-ppclock-mcp-design.md |
| 2026-07-31 | 引入 mcp 依赖(ppclock-mcp extra)并钉 >=1.23,<2 |
0.2.0-beta 新增 MCP 服务器层;GOVERNANCE 要求依赖引入留痕;mcp 2.0 移除 FastMCP/memory API | <2 防 2.0 API 断裂;>=1.23 因 transport_security(DNS 重绑定防护,--allowed-hosts 依赖)自 1.23 引入,且 1.23 起含 CVE-2025-66416 修复;本地与 Windows 实测均为 1.29.0 |
| 2026-07-31 | 0.2.0-beta 终审裁定放行项终裁:TRANSPORT_ERRORS 含 OSError 的理论变宽、token 非恒定时间比较、Image.open 惰性解码失败归入 INTERNAL | 终审提出的三处理论风险,需终裁留痕 | 均判低风险放行:OSError 变宽仅使极端平台错误归入 BLE_ERROR(语义可接受);token 比较在可信 LAN + Bearer 场景时序攻击不可行;Image.open 惰性解码异常有 INTERNAL 兜底且 message 带类型详情 |
| 2026-07-31 | --allowed-hosts "" 空串按 None 处理 |
空串逗号拆分得空列表,TransportSecuritySettings(allowed_hosts=[]) 启用防护后连 localhost 族也 421(自锁) |
main() 解析层 _parse_allowed_hosts 以 or None 归一,保持 mcp 默认 localhost 族;含回归测试 |
| 2026-07-31 | 双 TransportError 历史包袱在 MCP 层适配,SDK 零改动 | transports.base.TransportError 与 transports.local.TransportError 同名但互不继承(历史包袱);真实 bleak 写/读路径还裸抛 BleakError 不包装 |
改 SDK 会动公开语义、风险大于收益;MCP 层 device_manager.py:19-26 以 TRANSPORT_ERRORS 全家捕获兜底(base/local 两类 + BleakError + OSError + asyncio.TimeoutError),掉线判定不漏形态 |
| 2026-08-01 | 建立 Gitea 远端(chenwei/qianbian)并增补 Git 协作治理(GOVERNANCE §6) | 用户要求版本控制上云 + 后续治理迭代;此前仓库仅本地 | main 主干直提、分支短命、身份诚实不改写、推送前三项检查(净树/全绿/无 secret)、大文件仅原始输入随库 |