创建人员:dev.developer.project.secondary / infodev-2
开发事项:DEV-ANA-STOCK-VALUATION-PIPELINE-V2-20260801-001
当前审核员:dev.reviewer.project / inforev
方案性质:V003 的限定规范修订,只闭环 F5-R1、F7-R1、F8-R1。
当前状态:PENDING_FOCUSED_DESIGN_REREVIEW;PASS 前仍禁止创建 V2 代码、测试、fixture,禁止修改 ana-dev,禁止真实联网 smoke。
V004 的完整规范由以下两部分共同构成:
dev-doc/project-doc/开发方案/CODE-DESIGN-PROJECT-INFO-STOCK-VALUATION-PIPELINE-V2-V003.md=28030 bytes / 358C37EE1FE7F5F832FAF33EBDEB1B1714DE46F315A55A1C1D53AF43D687C61F;本文件明确替换 V003 第 9、13、15、18、20 节中对应的 freshness、终态文件/stdout/receipt、task-start、长城 fixture 路径条款;其余 V003 合同逐字继承且继续有效。冲突时以本文件为准。F1—F4、F6 已在 DEV-AUDIT-PROJECT-INFO-STOCK-VALUATION-PIPELINE-V2-DESIGN-REREVIEW-20260801-001 通过,不在本版重开。
每个可复用字段组必须保存并参与判定:data_kind,ticker,requested_as_of,baseline_as_of,data_date,publish_date,fetched_at,expires_at,adapter_version,raw_hash,schema_status,as_of_status,semantic_status,watermark。时间均为带时区 ISO-8601;TTL 从原始请求成功完成的 fetched_at 起算,expires_at=fetched_at+TTL,判断时刻固定为本次 process_start,不随单个 provider 完成时间漂移。
共通 fresh predicate:
baseline_as_of <= requested_as_of
and publish_date <= requested_as_of(字段需要发布日时)
and data_date <= requested_as_of
and process_start <= expires_at
and adapter_version/hash/schema/as_of/semantic 全部通过
and data_kind 专属水位条件通过
任一值未知不视为 fresh。状态只允许 FRESH|STALE|MISSING:命中且全部 predicate 通过为 FRESH;候选存在但 TTL、水位、hash、版本、schema、as-of 任一失败为 STALE;无候选为 MISSING。
| data_kind | TTL 与专属水位 | FRESH | STALE/MISSING 后动作 | 失败终态/停止 |
|---|---|---|---|---|
stock_identity |
7×24h;证券代码、市场、orgId 必须完整 | 直接复用,不请求 | 在预算内请求 CNInfo stock list | 取不到为核心 BLOCKED;不自由换站 |
announcement_index |
requested_as_of 距 process 本地日期<=7天时 6h,否则 30×24h;watermark=max(announcementTime<=as_of) |
复用索引并继续 A1 选取 | 请求固定 CNInfo page,直到覆盖所需报告期或登记页数上限 | 核心字段无 A1 为 BLOCKED;非核心为 gap;达到登记上限即停 |
market_close |
30×24h;data_date 必须等于交易日序列中不晚于 as-of 的最近一日,价格>0 | 复用,不请求 | 请求固定 kline | 无合法收盘价为 BLOCKED;不使用陈旧值 |
shares_market_cap |
15min;仅当 requested_as_of 等于 fetched_at 的本地日期,且股本>0、市值>0、price×shares 勾稽通过 |
复用,不请求 | 请求固定 quote;历史 as-of 只允许复用“baseline_as_of=requested_as_of 且当日采集”的候选 | 取不到为 BLOCKED;不得把当前股本回填旧 as-of |
finance_main|income|balance|cashflow |
requested_as_of 距 process 本地日期<=7天时 6h,否则 30×24h;watermark=(NOTICE_DATE,REPORT_DATE);所需三期/表项齐全并有 A1 ID |
复用满足的表/期间 | 只请求缺项或陈旧 reportName;成功项可独立提交 | 核心三期利润/资产负债缺失或无 A1 为 BLOCKED;非核心现金流项为 gap;不使用 STALE 核心值 |
forecast_summary |
6h;watermark=max(REPORT_DATE|UPDATE_DATE<=as_of);机构数与年度字段完整 |
复用汇总 | 请求固定 summary | 失败为一个预测 gap,然后允许请求 detail;不阻断核心 |
forecast_detail |
6h;watermark=max(detail_report_date<=as_of);每条机构、日期、年度、数值完整 |
复用明细 | 请求固定 detail,这是第二且最后来源 | 失败或 4/3 差异并入唯一 W_FORECAST_COVERAGE,立即停止 |
STALE 原始 blob 保留为诊断,但绝不作为正式字段值;刷新失败不会把 STALE 改名为 FRESH。局部失败时只有表中明确非核心项可以 gap 降级。负 HTTP/schema/semantic 结果仍只按 V003 的 60 秒本次运行去重,不进入本表的 reusable baseline。
候选先按 baseline_as_of 取不晚于 requested_as_of 的最大值;同一 baseline_as_of 再按规范化 watermark tuple 取最大值;watermark 完全相同时,按 64 位小写十六进制 data_hash 的 ASCII 字典序取最大值(max)。current.json 使用同一三元组比较;较旧/较小候选不得覆盖较新/较大指针。测试固定覆盖每个 data_kind 的 FRESH、STALE、MISSING,以及同 as-of 两个相反 data_hash 插入顺序仍选择同一最大 hash。
成功数据包只允许以下相对文件名:
| 文件 | COMPLETE | COMPLETE_WITH_GAPS | DATA_READY_NEEDS_JUDGMENT |
|---|---|---|---|
data_snapshot.json |
必有 | 必有 | 必有 |
snapshot_build_report.json |
必有 | 必有 | 必有 |
valuation_snapshot.json |
必有 | 必有 | 禁止 |
valuation_results.json |
必有 | 必有 | 禁止 |
report.md |
必有 | 必有 | 必有,固定 16 节且判断章节为 GAP |
qa_report.json |
必有 | 必有 | 必有 |
gaps.json |
必有、空数组 | 必有、非空 | 必有,至少 judgment gap |
source_evidence.json |
必有 | 必有 | 必有 |
provider_results.json |
必有 | 必有 | 必有 |
runtime_metrics.json |
必有 | 必有 | 必有 |
runtime.log |
必有 | 必有 | 必有 |
manifest.json |
最后写、complete=true | 最后写、complete=true | 最后写、complete=true、status 同名 |
外部提交回执固定在正式目录同级:<OUT.name>.commit-receipt.json,不位于 OUT 内,不进入 manifest。成功 stdout 中 manifest_path 指向 OUT/manifest.json,receipt_path 指向该同级回执。
BLOCKED/FAILED 不创建 OUT 和 receipt;失败包固定为同级 OUT.failed-<run_id>/,必有 failure.json,runtime_metrics.json,runtime.log,可有 provider_results.json,source_evidence.json,禁止 manifest.json,report.md,valuation_snapshot.json,valuation_results.json,qa_report.json。ticker 输入合同错误 exit 2 时连失败包也不创建。
ticker 模式每个终态都在 stdout 输出且只输出一行规范 JSON。下列字段全部出现,缺项一律 JSON null,不得省略、空串或另造字段:
{
"schema_version": 1,
"status": "COMPLETE|COMPLETE_WITH_GAPS|DATA_READY_NEEDS_JUDGMENT|BLOCKED|FAILED|INPUT_ERROR",
"run_id": "string|null",
"exit_code": 0,
"output_dir": "absolute-string|null",
"failed_dir": null,
"manifest_path": "absolute-string|null",
"manifest_sha256": "hex|null",
"receipt_path": "absolute-string|null",
"receipt_sha256": "hex|null",
"receipt_bytes": 0,
"task_start": "ISO-8601|null",
"task_start_source": "arg|process_start|null",
"process_start": "ISO-8601|null",
"terminal_at": "ISO-8601|null",
"task_wall_seconds": 0.0,
"process_wall_seconds": 0.0,
"gap_count": 0,
"error_code": null,
"error": null
}
字段值矩阵:
receipt_bytes=null。V1 --input 兼容模式不使用该 schema,继续严格遵循 V003 第 5 节的 V1 stdout/stderr 0/2/3。
OUT.commit-receipt.json 固定包含:schema_version,run_id,status,output_path,manifest_path,manifest_sha256,manifest_bytes,commit_ready_at,commit_finished_at,task_start,task_start_source,process_start,task_wall_seconds,process_wall_seconds,wall_scope="through_commit_finished"。文件写完后计算 receipt_sha256/receipt_bytes,只写 stdout,不自引用回执本体。stdout 的 manifest/receipt 路径、hash、bytes 和双 wall 必须逐值匹配正式文件与 receipt;测试复算两个 hash。
本事项的用户实现请求来自 Codex 任务 019fb338-fe89-7d52-9ba6-513e82de54d8 的 turn 019fbd7c-00c5-7962-8a80-3206ca5a58d9(用户消息“按照这个思路去做吧”)。Codex read_thread 返回 startedAt=1785590448 Unix 秒,规范化为 2026-08-01T21:20:48+08:00。实现证据必须保存 thread/turn/startedAt/ISO 映射;真实 smoke 两次均传同一实际 task-start:
python -m stock_valuation_pipeline_v2 --ticker 001270.SZ --as-of 2026-08-01 `
--cache-dir dev/tmp/valuation-v2-smoke/cache --output-dir dev/tmp/valuation-v2-smoke/cold `
--task-start 2026-08-01T21:20:48+08:00
python -m stock_valuation_pipeline_v2 --ticker 001270.SZ --as-of 2026-08-01 `
--cache-dir dev/tmp/valuation-v2-smoke/cache --output-dir dev/tmp/valuation-v2-smoke/warm `
--task-start 2026-08-01T21:20:48+08:00
断言:task_start<=process_start<=terminal_at;task_wall_seconds>=process_wall_seconds>=0;receipt 双 wall 是到 commit_finished 的权威值,stdout 与之完全相等;包内 runtime 双 wall 是到 commit_ready,均不大于 receipt;冷/热运行使用同一 task_start,热运行 task wall 可更大,不能用 process wall 替代总任务墙钟。其他 smoke 换股条件和证据清单继续继承 V003。
V003 中不存在的 greatwall_example.json 全部作废,不得创建假同名替代文件。唯一冻结路径为:
dev/ana-dev/test/stock_valuation_pipeline/fixtures/great_wall_military_20260731.json=7142 bytes / 06AB6A7C45C2E43F71654C616F15A826B21E468C4BA72AFB0B253C9DD89FACD8。
直接 V1 与 V2 bridge 的无 force、复跑、force、输入错误比较全部使用这个实际路径;命令、stdout/stderr、V1 三件套 bytes/hash 和 V2 bridge 对比证据也登记该路径。V1 测试入口和 10/10 基线继续继承 V003,不修改 ana-dev。
V004 新增且仅新增以下方案级验收:
V004 只提交现有 dev.reviewer.project 对 F5-R1、F7-R1、F8-R1 做限定复审。只有明确 PASS 后,才允许创建 V2 代码、测试和 fixture;本文件不回退 V003 已通过合同,也不授权修改 ana-dev 或提前联网。