diff --git a/audit/20261005_qmt_identity_env_plan.md b/audit/20261005_qmt_identity_env_plan.md index c12000d0..32f451b3 100644 --- a/audit/20261005_qmt_identity_env_plan.md +++ b/audit/20261005_qmt_identity_env_plan.md @@ -87,21 +87,30 @@ env SANGUO_QMT_ACCOUNT > env BIGQMT_ACCOUNT_ID(兼容别名,存量 wrapper 设 | `docs/deployment/vps-production-runbook.md` | 身份文件条目(CI 基建门:qmt_relogin/bridge_switch_ops 触发) | | `docs/superpowers/specs/2026-10-03-monitoring-design.md` | gate 簇身份链一句话 + 坑台账 | -### 测试策略(tests/trader/test_qmt_identity.py 三组钉) +### 测试策略(tests/trader/test_qmt_identity.py 四组钉) 1. **装载链语义**:env 两名覆盖、`SANGUO_IDENTITY_JSON` 指空=RuntimeError、模块 `ACCOUNT` ≡ json。 2. **单源一致性(anti-drift,休市表先例)**:identity ≡ live.yaml.account ≡ ∈ watch_accounts ≡ gate_common.ACCOUNT ≡ xt_gateway/qmt_gateway_client 镜像解析值(env 清空)。 3. **字面量 grep-pin**:`66639661` 只允许出现在 config 三件套 + tests/ + docs/ + audit/; 生产码面(scripts/、sanguo_*/)零字面量——任何新增扩散直接被单测抓住。 +4. **文件格式钉=纯 ASCII**(10-07 补,🔴 生产事故反向钉):PS5.1 `Get-Content` 默认按 + ANSI/GBK 解无 BOM 文件,文件含 UTF-8 中文原始字节 → `ConvertFrom-Json` + FormatException → env 注入失败。10-06 21:00 xt_eod 实证全链: + `BIGQMT_ACCOUNT_ID` 未注入 → 桥 shim import 期硬错 `account_id is required` + → universe ETF/基金=0 → rc=1(对照 10-05 同假期班 rows=37301 正常)。 + 修=文件中文一律 `\u` 转义(`ensure_ascii`),双端等值:Python `json.load` + 与 PS5.1 `ConvertFrom-Json` 均原生解转义。**phase-③ 生产 wrapper 裸 + `Get-Content` 读此文件的安全性由本钉担保**(改文件加中文必红)。 ## 五、分阶段上线 | 阶段 | 时点 | 内容 | |------|------|------| | ① repo | 本班(10-05) | 上表全部 + 测试 + 两档更新;push 后 CI test 绿即达(nas-deploy 楔死=找 infra 手动 promote,既定协议) | -| ② VPS | **10-08 复市验证窗口后**班车 | promote 带上 json + 新脚本;10-08 07:50 relogin 首班跑旧码=纯净验证 | -| ③ 生产 wrapper | ②后 | `run_shadow_bridge.ps1` 等库外资产改读 json(runbook 非代码资产流程报备 infra) | +| ①′ ASCII 化修复 | **10-07(10-08 窗口前)** | json 改 `\u` 转义 + 第④钉;**紧急性=10-08 复市 21:00 xt-daily 必须能用**(10-06 起已断,30d 窗口拉取自愈无数据丢失);部署须在 10-08 21:00 前落地(理想=10-07 当天,当晚 21:00 班即真班验证) | +| ② VPS | **10-08 复市验证窗口后**班车 | promote 带上 json + 新脚本;10-08 07:50 relogin 首班跑旧码=纯净验证(注:①′ 若 10-07 发车则 ② 的 json 部分已随行,脚本部分仍候窗口后) | +| ③ 生产 wrapper | ②后 | `run_shadow_bridge.ps1` 等库外资产改读 json(runbook 非代码资产流程报备 infra);裸 `Get-Content` 安全性由第④钉担保,也可加 `-Encoding UTF8` 双保险 | | ④ 可选增强 | 按需 | setx /M 机器级兜底;mini_path 接线;watch_accounts 多账号扩展 | ## 六、回滚 diff --git a/config/qmt_identity.json b/config/qmt_identity.json index a6c87beb..ba77a36e 100644 --- a/config/qmt_identity.json +++ b/config/qmt_identity.json @@ -1,5 +1,5 @@ { "default_account": "66639661", "kind": "simulated", - "mini_path": "C:\\国金QMT交易端模拟\\userdata_mini" + "mini_path": "C:\\\u56fd\u91d1QMT\u4ea4\u6613\u7aef\u6a21\u62df\\userdata_mini" } diff --git a/tests/trader/test_qmt_identity.py b/tests/trader/test_qmt_identity.py index 39ad2927..152b4f9a 100644 --- a/tests/trader/test_qmt_identity.py +++ b/tests/trader/test_qmt_identity.py @@ -60,6 +60,20 @@ def test_module_account_bound_to_identity(): assert gate.ACCOUNT == _ident()["default_account"] +def test_identity_file_ascii_only(): + """④ 文件格式钉: 纯 ASCII(中文一律 \\u 转义)。 + + PS5.1 Get-Content 默认按 ANSI/GBK 解无 BOM 文件——文件含 UTF-8 中文 + 原始字节时 ConvertFrom-Json 直接 FormatException(2026-10-06 xt_eod + 实证: BIGQMT_ACCOUNT_ID 注入失败→桥 shim import 期硬错 account_id + required→universe=0→rc=1)。纯 ASCII 双端等值: Python json.load 与 + PS5.1 ConvertFrom-Json 都原生解 \\u 转义。phase-③ 生产 wrapper 读此 + 文件同样依赖本钉。 + """ + raw = (_CFG / "qmt_identity.json").read_bytes() + raw.decode("ascii") # 非 ASCII 字节 = UnicodeDecodeError 直接红 + + # ---------------- ② 单源一致性 ---------------- def test_single_source_agreement(monkeypatch):