Просмотр исходного кода

docs: lock V2 scope, flip hidden sign-off items, add web V2 iteration

V2 plan (06):
- Lock V2 scope line: single-platform single-pack (Content) proving
  decoupling MECHANISM + config-as-truth + observability; breadth/multi-pack
  to V3; visual config editor explicitly out of scope (Excel+CI is the
  foolproof-config ceiling for V2).
- Flip hidden "需要拍板" decisions previously marked "无":
  M0 byte-equal vs semantic-equal + flat→nested mapping algorithm;
  M3 future-pack (dispatch_enabled=false) rule_pack_id write behavior;
  M2 per-entity dispatch guardrail location;
  M4 /blogger field contract reframed as a blocking sign-off, not a test tip.
- Add visual-config-editor to section 12 (V3 backlog).

Web plan (web/docs/03):
- Add "Web V2 迭代规划" consuming CFA V2: M5 timeline/gantt/stalls,
  M0/M2/M3 config-as-truth read views + per-edge rule_pack_id, M-test replay
  diff. Reconcile doc with reality (Next.js + dashboard API already scaffolded).
  Read-only config display only; editing UI deferred to Web V3.

Cross-verified against real code: M5 observability fields all new;
dashboard_service/timeline API + web pages exist as uncommitted WIP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam Lee 1 месяц назад
Родитель
Сommit
affd1b55a0

+ 17 - 8
tech_documents/工程落地/06_V2阶段开发计划.md

@@ -23,6 +23,11 @@ V1 已按 P0–P8 打通「Pattern → 抖音 → Content 判断 → 游走 →
 
 **V2 目标**:还清四笔欠债,交付档 1(配置即真相)+ 档 2(真解耦)+ 档 3(傻瓜配置体验),并把 query 生成 prompt 配置化、补齐后端可观测性。明确**不做**档 4(数据源 / 平台宽度扩展)与多包自由叠加,留 V3。
 
+**V2 范围一句话(锁定)**:**单平台(抖音)单包(Content)跑通「解耦机制 + 配置即真相 + 可观测」三件事**。
+
+- 解耦交付的是**机制**(按 entity / 边 dispatch 的接线),不是宽度证明——4 个 future 包真跑、多平台、数据源宽度均留 V3。
+- 档 3「傻瓜配置」V2 只做到「业务改 Excel → CI 兜底」;**可视化配置编辑器(傻瓜配置最后一公里 UI)V2 不做**,留 web 看板项目 / V3。web 端的 V2 消费规划写在 `web/docs/03_技术开发规划.md` 的「Web V2 迭代规划」,由 web 项目单独迭代。
+
 ## 2. 锁定的范围决策(已确认)
 
 - **档 2 解耦边界**:去 Content 硬编码、dispatch 按 `target_entity` 参数化;walk_engine 真正读 `walk_rule_pack_binding` 按边选包并写回 `walk_actions.rule_pack_id`;**每边 / 每实体先支持单包**,逐步启用 Author / Hashtag / Path / Budget。**不做多包叠加 / 决策合并(V3)**。
@@ -166,9 +171,10 @@ V2 主题开发融合为 6 个解耦业务模块(M0–M5)。每个模块独
 - `openpyxl` 仅作 `[excel]` optional 依赖组,不进 runtime。
 - `config_store` 抽象是纯重构,**不改 `load_policy_bundle` 返回 dict 形状**。
 
-开工前必须拍板:
+开工前必须拍板(开发到 M0 时定,不阻塞前置模块)
 
-- 无。sheet 列 ↔ JSON 嵌套 key 的映射契约在实现时随「sheet↔JSON key 对照表」一并定稿。
+- **byte-equal 还是语义等值(暗礁)**:转换器输出能否与现有 JSON **字节级相等**有真实风险——`policy_json.py:70` 用原始 JSON 文本算 `policy_bundle_hash`,而扁平 Excel→嵌套 JSON 经 `json.dumps` 后受 `ensure_ascii` / `indent` / key 顺序 / openpyxl 行序影响,未必字节相等。需拍板二选一:① 坚持 byte-equal(则锁定 `json.dumps` 参数 + 冻结 Excel 行号映射 + 一次性把现有 JSON 重写为转换器规范输出);② 放宽为「canonical / 语义等值」(`policy_bundle_hash` 改为对规范化后的结构取,不再依赖原始文本字节)。建议开工先做 round-trip 可行性 spike 再定。
+- **扁平行 ↔ 嵌套数组的映射算法**:`rule_packs[].hard_gates[].when.{field,op,value}`、`scorecard.dimensions[]`、`walk_rule_pack_binding[]`(含 `edge_id` 外键)如何在扁平 sheet 里表达与校验,须随「sheet↔JSON key 对照表」定稿(JSON 嵌套达 8 层,非平凡)。
 
 可先按当前默认值推进:
 
@@ -341,9 +347,10 @@ V2 主题开发融合为 6 个解耦业务模块(M0–M5)。每个模块独
 - `evaluator` 区分「单维度缺失」与「全 scorecard 缺失」(当前 `not matched_scoring_rules` 触发 missing_score 太激进)。
 - 不做多包决策合并(V3);future 包仍 `dispatch_enabled=false`。
 
-开工前必须拍板:
+开工前必须拍板(开发到 M2 时定)
 
-- 画像 `missing` 与 `weak` 是否区别对待。建议:`missing`→待复看;`weak`→进 scorecard 按分;最终阈值由业务在 Excel 定。
+- 画像 `missing` 与 `weak` 是否区别对待。建议:`missing`→待复看;`weak`→进 scorecard 按分;最终阈值由业务在 Excel 定。注意:现 `age_50_plus_weak` 把 `["weak","missing"]` 合成一条 gate(`douyin_rule_packs.v1.json`),要分裂行为须拆 gate 或在 `evaluator` 加 field-value 分支。
+- **dispatch「每 entity 最多 1 个」护栏的落点**:`policy_json.py:80-93` 现按 `target_entity=="Content"` 硬编码 + `len(matches)!=1` raise。参数化后该护栏放在 `_select_dispatch()` / `load_policy_bundle()` / `evaluator` 哪一层、以及多 entity 同时 enabled 时的报错口径,须在开发到该步时定。(注:顶层 dispatch 兼容 shim 是否掩盖解耦真伪,另列待业务讨论,不在本条。)
 
 可先按当前默认值推进:
 
@@ -429,9 +436,10 @@ V2 主题开发融合为 6 个解耦业务模块(M0–M5)。每个模块独
 - future 包 `dispatch_enabled=false` 时只写「归属」不跑其 evaluator(依赖 M2 的按 entity dispatch)。
 - 不做多包叠加(V3)。
 
-开工前必须拍板:
+开工前必须拍板(开发到 M3 时定)
 
-- 无。`KEEP_CONTENT_FOR_REVIEW` 走低预算扩展已拍板。
+- **future 包(`dispatch_enabled=false`)的 `rule_pack_id` 写法**:`KEEP_CONTENT_FOR_REVIEW → budget_downgrade` 边绑定 Budget 包(`dispatch_enabled=false`),而 `walk_strategy.py:162` 写的 `decision["rule_pack_id"]` 来自 Content 评估。须拍板:该边 `walk_actions.rule_pack_id` 写 binding 的归属包(Budget)、写 NULL、还是跳过——即「归属包」与「实际跑的包」如何分别落库。
+- `KEEP_CONTENT_FOR_REVIEW` 走低预算扩展已拍板。
 
 可先按当前默认值推进:
 
@@ -513,9 +521,9 @@ V2 主题开发融合为 6 个解耦业务模块(M0–M5)。每个模块独
 - 限流命中区分 `PLATFORM_RATE_LIMITED`(HTTP 429 / 业务 `code=22001`),不混入通用 `PLATFORM_REQUEST_FAILED`。
 - 分类树 v2 响应 `items[].matches[].path` / `matched_paths` 解析补测;文档明确 v2 为当前事实,旧 `data` 结构仅历史兼容。
 
-开工前必须拍板:
+开工前必须拍板(开发到 M4 时定,且为阻塞项)
 
-- `/blogger` 真实字段合同。建议先做一次真实 smoke 固定参数名,再改代码。
+- **Crawapi `/blogger` 完整字段合同**(endpoint path、参数名、author id 映射、account id 格式)。这不只是测试建议而是**阻塞项**:`douyin.py:96` 现打到 `keyword_path`、`from_env`(L44-63)无 blogger path、参数映射未定,作者边在合同固定前无法实现。建议先做一次真实 smoke 固定参数名,再改代码。
 
 可先按当前默认值推进:
 
@@ -686,6 +694,7 @@ V2 主题开发融合为 6 个解耦业务模块(M0–M5)。每个模块独
 5. 前端时间线 / 甘特组件(V2 只后端 API)。
 6. 独立 `step_logs` DB 表(默认增强 run_events)。
 7. DemandAgent 合同改造。
+8. **配置可视化编辑器**:业务在 Excel 配置 + CI 兜底是 V2 的傻瓜配置上限;可视化「编辑」UI 留 web 看板项目 / V3,V2(含 web 端)只做配置「只读展示」。
 
 ## 附录 A:真实 E2E 暴露问题(并自 v1.1 迭代落地)
 

+ 57 - 0
web/docs/03_技术开发规划.md

@@ -370,6 +370,63 @@ web/
 - 游走页是否有筛选器和边详情。
 - 移动端不作为第一优先级;当前 show 本身是宽屏工作台。
 
+## Web V2 迭代规划(消费 CFA V2 可观测性与配置即真相)
+
+> 本节为 Web 的 V2 轮规划,对应后端 `tech_documents/工程落地/06_V2阶段开发计划.md` 的 V2-M5(可观测性)/ M0·M2·M3(配置即真相 + 按边 `rule_pack_id`)/ M-test(真实 case 回放)。**后端 V2 只产出数据与 API,前端 V2 在此独立迭代**(由 web 项目单独排期)。CFA V2 锁定范围:单平台(抖音)单包(Content)跑通「解耦机制 + 配置即真相 + 可观测」;配置可视化「编辑」UI 不在 V2(含 web V2)。
+
+### 现状对齐(与本文档第一版的差异)
+
+本文档第一版写「本轮只写规划,不初始化 Next.js」,但实际 web 已落地骨架与基础消费,Web V2 是在此之上「消费 CFA V2 新增事实」,不是从零搭:
+
+- 前端已初始化(Next.js 15 + App Router):`app/runs/page.tsx`、`app/runs/[runId]/page.tsx`,feature 页 `features/runs/RunListPage.tsx`、`RunDashboardPage.tsx`,组件 `components/pipeline/PipelineHeader.tsx`、`components/cards/*`、`components/badges/StatusBadge.tsx`,`lib/api/client.ts`、`lib/adapters/pipeline.ts`。
+- 后端 Web-1 API 已存在(当前为未提交 WIP):`content_agent/dashboard_service.py`(`list_runs` / `dashboard` / `queries` / `timeline` / `content_items` / `runtime_files` / `runtime_file`),`api.py` 已注册 `GET /runs`、`/runs/{id}/dashboard|queries|timeline|content-items|runtime-files|runtime-files/{filename}`,`schemas.py` 有对应 response model,CORS 已配。
+- 即 Web-0…Web-5 的「骨架 + 基础消费」事实上已落地;Web V2 聚焦三块新消费。
+- **依赖关系**:Web V2 各项依赖 CFA V2 对应模块先落地(新增字段为增量,旧消费不破坏);CFA 未交付前,adapter 对缺字段降级为空状态,不白屏。
+
+### Web-V2-A:全流程时间线与卡点可视化(消费 CFA V2-M5)
+
+职责:
+
+- 把现 `timeline` 的扁平事件流升级为「甘特 / 阶段耗时」视图。
+- 展示每节点 `duration_ms`、`total_duration_ms`、`stalls[]`(decode 超时 / 限流命中 / query 高失败率)。
+- decode 逐条进度(`decode_submitted` / `polling` / `succeeded` / `timeout` 中间事件)。
+
+依赖接口:
+
+- `GET /runs/{run_id}/timeline`(M5 后新增 `stage` / `started_at` / `ended_at` / `duration_ms` / `attempt` / `stall_flag` / `stall_reason` / `total_duration_ms` / `stalls[]`;这些字段当前代码均不存在,由 CFA V2-M5 补,属增量)。
+
+### Web-V2-B:配置即真相只读视图(消费 CFA V2-M0 / M2 / M3)
+
+职责:
+
+- 展示当前生效的规则包(Content 包 hard gates / scorecard / thresholds)与游走 `walk_rule_pack_binding`(边→包)。
+- 在 walk 视图按边展示 `walk_actions.rule_pack_id`(M3 后非 NULL 按边正确),让「哪条边跑了哪个包」可见;future 包(`dispatch_enabled=false`)标注为「已归属未运行」。
+
+依赖接口:
+
+- `GET /runs/{run_id}/content-items` + `runtime-files/rule_decisions.jsonl`(已存在)。
+- `runtime-files/walk_actions.jsonl`(已存在;`rule_pack_id` 字段由 CFA V2-M3 补正)。
+- 建议后端补一个只读「当前配置」摘要接口(暴露 rule_pack / binding 概要),避免前端直接解析 JSON 源文件。
+
+### Web-V2-C:真实 case 回放 diff 视图(消费 CFA V2-M-test)
+
+职责:
+
+- 对接 M-test 语料库回放:同一 case、不同配置(config × case 矩阵)的产物对照。
+- 复用现有 `data_origin` badge 区分「生产事实 / 回放导出」。
+- 展示 snapshot diff(改一档配置后入池 / 淘汰 / `rule_pack_id` 的变化)。
+
+依赖接口:
+
+- 现 `data_origin` 机制(已支持 `runtime_export` / `mixed_with_runtime_export`)。
+- 回放产物经 runtime export 读取,沿用 runtime file 白名单。
+
+### Web V2 不做
+
+- 配置可视化「编辑」(写)能力——CFA V2 傻瓜配置上限是「业务改 Excel + CI 兜底」,可视化编辑 UI 留 Web V3;Web V2 只做配置「只读展示」。
+- 移动端适配。
+- 前端直连 MySQL。
+
 ## 不做
 
 - 本轮不搭 Next.js 代码。