feat(v2): 纠偏第二批——接通历史经验加工闭环

覆盖 AC-50/51/52(BR-48/49、E-28)。审计确认的 P1-3 缺口"历史提炼与卡片
不在实时 API 调用图上"由此关闭:提炼、候选治理、卡片进方案全部有真实调用方。

后端:
- contracts:新增 E-28 EXTRACTION_UNAVAILABLE(运行级,不进 HTTP 信封)与
  KnowledgeExtraction 记录类型。契约层强制"失败不得带候选",
  AC-50「模型不可用⇒不产生候选」是类型约束而不是文档约定。
- services/experience_extraction.py(新):真实提炼入口。模型不可用或调用失败
  → 记 E-28 且 candidate_id 为空;不产半成品候选。传输纪律同 assistant_model
  (禁进程内代理、零重试),且 tools=[] 使"越权读材料"在结构上不可能。
  自然语言修订同样必须真实调用模型,没有"把中文猜成条件"的回退路径。
- services/knowledge_cards.py:新增 current_draft/revise/list_cards 与
  registry_conditions。修订只产草稿、保留 origin 与来源、升版本记 parent_version;
  test_cases 纳入可改字段——它是 component_evaluation 对自定义 Skill 的发布门禁,
  不开放则提炼出的候选永远卡在评测门外。
- services/project_assistant.py:enqueue 改用 review_plan.assemble(),
  让 T06-b 的依赖预检(E-19 可定位文案)与维度解析不再被绕过。
- api/prescreen.py:case-timeline、knowledge-extractions、knowledge-candidates
  (创建/修订/状态机)、review-plans(装配/状态机)。角色门禁与既有
  /components 入口一致;id 与数据域由服务端生成;按 id 的路由一律在 run() 内
  查归属,否则 KeyError 会变成 500 而不是 404。
- component_registry/review_plan:下沉 current_draft/version_key 与 list_plans。

前端:
- 新增 /experience-center 独立入口(BR-50)与 ExperienceCenter 组件;
  AgentNav 增加「历史经验加工」。
- originBadge 此前零调用方、.origin-* 无任何 CSS——守卫只 grep 库文件字符串,
  于是"测试通过但功能不存在"。本批补齐消费方与样式,并用左边框样式区分四种来源,
  保证去色仍可区分(AC-42/BR-48)。
- 守卫语义按 AC-55 调整:由"禁止新建路由"改为"禁止重复页面"
  (面板不得搬到独立路由、已合并页必须保持重定向),并新增
  experience-center-ui 守卫(已登记 verify.py,共 12 项检查)。

测试:新增 36 项(提炼 15 / 候选治理 15 / 卡片到运行 6),全量 unittest 无回归;
两次同项目运行对照证明卡片确实改变了核查结果,且 basis_ids 指向 卡片id@版本。

未闭合(记录在 17 的剩余缺口):真实模型提炼尚未实测(需端点);
界面未经浏览器点击验证;例外边界未进入可求值语言;规则类候选不在本批。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-10-01 00:31:42 +08:00
co-authored by Claude Code
parent 350146d9bc
commit 2e7e19471c
20 changed files with 2195 additions and 14 deletions
+23
View File
@@ -84,6 +84,15 @@ API 候选命名空间 `/api/prescreen`,通过同源 `/api/core/prescreen` 代
| BR-42 | 人工新增和历史提炼 Skills/Rules 共用审核发布路径;编辑已发布内容生成新草稿版本。owner:卡片治理 |
| BR-43 | 雷达只对同刻度且3–8维绘制;其余用完整列表/分组,不遗漏关键项或由面积计算概率。owner:维度呈现 |
| BR-44 | stop 只表示暂不建议推进并附依据;系统不得自动关闭项目或执行正式审批。owner:建议动作边界 |
| BR-45 | 正常预审执行链必须在运行结束时产出新版预审记录(运行视图、维度结果、轨迹),由页面读取;不得依赖测试或演示脚本写入。owner:预审执行链 |
| BR-46 | 维度与阶段由**本次实际执行的核查项与证据**决定:方案未声明维度时不补占位轴;阶段只表达证据成熟度,不看结论好坏。owner:维度投影 |
| BR-47 | 模型不可用时必须显示未完成(降级记录 + 未完成项),不得用固定返回值冒充核查结果。owner:预审执行链 |
| BR-48 | 历史经验加工必须走真实提炼入口:展示"大模型提炼"时须实际调用已配置模型,模型不可用即明确未完成;历史来源与人工来源在视觉上必须可区分(文字+图标+样式)。owner:经验提炼 |
| BR-49 | 新发布的卡片必须能被选入评审方案,并实际影响后续核查;否则不算完成。owner:方案装配与执行链 |
| BR-50 | 三个模块各有独立入口,按已确认原型的深色导航+浅色工作区实现;不得只在旧页下叠加面板。复用旧能力不等于保持旧版布局。owner:界面入口 |
| BR-51 | 会议结果必须与对应材料版本和 AI 轨迹对照;改进候选发布必须调用真实知识发布入口,发布后新运行使用新版本,旧运行仍可回放。owner:改进治理 |
BR-45–51 的正文与验收口径由 [交付纠偏规格](16-delivery-corrections.md) 定案;本表负责编号登记与 owner,编号唯一 owner 仍是本文件。
## 5. Exception Scenarios
@@ -115,6 +124,8 @@ API 候选命名空间 `/api/prescreen`,通过同源 `/api/core/prescreen` 代
| E-24 | 改进未完成对照或未获审核,409 IMPROVEMENT_NOT_VALIDATED | 改进尚未完成验证与审核,暂不能发布 |
| E-25 | 输入超出模型已验证预算,运行结果 JUDGMENT_CONTEXT_EXCEEDED | 本次证据超出专项核查范围,请缩小问题或转人工复核 |
| E-26 | 会议结果代码无法映射,记录状态 OUTCOME_LABEL_UNMAPPED | 评审结果口径尚未确认,已保留原记录,暂不计入通过率 |
| E-27 | 运行视图装配失败(某步骤失败且非预算原因),运行结果 RUN_STEP_FAILED | 本次核查有步骤未完成,已保留其余结果 |
| E-28 | 提炼不可用(未配置模型或调用失败),运行结果 EXTRACTION_UNAVAILABLE | 本次未能完成经验提炼,请稍后重试或改为人工创建 |
运行级错误保存在 degradations/finding 中,HTTP 200 仅表示结果可读取,不表示核查通过。禁止把 failed 状态当作 completed。
@@ -167,6 +178,18 @@ API 候选命名空间 `/api/prescreen`,通过同源 `/api/core/prescreen` 代
| AC-43 | Given 人工新增/历史提炼候选与已发布卡片,When 保存/编辑/审核,Then 共用同一治理入口;已发布编辑产生新草稿,无权及自批均拒绝 | BR-42, E-03, E-05, E-07 |
| AC-44 | Given 0/2/6/9个维度或异刻度,When 展示结果,Then 只对同刻度3–8维画雷达,其余完整列表,硬阻断独立且面积不推概率 | BR-43, E-20 |
| AC-45 | Given 预审建议stop,When 查看结果或模型试图关闭项目,Then 展示依据及人工决定入口,不修改正式审批/项目关闭状态 | BR-44, E-03 |
| AC-46 | Given 演示项目与已确认材料,When 在页面发起预审并在队列中被执行,Then 产生新版预审记录(含维度结果与轨迹引用),面板可读到;刷新页面后仍可读取 | BR-45 |
| AC-47 | Given 缺少必需数据的项目,When 执行,Then 缺证进入未完成项与降级记录,不因缺证给出通过结论 | BR-07, BR-45 |
| AC-48 | Given 模型不可用,When 执行,Then 失败步骤保留、运行标记未完成、面板显示未完成原因;不得伪造核查结果 | BR-47, E-27 |
| AC-49 | Given 同一项目再次发起预审,When 执行完成,Then 生成新的预审记录,旧记录仍可读取 | BR-13, BR-45 |
| AC-50 | Given 模拟历史材料,When 选择案例并请求提炼,Then 若模型已配置则实际调用并产出候选草稿;若模型不可用,返回 E-28 且**不产生**候选 | BR-48, E-28 |
| AC-51 | Given 提炼候选与人工新增,When 用自然语言修改适用范围,Then 形成草稿修订,不直接发布、不自批 | BR-25, BR-26, BR-48 |
| AC-52 | Given 已发布卡片,When 装配评审方案,Then 卡片可被选入方案并影响后续核查(在运行结果中可追溯引用了该卡片版本) | BR-49 |
| AC-53 | Given 已登录用户,When 打开工作台,Then 可见历史经验加工 / AI 预审 / 轨迹复盘三个入口,采用深色导航+浅色工作区;不得只保留旧版落地页布局 | BR-50 |
| AC-54 | Given 预审结果,When 查看,Then 概率状态与依据、动态维度、推进沙盘、可回放轨迹均可操作,且与已确认原型一致(来源文字+图标,颜色不单独传意) | BR-48, BR-50 |
| AC-55 | Given 新增路由与样式,Then 必须通过"防重复页面、权限、数据隔离"约束(不再禁止新增路由或样式) | BR-50 |
| AC-56 | Given 页面录入的模拟会议结果,When 保存,Then 与对应材料版本和 AI 轨迹对照,未匹配的单列且不计入分母 | BR-51, E-23 |
| AC-57 | Given 改进候选,When 完成对照验证与独立审核并发布,Then **实际知识版本生效**:新运行使用新版本,旧运行仍可回放;仅改状态或返回版本号不算通过 | BR-51 |
## 7. Open Questions & Decision Record
+27
View File
@@ -170,3 +170,30 @@ TrajectoryStep 的输入/输出正文通过授权存储引用访问;cost 缺
导入/冲突→AC-23/24;来源与治理→AC-25/26/27/43;方案/维度→AC-28/29/44;概率/沙盘→AC-30/31;轨迹/结果→AC-22/32/33;改进→AC-34/41;数据集→AC-35/36;业务指标→AC-37;专项准入/冻结/预算→AC-38/39/40;卡片UI→AC-42;建议边界→AC-45。
本节明确了候选类型和写路径,但读接口完整清单、DDL、生产角色映射、容量/模型时延及实际目录尚未定案。T00先关闭首个实施切片的缺口,不能以“文档写完”宣布全部Contract gate通过。
### 9.7 已实现接口(纠偏第二批,2026-09-30)
§9.4 要求"拟新增请求参数必须在契约定案及对应 OpenAPI 中完整列出,未定案不开始接口实现"。
以下为**已落地**的接口,路径与字段以本节为准(实现见 `backend/api/prescreen.py`):
| 接口 | 输入 / 输出 | 权限 / 错误 |
|---|---|---|
| GET/POST `/projects/{project_id}/case-timeline` | 无输入;输出 CaseTimeline。POST 从项目材料重算,同项目 revision 递增 | 项目查看/材料编辑;POST 后 201;未重建过 GET 返回 404 |
| GET `/projects/{project_id}/knowledge-extractions` | 输出 `{items: KnowledgeExtraction[]}`;失败记录照常返回 | 项目查看;404 |
| GET `/projects/{project_id}/knowledge-extractions/{id}` | 输出 KnowledgeExtraction | 项目查看;404 |
| POST `/projects/{project_id}/knowledge-extractions` | `event_ids:string[]`(空=全部事件)、`requirement:string[0..2000]`;201 KnowledgeExtraction | 提议者;E-28 记在记录里而**非** HTTP 错误;两者都空 → 422 |
| GET `/projects/{project_id}/knowledge-candidates` | 输出 `{items: KnowledgeCard[]}`(草稿与已发布) | 项目查看;404 |
| POST `/projects/{project_id}/knowledge-candidates` | `kind,title,content,origin,version,source_event_ids,source_evidence_ids,card_scope,team_id,expires_at`;201 草稿。**id 与数据域由服务端生成** | 提议者;E-03/04/07/18 |
| PATCH `/knowledge-candidates/{card_id}` | `requirement`(自然语言)**或** `changes`(`conditions`/`exception_note`/`test_cases`)、`note`(必填)、`expected_revision`;200 新草稿修订 | 编辑者;E-03/05/07。自然语言修订需已配置模型,否则 422 并提示改用结构化修改 |
| POST `/knowledge-candidates/{card_id}/transitions` | `action:evaluate\|publish`、`expected_revision`、`reason` | evaluate 角色 admin/reviewer;publish 角色 reviewer 且不得自批(E-03);未过评测 → 409 |
| GET `/projects/{project_id}/review-plans` | 输出项目自建方案(草稿与已发布);内置种子方案不在此列 | 项目查看;404 |
| POST `/projects/{project_id}/review-plans` | 方案字段(`name,skills,rules,template,budget,audience,run_kind,dimensions,version`);201 草稿。**id 与数据域由服务端生成** | 方案编辑;E-03/07/19/20;拒绝 `tools/allowed_tools` 等工具配置面(ADR-11) |
| POST `/review-plans/{plan_ref}/transitions` | `action:evaluate\|publish`、`expected_revision` | 同候选状态机;依赖未发布 → 评测不通过、发布 409 |
**字段口径补充**:
- `KnowledgeExtraction.status=failed` 时 `candidate_id` 必须为空,`degradations` 必须非空(契约层强制,见 `contracts/prescreen.py`)。
- `KnowledgeCard` 的**例外边界**在本批保存为文本 `exception_note`,不进入可求值条件语言:
注册表条件只支持数值阈值算子,`present/absent` 被既有断言锁定拒绝。这是已记录缺口,不是已实现能力。
- 卡片"适用条件"在运行时**不参与**逐项判定;它经 `knowledge_cards.effective()` 用于域/范围/有效期过滤,
运行内条件求值仍需独立设计。
- 运行装配已改用 `review_plan.assemble()`(依赖预检 + 维度解析),此前该模块在生产被绕过。