|
| 1 | +# M0 研究发布封套 v1 |
| 2 | + |
| 3 | +`python/scripts/build_m0_research_publisher_envelope.py` 是 M0 研究台账的 |
| 4 | +**离线**发布构建器。它只接受一个已闭合的 |
| 5 | +`qsl_m0_research_source_snapshot.v1` 文件,并调用本仓 |
| 6 | +`m0_research_ledger` validator/aggregator 生成 |
| 7 | +`qsl_m0_research_ledger.v1`。它不导入 selector、平台配置、调度器、券商、 |
| 8 | +策略开关或执行组件。 |
| 9 | + |
| 10 | +输出为严格的 `qsl_m0_research_publisher_envelope.v1`: |
| 11 | + |
| 12 | +```json |
| 13 | +{ |
| 14 | + "schema_version": "qsl_m0_research_publisher_envelope.v1", |
| 15 | + "producer": { |
| 16 | + "repository": "QuantStrategyLab/QuantRuntimeSettings", |
| 17 | + "revision": "<40-char immutable git revision>" |
| 18 | + }, |
| 19 | + "source_artifact": { |
| 20 | + "repository": "QuantStrategyLab/QuantAdvisorResearch", |
| 21 | + "revision": "<40-char immutable git revision>", |
| 22 | + "run_id": "<immutable run id>", |
| 23 | + "artifact_id": "<immutable artifact id>", |
| 24 | + "sha256": "<SHA-256 of the exact input snapshot bytes>" |
| 25 | + }, |
| 26 | + "ledger_sha256": "<SHA-256 of canonical ledger JSON>", |
| 27 | + "ledger": { "...": "qsl_m0_research_ledger.v1" } |
| 28 | +} |
| 29 | +``` |
| 30 | + |
| 31 | +`producer` 和 `source_artifact` 只能包含以上字段;不能附带 token、账户、 |
| 32 | +平台、策略、权重、仓位、订单或运行时目标。`ledger_sha256` 使用 UTF-8 的 |
| 33 | +canonical JSON(键排序、紧凑分隔符、禁止 NaN)计算。台账的 |
| 34 | +`generated_at` 和 `computed_at` 必须相同,均为精确到秒的 UTC `Z` 时间戳。 |
| 35 | +因此同一 source artifact、metadata 和 `--now` 总会生成字节相同的封套。 |
| 36 | + |
| 37 | +## 默认离线构建 |
| 38 | + |
| 39 | +```bash |
| 40 | +python3 python/scripts/build_m0_research_publisher_envelope.py \ |
| 41 | + --source-snapshot /safe/input/m0-source.json \ |
| 42 | + --output /safe/output/m0-envelope.json \ |
| 43 | + --source-artifact-repository QuantStrategyLab/QuantAdvisorResearch \ |
| 44 | + --source-artifact-revision 0123456789abcdef0123456789abcdef01234567 \ |
| 45 | + --source-artifact-run-id 123456789 \ |
| 46 | + --source-artifact-id m0-source-snapshot \ |
| 47 | + --source-artifact-sha256 "$(sha256sum /safe/input/m0-source.json | awk '{print $1}')" \ |
| 48 | + --producer-repository QuantStrategyLab/QuantRuntimeSettings \ |
| 49 | + --producer-revision 89abcdef0123456789abcdef0123456789abcdef \ |
| 50 | + --now 2026-08-29T12:00:00Z |
| 51 | +``` |
| 52 | + |
| 53 | +默认模式只写 `--output` 指定的本地 JSON;没有网络调用,也不会读取任何 |
| 54 | +environment variable。输入源文件限制为 2 MiB、拒绝重复 JSON key,且其原始 |
| 55 | +字节 SHA-256 必须与显式 `--source-artifact-sha256` 一致。metadata 中的 revision |
| 56 | +均要求 40 位小写 git SHA。上述 shell 中的 `sha256sum` 只是操作员生成显式 |
| 57 | +metadata 的便利方式,构建器不会执行 shell 或命令替换。 |
| 58 | + |
| 59 | +## 明确选择的发布 |
| 60 | + |
| 61 | +发布不是默认行为。只有传入 `--publish` **且**同时存在两个专用环境变量时, |
| 62 | +构建器才会在成功写入本地封套后对 HTTPS endpoint 进行一次 POST: |
| 63 | + |
| 64 | +```bash |
| 65 | +export QSL_M0_RESEARCH_LEDGER_PUBLISH_URL='https://research-console.example/api/internal/m0' |
| 66 | +export QSL_M0_RESEARCH_LEDGER_PUBLISH_TOKEN='dedicated-publisher-token' |
| 67 | + |
| 68 | +python3 python/scripts/build_m0_research_publisher_envelope.py ... --publish |
| 69 | +``` |
| 70 | + |
| 71 | +URL 必须是无用户名、无密码、无 query、无 fragment 的 HTTPS URL。token 只从 |
| 72 | +`QSL_M0_RESEARCH_LEDGER_PUBLISH_TOKEN` 读取,作为 HTTP `Authorization: Bearer` |
| 73 | +header;它从不写进封套、标准输出、错误信息或日志。该工具不接受 token CLI 参数, |
| 74 | +也不会读取 broker、平台、策略、运行时或通用控制平面凭据。缺少任一专用环境变量, |
| 75 | +或 POST 失败,都会 fail closed。 |
| 76 | + |
| 77 | +发布 endpoint 只是研究资料接收端:接收者仍必须重验 schema、artifact metadata、 |
| 78 | +`ledger_sha256` 和 `ledger.policy` 的 `research_only/no_order` 固定值。接收、展示或 |
| 79 | +排队研究任务都不能构成 P4/P5/P6、Shadow、Paper 或 live 授权。 |
0 commit comments