From 5d5a9f29f4755a36f9bee2cec479509a1c0a0ddf Mon Sep 17 00:00:00 2001 From: claude_dev Date: Wed, 7 Oct 2026 11:45:00 +0800 Subject: [PATCH] =?UTF-8?q?fix(config):=20=E8=BA=AB=E4=BB=BD=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20ASCII=20=E5=8C=96(\u=20=E8=BD=AC=E4=B9=89)=E4=BF=AE?= =?UTF-8?q?=20PS5.1=20GBK=20=E8=AF=BB=E7=82=B8=E2=80=94=E2=80=9410-06=2021?= =?UTF-8?q?:00=20xt=5Feod=20=E7=94=9F=E4=BA=A7=E5=AE=9E=E8=AF=81:=20Conver?= =?UTF-8?q?tFrom-Json=20FormatException=E2=86=92BIGQMT=5FACCOUNT=5FID=20?= =?UTF-8?q?=E6=9C=AA=E6=B3=A8=E5=85=A5=E2=86=92=E6=A1=A5=20shim=20?= =?UTF-8?q?=E7=A1=AC=E9=94=99=20account=5Fid=20is=20required=E2=86=92unive?= =?UTF-8?q?rse=20ETF/=E5=9F=BA=E9=87=91=3D0=E2=86=92rc=3D1(=E5=AF=B9?= =?UTF-8?q?=E7=85=A7=2010-05=20=E5=90=8C=E5=81=87=E6=9C=9F=E7=8F=AD=20rows?= =?UTF-8?q?=3D37301=20=E6=AD=A3=E5=B8=B8,=2030d=20=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E6=8B=89=E5=8F=96=E8=87=AA=E6=84=88=E6=97=A0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=8D=9F=E5=A4=B1);=20=E4=BF=AE=3Densure=5Fascii=20=E9=87=8D?= =?UTF-8?q?=E5=86=99(=E5=80=BC=20round-trip=20=E7=AD=89=E5=80=BC)+test=5Fq?= =?UTF-8?q?mt=5Fidentity=20=E7=AC=AC=E2=91=A3=E9=92=89(=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=BA=AF=20ASCII,=20phase-=E2=91=A2=20wrapper=20=E8=A3=B8=20Ge?= =?UTF-8?q?t-Content=20=E5=AE=89=E5=85=A8=E6=80=A7=E7=94=B1=E9=92=89?= =?UTF-8?q?=E6=8B=85=E4=BF=9D)+=E8=90=BD=E6=A1=A3=E6=A1=88=20=C2=A7?= =?UTF-8?q?=E5=9B=9B=E2=91=A3/=C2=A7=E4=BA=94=E2=91=A0=E2=80=B2(=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E7=A1=AC=E6=9C=9F=E9=99=90=3D10-08=20=E5=A4=8D?= =?UTF-8?q?=E5=B8=82=2021:00=20xt-daily=20=E5=89=8D,=20=E7=90=86=E6=83=B3?= =?UTF-8?q?=2010-07=20=E5=BD=93=E5=A4=A9)=20[vps]=20[no-doc]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- audit/20261005_qmt_identity_env_plan.md | 15 ++++++++++++--- config/qmt_identity.json | 2 +- tests/trader/test_qmt_identity.py | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) 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):