Files
meida/docs/开发任务包/T13-黄金集CI框架.md
T
xsl e511b6a66f 收尾两批并行开发的文档回写与任务包
- Sprint 执行计划 v1.1:§1.1 补第一批交付实据;T9 SPIKE 结论回写 Sprint 1 表
  (T-P0-16 通过 2.8ms;T-P0-12 有条件;T-P0-10 原型 6/6 + 真实照片重验前置);
  Sprint 2 表标注 T-P2-01~06 交付;新增 §9 两批交付记录
- 开发任务拆解 v1.5:交付回写 + 新风险登记(RTMPose 域差异、BiRefNet 异步化)
- 新增 开发任务包/:三批多 agent 并行的协作规程与 14 份任务契约
- 新增 前置开通清单-云资源与资质.md
- 清理已用毕的评审报告(文档评审 2026-08-13、项目整体评审 2026-08-14),
  README 中相应引用改为留痕表述
2026-08-14 21:07:20 +08:00

5.6 KiB
Raw Blame History

T13 · 黄金集回归框架接入 CI

对应任务:T-P2-11 🔴 | 需求:FR-KB-11、NFR-MAINT-04(指标退化阻断合并)、架构 §17「黄金集是最重要的一道防线」| 分支:task/t13-golden-ci | worktree:/home/xsl/meida_backend-t13 先读《README.md(协作规程)》,遵守全部纪律。

1. 目标

把黄金集从"散在单测里的固定样本"升级为数据驱动的回归框架:用例存 JSON、阈值存配置、CI 强制跑、指标退化直接 fail。V1 先落两个子集(规则黄金集、检索黄金集),Agent 问答与报告结构两个子集留占位(等 Sprint 3/4)。

2. 已就绪的契约(协调提交 9c18021 已提供)

  • pytest marker golden 已注册(--strict-markers 下可直接用);默认 addopts 排除 golden(与 integration 同待遇),make golden / CI 防线 5c 强制跑(env MEIDA_RUN_INTEGRATION=1)。
  • 规则黄金集现有资产:tests/unit/test_rules_golden.py 有 8 条规则 + 11 组样本(硬禁忌压制、多规则叠加等)——不许改它;你的 JSON 用例集是独立交付(可参考其场景设计新写,不是搬运代码)。
  • 检索侧可复用:packages/retrieval/embedding.py 的 DeterministicEmbedder(同文本同向量→黄金集可断言确定性结果)+ packages/rules 的 DSL/引擎。

黄金集规模口径(知识库文档 §7,唯一事实源)

四子集共 330 例(检索 100 / Agent 问答 100 / 诊断 100 / 报告结构 30)。本任务只搭框架 + 规则/检索各 10~15 例种子,规模达标是内容轨 T-P2-16 的事——框架必须让"加用例=加 JSON 行"。

3. 实现要点

允许改动:tests/golden/**(新目录,归你全部)、仅此一处;不改 packages/apps/已有测试。

  1. 目录结构:
    tests/golden/
      README.md              # 用例格式说明 + 如何加用例 + 阈值怎么调
      thresholds.json        # {"rules": {"pass_rate_min": 1.0}, "retrieval": {"pass_rate_min": 0.8, "first_hit_in_top3_min": 0.8}}
      cases/
        rules_cases.json     # 规则黄金集种子
        retrieval_cases.json # 检索黄金集种子
      runner.py              # 用例加载 + 执行 + 指标计算 + 明细报告
      test_golden.py         # pytest 入口(marker=golden,skipif 无 MEIDA_RUN_INTEGRATION)
    
  2. 规则用例格式(rules_cases.json):{"name", "rules": [完整 Rule DSL 数组], "context": {...RuleContext}, "expect": {"must_recommend": [{"slot": "top", "attrs_include": {...}}], "must_avoid": [...], "hard_blocks_nonempty": bool, "forbidden_recommend": [...]}}。判定:evaluate() 结果逐一核对 expect;一条不符 = 该用例 fail。
  3. 检索用例格式(retrieval_cases.json):{"name", "seed_entities": [{entity_type, name, attrs, status, chunks: [text]}], "query", "user_ctx": {...}, "expect": {"must_hit_names": [...], "must_miss_names": [...], "first_hit_in": "top1|top3"}。执行:每个用例先清自己 seed 的实体(按 name 前缀 golden: 命名,跑前 DELETE 这些行,保证幂等重跑)→ DeterministicEmbedder 写 chunk → hybrid_search → 判定。must_miss 语义 = 硬过滤红线(禁忌/draft 实体绝不出现)。
  4. 指标与阻断(runner.py):
    • 每子集算 pass_rate(通过用例/总数);检索加算 first_hit_in_top3_rate;
    • 规则子集阈值 = 1.0(硬结论子集,一条不许退);检索 = 0.8 起步(阈值在 thresholds.json,顾问扩充用例后可调);
    • fail 时输出逐用例明细(name + 期望 vs 实际的差异摘要)——CI 日志里要能直接看出哪条退化了;
    • runner.py 是普通模块(不依赖 pytest),test_golden.py 只是薄壳调用——将来想在本地脚本或 admin 后台跑同一套,不用改框架。
  5. README.md:写明四子集规划(330 例口径)、当前覆盖(两子集 N 例)、加用例流程、"为什么规则阈值必须 1.0"(核心结论由规则产出,规则退化=产品根基退化)。

4. 测试要求(即框架本身)

  • make golden(或 MEIDA_RUN_INTEGRATION=1 .venv/bin/pytest -m golden --no-cov)全绿:两个种子子集通过率 100%(种子用例是手工校准过的,必须全对,否则框架自身有 bug);
  • 阻断语义自证:在本地临时改坏一条用例的 expect 验证会 fail 且输出明细(验证完改回来——提交里只有正确版本;这个自证过程写进提交信息,不写代码);
  • 无 PG/Redis 时 pytest -m golden 全部 skip(不拖累本地 make test)。

5. 禁改清单

通用禁改之外:packages/**、apps/**、tests/unit/**、tests/integration/**、pyproject.toml(golden marker 已注册)、Makefile/CI(防线 5c 已挂)。你的全部产出在 tests/golden/**。

6. 验收标准(T-P2-11)

  1. CI 防线 5c 能跑且通过(本地等价命令全绿);
  2. 指标退化即 fail:人为退化会被拦截(自证过程留提交信息);
  3. 加用例 = 加 JSON 行,零代码改动(README 有流程);
  4. 规则子集含硬禁忌场景、检索子集含 must_miss(红线)场景;
  5. 全部检查绿(tests 不在 mypy 范围;ruff 对 tests/golden 全绿)。

7. 提交信息

test(golden): data-driven golden set framework wired into CI

tests/golden:JSON 用例 + 阈值配置 + runner(规则 pass_rate=1.0、检索 0.8
起步)+ pytest 壳;规则/检索两子集种子,Agent/报告子集占位(T-P2-11)。

偏差说明:<如有写在这里,无则写"无">