Commit Graph
48 Commits
Author SHA1 Message Date
qiaoqichao fa4163b2d0 feat(v2): 实现SQLite对公租赁经验加工与卡片预审轨迹闭环 2026-10-01 13:38:03 +08:00
qiaoqichaoandClaude Code 9c351b08d3 docs(v2): 记录浏览器验证第二篇与 F11 剩余部分的收口
17 新增「浏览器验证(第二篇):AI 预审 / 历史经验加工」:覆盖的交互、
点通过程中发现并修掉的 2 个缺陷(预审面板不刷新、候选行同 id 连开多行)、
写演示库的副作用清单,以及本数据集下仍点不到的 3 处(沙盘勾选联动、
来源事件勾选、reviewer 视角的审核发布)与 2 处口径待确认项。

15 第 7 节改为本轮交接:F11 三个表面均已由真实 Chrome 走过;F27/F29/F30
与新证据路径;下一任务只剩需要用户或外部输入的部分。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 09:39:08 +08:00
qiaoqichaoandClaude Code c880f40e4c fix(v2): 修掉预审面板不刷新与候选行同 id 连开多行的缺陷
真实 Chrome 端到端验证第二篇(/prescreen-workbench、/experience-center)发现两个
源码守卫与生产构建都看不见的缺陷:

- 发起 AI 预审、运行结束后 PrescreenPanel 不重载:新运行进不了"查看哪一次运行",
  面板继续显示上一次运行,而徽标写着"结果会自动刷新"。根因是 load() 只依赖
  project.id;补修时又发现 worker 先写 run.status、再另写 prescreen_run 视图
  (assistant_worker.process_next),两者不在同一事务,只读一次会读到视图还没
  落库的中间态,因此改为按运行集合重载并在最新运行进入视图前短时重试。
- 候选区 key={card.id} 撞 React key,且「自然语言修改适用范围」「补充独立测试」
  按 card.id 开合,点一行连开 4 行(同一 card.id 的草稿行与各版本行共享 id)。
  改为行级 rowKey(组件id@版本@状态)。

同时新增可选脚本 scripts/browser-e2e-modules.cjs(42/42 通过),并给
test_prescreen_ui.cjs / test_experience_center_ui.cjs 补上对应源码断言。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 09:35:29 +08:00
qiaoqichaoandClaude Code 8e2473cf3e docs(v2): 交接记录不写死 HEAD
交接文档自身的提交会成为新的 HEAD,写死必然过期(本行刚被自己的提交证伪过)。
改为列本轮三个实质提交 + 以 git log 为准。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 03:04:55 +08:00
qiaoqichaoandClaude Code f01619755e docs(v2): 第四批交接记录列全本轮三个提交
原先只记了 f775c6c,读者容易以为整轮就一个提交。补列 ff59d7e 与 4720d72,
并写明 HEAD 应为 4720d72。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 03:04:45 +08:00
qiaoqichaoandClaude Code 4720d72965 fix(v2): 浏览器端到端验证——修掉模块页在浏览器里渲染不出内容的缺陷
首次用真实 Chrome 打开 /trajectory-center(新增可选脚本 scripts/browser-e2e.cjs),
暴露 5 个源码守卫与生产构建都看不出的缺陷,全部修复:

1. 三个模块页读 `list.items`,而 /projects 返回的是 {projects, identity}——
   项目列表恒为空,prescreen-workbench / experience-center / trajectory-center
   整页渲染不出任何面板,只显示"当前身份没有可访问的项目"这种看着正常的空态。
   (第二/三批引入)改为 list.projects。
2. TrajectoryPanel 没被传 identity,canRecord 恒假 → 会议结果录入表单永不出现。
3. ImprovementPanel 草稿下拉以组件 id 作 key/value,同一组件多版本草稿时撞 React key,
   且选不准要发布哪一版;改以 `组件id@版本` 为键值。
4. JSX 文本里的 `**强调**` 会原样显示星号(JSX 不渲染 Markdown),共 9 处;
   改为 <b>(字符串上下文处直接去掉标记)。
5. 深色导航模块名被 flex 压缩折行("AI 预审"断成两行);
   加 flex:0 0 auto + white-space:nowrap。

另修一个既有测试脆弱点:test_trajectory.py 的更正用例断言"哪条排前面",
两条记录同刻度时排序翻转,曾让 verify.py 偶发失败;改为断言"两条都在、更正指向旧记录"。

回归防线:第 5 项补进 test_module_shell_ui.cjs 源码断言;
test_ui_readability.cjs 的导航字号断言改为不把 min-height 钉在规则首位。

验证:scripts/verify.py 14/14 PASS(backend-unit 572 项),
证据 test-evidence/20261001-030127-ff59d7e/;scripts/browser-e2e.cjs 19/19 PASS
(截图在 test-evidence/e2e-batch4/)。该 E2E 脚本刻意不接入 verify.py。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 03:04:18 +08:00
qiaoqichaoandClaude Code ff59d7e8f1 docs(v2): 第四批交接记录补记本轮提交号
15 §7 的 Git 行改为记下 `f775c6c`,与本批其余交接记录口径一致
(前三批同样在 docs 提交里回填实现提交号)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 02:22:19 +08:00
qiaoqichaoandClaude Code f775c6cbe4 feat(v2): 纠偏第四批——会议结果录入与改进发布接真实知识发布入口
- api/prescreen.py:transition_improvement 注入 _knowledge_publisher,
  release 委托 knowledge_cards.publish → component_registry.release;
  按 proposed_revision_ref 以「组件id@版本」精确解析草稿(不取"最新草稿",
  否则会出现"审核的是 A、发布的是 B");客户端自报 released_ref 一律 422;
  非 knowledge 目标 409 诚实拒绝;发布与候选状态同一事务,失败保留旧版。
- TrajectoryPanel:新增会议结果录入(追加式更正走 supersedes_id;
  未匹配单列且不计入分母)。
- ImprovementPanel(新增):偏差→候选→两道评测门→独立审核→发布;
  请求体不含版本号,无自动上线,不自批。
- 界面并入「轨迹复盘」,不新增第四个导航入口(AC-53)。
- 守卫:新增 scripts/test_improvement_panel.cjs(verify.py 13→14 项);
  test_module_shell_ui.cjs 的「只读」断言改为分别锁死「回放只读」与「结果只可追加」。
- 测试:新增 backend/test_improvement_release.py(AC-57 端到端 + 三条反例);
  test_improvements.py 补「自报版本号被拒」。
- 文档:17 第四批交付记录、15 §7 交接、03 §9.4 发布事务边界。

验证:scripts/verify.py 14/14 PASS(backend-unit 572 项),证据
test-evidence/20261001-013517-3e15bda/;scripts/xingbang_batch4_smoke.py
对真实服务器实跑通过(发布指针实测移到新版本)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 02:21:11 +08:00
qiaoqichaoandClaude Code 3e15bda8cd docs(v2): 第三批交付记录与交接(深色导航与三入口)
按 16 §4 的五项口径填第三批,状态记**部分完成**:深色导航、三个模块的独立入口、
轨迹回放界面已接通;界面仍未经浏览器点击验证(F11),录入属第四批。

记录里如实写明而不是含糊:
- 对比度改为守卫内按 WCAG 实算(最低 8.37:1),并说明"配色达标 ≠ 实机版面已验收";
- `/` 默认路由由聊天页改为业务工作区,属**用户可见的行为变化**,列出需确认;
- 工作台旧「评审经验」页签与第二批的知识卡片治理新旧并存,未擅自下线;
- `AgentLoopFlow.tsx` 仍是零引用死代码,本批未复用也未删除;
- 原型顶部演示提示条未实现。

15 §7 交接同步:新增 F20(新旧经验入口并存)、F21(首页路由变更)、
F22(轨迹/会议录入属第四批),F11 扩到三个模块,下一任务改为第四批。

验证:`test-evidence/20261001-005027-ae89462/`(verify.py 13/13 PASS,全量 567 项)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 00:52:13 +08:00
qiaoqichaoandClaude Code ae89462756 feat(v2): 纠偏第三批——深色导航、三模块独立入口与轨迹复盘
覆盖 AC-53/54/55(BR-50)。审计 P1-2「新界面未接入、原落地页与导航未改」
由此关闭:导航改为原型 token 的深色壳,三个模块各有独立路由与入口。

界面:
- navigation.css:导航改用原型 token(nav.bg #102B27 / active #244D41 /
  muted #B1C6BE),身份选择器在深色底上改用 dark 变体(否则白底白字);
  工作区画布保持浅色 #f5f7f9——"深色导航+浅色工作区"是两件事。
  保留可读性守卫锁定的两条规则(导航项 min-height:42px/font-size:14px、
  身份选择器 min-height:42px),原有 7 项守卫全部继续通过。
- AgentNav:品牌改为「兴邦金租/智审工作台」,加「业务工作区」分组标签,
  三个模块入口(AI 预审 / 历史经验加工 / 轨迹复盘)指向各自路由;
  权限仍按角色裁剪,身份仍来自服务端。
- 新增 /prescreen-workbench(AI 预审)、/trajectory-center(轨迹复盘)两个模块路由;
  / 从旧聊天落地页改为业务工作区首页,呈现三个模块入口;原落地页内容保留在
  /assistant,没有被删掉(AC-53 要求的是不再"只保留"旧布局)。
- TrajectoryPanel:消费既有只读轨迹端点,失败/跳过步骤照常列出并带错误码,
  成本缺失显示"未记录(不填 0)",并展示服务端对轨迹范围的说明;
  会议结果只读展示(录入属第四批)。

复用而非复制:三个模块路由都 import 既有的 PrescreenPanel / ImportBatchPanel /
ExperienceCenter,没有在路由里再写一份实现。

守卫:新增 module-shell-ui(已登记 verify.py,共 13 项检查),机械核对
深色 token、三入口存在、已合并旧页仍为重定向、按角色裁剪、
?project= 上下文与不硬编码项目 id、轨迹面板不渲染推理字段,
并做前后端路径一致性断言(界面调用的端点必须真的在后端声明过)。
深色底对比度按 WCAG 公式在守卫内**实算**(阈值 AA 4.5:1,实测最低 8.37:1),
不在文档里声称"应该够清楚"。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 00:50:16 +08:00
qiaoqichaoandClaude Code 01c88af501 docs(v2): 第二批交付记录与交接(历史经验加工)
按 16 §4 的五项口径(页面入口 / 操作步骤 / 实际结果 / 证据位置 / 剩余缺口)
填第二批,状态记**部分完成**:

- 后端闭环已接通并经真实执行链测试(提炼→候选治理→卡片进方案→运行可追溯);
- 本模块独立入口 /experience-center 已建,通过生产构建与新增源码守卫;
- 未闭合三项写清楚而不是含糊带过:真实模型提炼未实测(F17,需端点)、
  例外边界未进入可求值条件语言(F18)、卡片适用条件不参与运行内逐项判定(F19);
- 界面证据明确标注为"源码守卫 + 生产构建 + 代码走查",不是端到端点击证明。

验证:`test-evidence/20261001-003148-2e7e194/`(verify.py 12/12 PASS,全量 567 项)。
15 §7 交接同步更新:新增 F17/F18/F19,F13 标记为已由第一批关闭,F6 更新为 Q3–Q5。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 00:33:50 +08:00
qiaoqichaoandClaude Code 2e7e19471c 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>
2026-10-01 00:31:42 +08:00
qiaoqichaoandClaude Code 350146d9bc docs(v2): 更正第一批记录中模型失败的错误归因
原记录归因于"演示项目缺 financial.operating_cashflow 导致模型引用未知字段",
与代码不符:已定义但本次无值的字段仍会建键(apply_candidate 无条件建键),
不会触发该守卫,补该字段因此不可能修好它。

更正为字段表三处缺陷(方法文档 inputs 超出字段表、守卫比对错集合、未下发字段清单),
并补记实测结果、证据路径,以及一项未修复的完整性漏报(skill-quality 只遍历已存在值的字段)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 17:38:35 +08:00
qiaoqichaoandClaude Code 4df80c0053 fix(v2): 修复预审模型字段表三处缺陷并留出工具预算余量
- 补 8 个标准字段(还款来源/涉诉/增信/保证金/保险/客户名称),对齐原生方法文档声明的 inputs
- 字段守卫改为比对标准字段表,不再把"标准字段但本次无数据"误判为未知字段
- 向模型下发 standard_fields 并在提示词约束字段名,避免自造派生指标
- 补 insurance./deposit. 维度前缀;方案预算 12→18、120s→180s,版本升 1.1.0

实测(临时库 + DeepSeek):模型类技能由 failed 转为 partial(部分 unknown 属如实标注),
降级记录为空,工具调用 11 次。字段表三处为代码层改动,对既有库即时生效。
验证:scripts/verify.py 11/11 PASS,531 项单测。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 17:38:28 +08:00
qiaoqichaoandClaude Code 962d4250dd docs(v2): 第一批记录——材料确认走通、模型接通但预算不足
模型路径实测:字段守卫先拒绝了一次无依据引用(补齐演示项目缺失字段后消失),
随后工具调用超出方案冻结的 max_tool_calls=12 而终止,两次都如实记降级。
是否提高演示方案预算属产品决定,未擅自修改。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 13:23:45 +08:00
qiaoqichaoandClaude Code b666bc723d docs(v2): 交付记录改为实测推送状态(origin/main c5edb40)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 12:49:34 +08:00
qiaoqichaoandClaude Code c5edb400bc docs(v2): 交付记录补验证证据路径与推送受阻状态
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 12:37:53 +08:00
qiaoqichaoandClaude Code 9f3abbfaf5 docs(v2): 文档索引补 16 纠偏规格与 17 交付记录
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 12:35:14 +08:00
qiaoqichaoandClaude Code 02289661a8 feat(v2): 纠偏第一批——执行链产出新版预审记录(真实运行验收)
覆盖 AC-46/47/48/49(BR-45/46/47、E-27)。审计确认的 P1 缺口"正常发起评审不产生
新版预审记录"由此关闭:视图由执行链出口产生,不再依赖测试或脚本注入。

后端:
- services/prescreen.py:新增 screening_from_run(),把一次真实运行的执行结果装配成
  预审视图;维度与阶段按**本次实际执行的组件与核查项**投影
  (dimensions_and_evidence:冻结方案声明过、且本次真的执行过的技能/规则才算维度;
  经验核查等方案外伪步骤不算;阶段只表达证据成熟度,不看结论好坏)。
- services/assistant_worker.py:运行出口(含失败路径)统一调用 save_prescreen_view(),
  运行结束即落库视图;装配失败单独记事件,不让运行一起丢。
- contracts/prescreen.py:视图带 evidence(界面"查看依据"的来源实体);
  新增运行级错误码 RUN_STEP_FAILED(E-27)。
- 维度状态用本次执行的步骤与核查项算(含跑通但无问题的项),
  只看待办 finding 会把通过的维度误判成未核查。

前端:面板新增"核查结果"区(每条可打开依据抽屉,显示来源、定位、原文片段与组件版本)
与降级记录展示;没有证据时明确写"按缺证处理",不编造。

测试:backend/test_prescreen_from_run.py 12 项,用真实 enqueue + DurableWorker.process_next
(临时库)断言视图由执行链产生、失败与模型不可用如实留痕、重跑新增记录。
含反例:执行前不得存在任何记录。

实际验收(浏览器渲染 + 真实运行):状态 partial、10 维(5 已核查/2 待核实/3 阻断)、
4 条核查结果、14 条证据、1 条 RUN_STEP_FAILED 未完成项;记录见
docs/v2/17-batch-delivery-records.md(含剩余缺口:界面点击未自动化、材料确认未在浏览器走完、
演示角色需 XINGBANG_DEMO_ROLE_LOGIN=1、模型未配置)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 12:34:45 +08:00
qiaoqichaoandClaude Code f38959b483 docs(v2): 新增交付纠偏规格,T05–T11 改按部分完成记
依据 test-evidence/20260930-v2-audit 的审计结论:底层能力存在但产品闭环未接通。
16-delivery-corrections.md 定义交付口径、四项禁止的假接通方式、BR-45~51、
E-27/28、AC-46~57 四批验收;15-development-handoff.md §7 同步修正判定口径。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 12:32:30 +08:00
qiaoqichaoandClaude Code f1187218ca fix(v2): 修复沙盘面板在真渲染下暴露的三处缺陷(浏览器实测)
这些缺陷源码守卫与构建都查不出,只有真正渲染才暴露(正是 F11 要防的情况):

1. 雷达图没有尺寸约束:<svg> 只有 viewBox,撑满整个容器(实测约 1000px 高),
   且轴上没有维度标签。现按仓库既有约定给显式 width/height 并补轴标签。
2. 首屏不显示演示值:真实运行视图按 AC-30 不携带演示估计,导致首屏显示
   "暂不显示",与 13 §7「首屏并列概率(演示值)+ 主审意见」不一致。
   现载入演示域运行后取一次基线情景(空选择 → 服务端演示表条目 00),
   production 域不请求演示表。
3. 未勾选任何假设时也画出实线情景轮廓(等于把基线复制成"所选情景");
   现只在存在被假设的维度时画实线。另外维度阶段补上序号,便于对照图例。

守卫脚本相应补 4 条断言(显式尺寸、轴标签、基线虚线、无勾选不画实线),
并修正被本次改动影响的旧断言。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 10:59:27 +08:00
qiaoqichaoandClaude Code dbd6fee2e6 docs(v2): 记录首次推送 origin/main 与 OQ-06 Q2 远程归属定案
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 10:36:12 +08:00
qiaoqichaoandClaude Code b6f1e80c5d docs(v2): 更新第7节交接记录至 T11 完成状态
记录 T08–T11 的提交、517+ 项的测试规模、AC 覆盖对照与 9 项未决项
(含运行写入方缺位、轨迹产出方缺位、publisher 未接线三项本轮新发现的缺口)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 09:25:42 +08:00
qiaoqichaoandClaude Code d6bc8485f5 feat(v2): T11 改进治理与演示交付——对照门禁、泄漏作废、三模块演示脚本
覆盖 AC-15/16/34/37/41(BR-15/16/40、E-11/24)。

后端:
- contracts/improvement.py:ImprovementCandidate + ContrastReport/ContrastMetrics。
  零分母不得给比率或覆盖率(样本不足不是 0%);非独立评测不得给改进/退化结论;
  已发布必须引用既有不可变版本;没有对照证据不得进入待审核或已发布。
- services/improvements.py:
  · evaluate_contrast 在服务端判定泄漏——预测锁定前读到标签即整次评测作废(E-11),
    保留集来源进开发集的样本作废并单列,指标按分子/可观察分母/覆盖率/未观察分开报;
  · transition 状态机:draft→evaluating→ready→in_review→approved→released,
    自批拒绝、退化与结论不明拒绝发布、发布幂等且只引用既有版本、撤回只影响新运行。
- api/prescreen.py:候选列表、提出与状态机三个端点;评测请求体提交样本,
  泄漏与指标一律由服务端计算,不接受客户端交来的"成品报告"。
- contracts/prescreen.py:补 E-11/E-24 错误码与 409 映射。

前端一致性修正:
- src/lib/prescreen-run.ts 的呈现判定改用后端既有词汇
  (empty/list/grouped/radar/faceted,与 services/review_plan.presentation 一致),
  避免前后端各一套判定导致界面画出后端判定为不该画雷达的图。

演示交付:
- scripts/xingbang_prescreen_demo.py:按 08 §7 八步演示,只驱动已实现入口,
  未实现的步骤(批量清单、历史提炼、卡片治理)如实标注原因;
  工程演示与模型效果分列,本地专项/Jev/真实概率一律标未验证或未接通。
- backend/test_demo_script.py:冒烟断言八步状态、未实现原因与分列口径。

验证:backend 全量 unittest 519 项 OK;前端 npm run build 通过。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 09:25:25 +08:00
qiaoqichaoandClaude Code f2bbac03e7 feat(v2): T10 轨迹回放与会议结果复盘——只读轨迹、unmatched 单列、更正追加
覆盖 AC-22/32/33(BR-13/21/31/32、E-05/23/26)。

后端:
- contracts/trajectory.py:TrajectoryStep 与 ReviewOutcome。
  TrajectoryStep 失败必有错误码、成本未知时币种留空、observable() 给出
  可读字段白名单(机器可读地排除任何推理过程字段);
  ReviewOutcome 只在 matched 且有明确映射口径时才有二元标签,附条件/撤回/
  未送审一律留空,unmatched 不得挂快照。
- services/trajectory.py:
  · project_steps 把既有 run 的步骤投影成轨迹(顺序即 sequence,部分完成
    如实标注,失败保留,成本缺省留空不填 0);
  · replay 只读回放并按 sequence 稳定分页,不存在或跨项目抛 KeyError;
  · record 追加会议结果:未知快照记 unmatched,更正要指向本项目既有记录,
    链必须能终止;denominator 只数 matched 且有通过/否决口径的记录。
- api/prescreen.py:新增轨迹回放、会议结果列表与追加三个端点。

未做:轨迹写入仍由既有 DurableWorker.save_step 负责(本批不重做运行执行),
因此目前没有 judgment/rule 类步骤的产出方;会议标签映射(E-26)仍属 T11。

验证:backend 全量 unittest 494 项 OK(T09 时 469 项,无回归)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 09:19:33 +08:00
qiaoqichaoandClaude Code 22f8a37799 feat(v2): T09 预审与推进沙盘——运行只读视图、演示情景与界面守卫
覆盖 AC-11/12/29/30/31/42/44(BR-11/29/30/41/43、E-20/21/22)。

后端:
- contracts/simulation.py:Simulation/SimulationAssumption/ScenarioDimensionState。
  契约层直接禁止 production 域携带演示估计(E-21);ready 必须有结果、
  failed 必须带错误码且不得显示结果、计算中不得预告乐观增幅。
- services/prescreen_sandbox.py:演示情景表(DEMO-TABLE-v1)与推演入口。
  组合查表不是单项加和(assert_not_additive 把这条写成可执行断言);
  只改被假设的维度,其余维度原样保留;失败保留基线并标未完成。
- services/prescreen_store.py:运行视图只读存储,复用 assistant_objects 新 kind
  prescreen_run,不新建表;只提供保存与读取,要改结果必须产生新修订。
- api/prescreen.py:新增 3 个只读端点(运行列表、运行视图、可用假设动作)
  与 1 个情景端点;请求体里没有任何概率字段。越域返回 E-21、冲突假设 E-22、
  过期修订 409。
- contracts/prescreen.py:补 E-20/21/22 三个错误码与其 HTTP 映射。

前端(挂进既有工作台「材料与问题」页,不新建路由、不新增样式表):
- src/lib/prescreen-run.ts:客户端契约、呈现判定(同刻度 3–8 维才画雷达)、
  演示值域判定、来源与数据域徽标(文字+图标+样式,去色仍可区分)。
- src/components/xingbang/PrescreenPanel.tsx:主审意见、演示值(紧邻固定说明)、
  维度雷达与等价文字列表、维度依据抽屉、假设勾选即时推演。
  旧请求晚到或结果与当前选择不一致即丢弃;请求失败保留基线并标未完成。
- scripts/test_prescreen_ui.cjs:界面源码守卫,已注册进 scripts/verify.py。

未做:运行装配结果的写入方仍是执行链路(T10 范围),当前由测试写入;
沙盘尚未接入真实执行,界面数值全部为服务端演示表值。

验证:backend 全量 unittest 469 项 OK;前端 npm run build 通过。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 09:15:57 +08:00
qiaoqichaoandClaude Code 501a4d9c9b feat(v2): T08 专项离线质检——统一适配 fixture、逐任务准入与预算守卫
覆盖 AC-16/17/18/19/20/38/39/40/41(BR-17/18/19/20/37/38/39、E-10/13/14/15/25)。

新增:
- backend/contracts/judgment.py:JudgeProfile/TaskValidation 契约(逐任务逐用途
  验收登记 + 冻结 checkpoint)。放在独立契约模块,因为规格要求的 tokenizer/预算
  字段会撞上 prescreen.py 既有的"契约层不得出现凭据字样"静态守卫;不放宽该守卫。
- backend/services/judgment_adapters.py:统一适配入口。准入(未登记任务/用途拒绝、
  runtime 须独立评测)、冻结权重(unresolved 与不一致均拒绝)、上下文预算
  (正文与选项分开计,超限返回 E-25 且零发送)、中文否定/条件例外/来源矛盾/未登记
  映射一律落 unknown(inconclusive),不硬选正面结果。
- backend/fixtures/judgment/:中文提炼依据题集、本地模型原始输出、Jev 厂商响应
  fixture(虚构内容,离线契约用)。
- backend/test_judgment_adapters.py:30 项测试。

修改(最小面):
- contracts/prescreen.py:新增 E-25 运行级错误码 JUDGMENT_CONTEXT_EXCEEDED;
  Judgment 增 actual_checkpoint_ref、JudgmentConfig 增 checkpoint_ref。
- services/judgment_provider.py:映射适配层的策略拒绝异常;归一化保留实际权重。

未做(受授权限制):没有 Jev 凭据与 Laya 权重,因此只交付离线 fixture 路径,
live 传输层仅留注入点,未接入硬件与端口探测。fixture 通过不证明中文效果合格。

验证:backend 全量 unittest 440 项 OK(原 410 项无回归)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-30 09:09:05 +08:00
qiaoqichao 31663cafb7 docs(v2): 更新第7节交接记录至 T07 完成状态
记录 T00–T07 提交清单、410 项测试规模、T07 卡片验收对照;
新增未决项 F12(主审模型编排冻结口径未统一)与 run_instruction 服务端实现待补;
下一任务指向 T08,并注明其本地服务部分依赖硬件/权重、未获授权前需保持 disabled。
2026-09-29 20:38:13 +08:00
qiaoqichaoandClaude Code bd389ebd31 feat(v2): T07-c 预审运行装配与运行级集成,T07 收尾
T07 第三块。ScreeningRun 是**既有 run 对象的受约束投影**,不是第二份运行存储;
AC-13/14 由既有 enqueue 实现,本批只验证其成立、不重做。

新增契约:Degradation、DimensionResult、ProbabilityView、ScreeningRun。
契约层的硬约束:`probability` 与 `probability_view.real_estimate` 的类型就是
`None`,传任何数值都被 pydantic 拒绝——"未校准就没有概率"不靠自觉;
演示估计必须标 synthetic_demo 且带"人工设定"说明、取值 0–1。

新增 services/prescreen.py:
- assemble():把冻结方案、政策结论、降级与维度状态收成契约合法的运行视图
- versions_block():冻结 plan_hash 与各组件版本;题库与主审模型未接入时**留空**,
  不编造版本号
- dimension_results():维度状态由本次核查结果推出
- assert_versions_frozen():未冻结方案版本或专项修订的运行不得执行

**实现中被测试抓到一个真实错误**:初版把"被引用组件未报告结果"当作已核查
(状态 checked)。这是把静默当成通过,违背 BR-07。现改为:任一被引用组件没有
结果即 unknown;issue 优先于 unknown(具体阻断比信息缺失更该被看到)。

测试:新增 test_prescreen_run.py 20 项,其中 4 项直接验证既有 enqueue 的
AC-13(新证据→新快照+新运行、旧运行留存、旧 revision 冲突)与 AC-14(同键同载荷
返回同一运行、异载荷 409)。全量 410 项 OK(390 → 410);verify.py 10/10 PASS。

T07 三块完成,卡片验收对照:AC-05/06/07/12/45(T07-a)· AC-09/10/21(T07-b)·
AC-13/14 验证(T07-c)。AC-08 的跨项目引用拒绝已在 T03 覆盖。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 20:38:02 +08:00
qiaoqichaoandClaude Code 27d57c9227 feat(v2): T07-b 专项 disabled 路径与工具策略守卫
T07 第二块。本批**只做 disabled 路径**(T07 卡片要求"先 disabled 专项路径"),
真正的 Jev/本地适配器属 T08,不预造。

新增契约:JudgmentAnswer(可辨识联合,score 必须有限数值)、NativeMetric、
Judgment、JudgmentConfig。契约层硬约束:disabled 不得产出 completed;
关闭专项必须记录原因且不得冻结任何配置修订。

ErrorCode 补齐 E-06/E-13/E-14/E-15/E-08/E-10,并**区分两类编码**:
- 请求级(有 HTTP 语义,进 S1_ERROR_HTTP):含新增 JUDGMENT_CONFIG_INVALID 422、
  EGRESS_NOT_APPROVED 403
- 运行级(RUN_LEVEL_CODES,只出现在运行体 degradations/judgment 里):
  JUDGMENT_UNAVAILABLE / CAPABILITY_UNSUPPORTED / OUTPUT_INVALID / RUN_BUDGET_EXCEEDED
不再把假的 HTTP 200 塞进错误映射;两者互斥且并集等于枚举,有测试锁定。

新增 services/judgment_provider.py:
- resolve_config():关闭时记原因、不冻结配置;开关 false 却传 ID 属 E-07;
  无可用配置时明确报 E-13 而非悄悄关闭;未验证/提供方不符均拒绝
- judge():disabled → skipped+disabled;缺证**不发起调用**直接 completed+unknown;
  超时/异常 → failed+E-06;题型不符 → skipped+unsupported(E-14);
  题型对但内容非法 → failed+E-15。失败一律 answer 为空,**不补默认分值**
- allowed_tools():工具 = Skill 声明 ∩ 注册表白名单,**取交不取并**;材料正文里
  写什么都无法扩展权限(AC-10,有反例测试)

测试:新增 test_judgment_provider.py 22 项。全量 390 项 OK(368 → 390);
verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 20:33:36 +08:00
qiaoqichaoandClaude Code b5feee6982 feat(v2): T07-a 预审结果约束与结论校验
T07 是"预审执行"大卡,按纪律拆子卡。本批为第一块:纯确定性的结论校验,
不调用任何模型、不计算概率。覆盖 AC-05/06/07/09/12/45 与 BR-05/06/07/12。

新增 services/prescreen_policy.py:
- decide():四级优先(hard_block → critical_incomplete → open_findings → clean),
  优先级顺序即业务口径,改动等于改结论,已显式标注
- **硬性阻断不可覆盖**:命中 hard 规则即 stop,并指出规则版本、保留模型原始
  结构化提案供审计;专项模型的正面单题判断不能翻盘(有专门反例)
- **未知不等于风险也不等于通过**:关键核查不可完成给 insufficient_information
  并列出未完成项,findings 的 result 原样保留、**不得被改写成 issue**
- **没有 second path 给概率**:probability() 不接受任何入参,模型分数无法顺手传入;
  native_metrics 里名为 probability 的指标会被 assert_no_probability_leak 拦下,
  self_reported 置信度可入档但不得变概率
- stop 明确不触碰正式审批(AC-45),预算耗尽按 E-08 列未完成项而非伪造完成

实现中修正了两处自己的测试写法:断言"不含高风险三字"会被免责说明本身命中;
断言 open_findings 为空与"unknown 属待处理"的定义矛盾。两处都改成检验真正的
不变量(结论非风险判定 + findings 不被改写)。

测试:新增 test_prescreen_policy.py 19 项。全量 368 项 OK(349 → 368);
verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 20:28:45 +08:00
qiaoqichao d9d686bf62 docs(v2): 更新第7节交接记录至 T06 完成状态
按开发纪律在每张卡收尾更新交接记录:记录 T00–T06 提交清单、349 项测试规模、
未决项(F8/F11/F7/F6)与下一任务 T07;并声明本轮未推送远程。
2026-09-29 20:24:39 +08:00
qiaoqichaoandClaude Code 1bc17bb9bc feat(v2): T06-c 方案治理入口与 Tools 卡守卫,T06 收尾
T06 第三块,收尾。方案提案复用既有组件治理(registry.draft/release),
不新建发布路径;自批拒绝等既有保证有测试锁定。

- propose_plan():维度在提案时即去重与冲突拦截(T06-a 的解析前移),
  保证草稿阶段就挡住"同 ID 不同定义"
- **不得出现业务 Tools 卡**(ADR-11):方案自带 tools/tool_cards/
  allowed_tools/permissions 一律拒绝,否则业务侧可绕过工具白名单;
  工具只能由后台治理
- validate_critical_checks():关键核查项必须真由本方案的 Skill/规则产生,
  凭空声明的"关键项"会让 BR-06 的硬性阻断语义失去可追溯性

T06 三块完成,卡片验收对照:AC-28(装配与依赖拒绝)· AC-29(维度去重与刻度
冲突)· AC-44(0/2/6/9 维与异刻度的呈现判定)均有测试;"没有 Tools 卡" 有守卫。

测试:test_review_plan.py 增至 34 项。全量 349 项 OK(340 → 349);
verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 20:24:24 +08:00
qiaoqichaoandClaude Code 8a9005036c feat(v2): T06-b 方案装配与依赖预检(可定位的 E-19 文案)
T06 第二块。核对后确认 component_registry.freeze() 已实现大部分 AC-28:
按 release 指针解析依赖、原生方法文本装配时固化、循环依赖与输出冲突检查、
数据域一致性("演示与正式组件不能混用")、content_hash。因此本批**不重复实现冻结**,
只补真正的缺口。

新增 contracts:JudgmentBinding、ReviewPlan(含维度、关键核查项、专项绑定)。

新增 review_plan.check_dependencies() / assemble():
- **缺口**:未发布/已撤回的依赖原先抛裸 KeyError,被 translate() 映射成 404
  "对象不存在",用户无法定位是哪一项。现改为逐个检查并**指明依赖名与原因**
  ("尚未发布或已撤回"/"版本状态为 X"/"发布指针指向的版本不存在")
- 只用 release 指针判定可用性——草稿与已撤回天然没有指针,这正是 BR-27
  "草稿或已撤回组件不得进入新运行"的机械表达
- 装配时接入 T06-a 的维度解析与呈现判定,并做不丢失断言

测试:test_review_plan.py 增至 25 项(新增 7 项装配)。其中版本换版后
content_hash 必须变化,用于证明版本确实被冻结进结果而不是每次重解析。
全量 340 项 OK(333 → 340);verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 20:20:58 +08:00
qiaoqichaoandClaude Code 019d5081df feat(v2): T06-a 方案维度解析(去重、刻度冲突、呈现判定)
T06 是大卡,按纪律拆子卡。本批为第一块:维度契约与解析。

新增 contracts:ScaleLevel、DimensionSpec。刻度层级必须升序且取值唯一
(乱序会让展示语义倒置);同 ID 必须标签/量纲/刻度层级完全一致。

新增 services/review_plan.py:
- resolve_dimensions():按 dimension_id 合并;**同 ID 不同定义直接报冲突并拒绝**,
  不让程序或模型临时挑一个(BR-28 / E-20);相同定义只留一份并合并组件引用,
  避免重复计数
- presentation():AC-44 的呈现判定——0 维 empty / 2 维 list / 3–8 同刻度 radar /
  9 维 grouped / 异刻度 faceted;硬阻断**单列**且永不进雷达面积
- assert_nothing_dropped():三组并集必须等于全部维度,"不默默丢失关键项" 有守卫
  且守卫自身有测试证明会报错

刻度改版(同 scale_id 不同 version)视为不同定义——语义可能已变,不得共用雷达。

未完成:T06-b 方案装配与依赖冻结(AC-28)、T06-c 维度在结果中的落位属后续子卡。

测试:新增 test_review_plan.py 18 项(去重 8 + 呈现 10)。全量 333 项 OK(315 → 333);
verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 20:16:39 +08:00
qiaoqichaoandClaude Code d18c147076 feat(v2): T05-c 运行补充说明只能形成草稿(AC-26)
运行时的"本次预审补充说明"只影响本次运行(run_instruction 落在运行对象上,
属 T07 的 ScreeningRun 字段)。要变成持久知识只有一条路:显式提议为草稿,
且走正常审核。本批实现卡片侧的那一半。

新增 knowledge_cards.draft_from_run_instruction(),三条约束:
1. 只产草稿——运行中说过的话绝不直接生效(有测试断言无已发布版本产生)
2. **不得携带工具/权限/引擎字段**:allowed_tools / tools / permissions / engine /
   run_instruction 出现即拒,扩大工具授权必须走独立提议与审核
3. 记录 derived_from_run,便于回溯知识来自哪次运行
另:运行指令不能声明为 history_derived(历史提炼须提供来源事件或证据),
hard 门禁对运行衍生的卡片同样生效。

未完成:运行对象上的 run_instruction 字段与"只影响本次运行"的服务端实现属 T07,
本批只交付卡片侧,不宣称 AC-26 已整体闭环。

测试:test_knowledge_cards.py 增至 25 项(新增 5 项)。
全量 315 项 OK(310 → 315);verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:51:12 +08:00
qiaoqichaoandClaude Code f8c4ba9e1d feat(v2): T05-b 知识卡片与硬规则依据门禁
T05 第二步:候选与治理。设计明令"复用卡片治理、不新建第二套发布库",
故本模块**只做投影**,状态机与发布完全委托 component_registry。

新增 contracts:Origin / GovernanceStatus / RuleEffect / Condition /
RuleContent / KnowledgeCard。Condition 只允许字段+有限算子,**不执行表达式**。
RuleContent 在契约层就要求 hard 必须带 policy_ref 或 authorization_ref 且附依据证据。

新增 services/knowledge_cards.py:
- propose():投影字段(origin/谱系/范围/条件)后委托 registry.draft(),**只产草稿**
- publish():发布时**再查一次** hard 门禁——草稿可能在提议后被改,不能只信提议时的校验
- effective():按数据域/有效期/范围过滤已发布版本(BR-04)

既有治理的保证原样生效,有测试锁定:自批被 release() 拒绝、无评测不能发布、
已发布需新版本号、提议不产生已发布版本。

三处必须点明的边界与映射:
1. **同键不同义**:本设计的 data_domain ↔ 注册表的 scope(demo/production),
   而本设计的 scope 是 project/team。投影层显式互换并存为 card_scope,绝不混用;
   调用方私传 data_domain 会被拒
2. **条件形状不同**:注册表条件是 {code,field,operator,threshold,title,suggestion},
   本设计是 {field,operator,value}。做**翻译**而非强加;算子只映射注册表实际
   会产出的 5 个(gt/lt/eq/gte/lte),出现其它取值即报错而非当作已支持
3. **内置种子组件是全局的**,没有 project_id/edited_by,**不是项目知识卡片**。
   投影时明确报错,避免把内置 Skill 误当项目卡片

测试:新增 test_knowledge_cards.py 20 项(门禁 6 + 来源谱系 6 + 治理复用 5 + 有效过滤 3)。
全量 310 项 OK(290 → 310);verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:47:59 +08:00
qiaoqichaoandClaude Code 04ef3972a8 feat(v2): T05-a 历史过程时间线(缺时间不编造)
T05 卡片要求"先 timeline,再候选,再编辑/测试/审核"。本批是第一步。

新增 contracts:DecisionEvent(区分 occurred_at 与 recorded_at)、CaseTimeline。
新增 services/history_cases.py:确定性提炼,无模型调用。

两条硬规则的实现:
- **不编造发生时间**(BR-02):occurred_at 只取材料里记载的日期;缺失/占位值
  ("-"、"缺失"、"未知")或无法解析时保持 None 并给缺证提示。recorded_at 必填,
  但它**不表示发生时间**——有测试断言二者不相等
- **不编造经过**(14 §4):只有最终报告或非结构化材料时产出 **0 个事件** 并标
  `partial` + "过程材料不完整",绝不生成虚构的问询顺序

其它:列名靠别名表识别,**未识别的列忽略而非猜测**;未声明事件类型时保守记为
question 而不丢弃该行;事件携带行级 evidence_id 以便回溯原文定位;同项目重复提炼
是同一对象 revision 递增(03 §4);缺日期事件排序时置于末尾,不被打乱成"近期"。

实现中修掉一处自己的问题:build() 初版调了两次 store.put(首次建库 revision 会变 2),
且校验发生在落库之后——非法时间线本可能入库。现改为先校验再单次 put。

测试:新增 test_history_cases.py 18 项(不编造 6 + 提炼 6 + 隔离与版本 6),
含"缺日期为 None 且不等于导入时间""只有最终报告不得生成时间线"等反例。
全量 290 项 OK(272 → 290);verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:41:50 +08:00
qiaoqichaoandClaude Code 8fef00d268 feat(v2): T04 模拟案例生成与数据集划分
先边界 fixture 再批量生成;全程程序组合场景,**不做任何模型调用**(14 §8 末)。

新增 services/simulation_dataset.py:
- generate(seed, scale):程序化生成虚构项目,同 seed 同版本**逐条一致**
- split():按关联组 + 时间分桶(组内不拆),以组的最早发生时间排序
- assert_group_integrity / assert_source_allowed:组不跨集合;保留集来源禁止用于提炼
- manifest():构造 DatasetManifest 契约体

契约补 T04 才该有的部分(T00/04 当初有意推迟):EventOutcome 七值枚举、
OutcomeCount、DatasetManifest。含两条硬约束——合成数据必须 demo 域(BR-34)、
计数不得为 0(空结果用不适用表达)。

配比按 14 §8:通过 1800(直接 900 + 补件后 900)/ 未通过 600 / 不计入 600
(附条件 100 + 未送审 175 + 退出 175 + 待定 150)= 3000。
两个建模决定:
- "补件后通过"是 approved 的**子类型**(outcome_subtype),不是独立 outcome ——
  06 §3 要求区分首次提交与补件后,但设计 §9.1 的 EventOutcome 只有 7 个值,不自扩充
- conditional 是否计入目标由客户映射决定(OQ-05),故 label=None,绝不默认当通过

实现中被自己的检查抓到两个 bug:
1. 分组与近重复用了两套独立公式,导致 near_duplicate_of 指向别组记录,
   assert_group_integrity 直接报"近重复案例跨集合"。现组号与近重复由同一序号唯一推出
2. split() 末段取剩余可能为负(极端小样本),会静默切出错误的划分。已夹到非负

测试:新增 test_simulation_dataset.py 24 项(边界 fixture 10 + 生成 10 + 清单 4 +
落盘 2),含 AC-35 的可复现性与 AC-36 的组不跨集合/保留集来源拒绝。
全量 272 项 OK(248 → 272);verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:30:34 +08:00
qiaoqichaoandClaude Code 669e969c41 feat(v2): T03 来源定位接上契约,并锁定跨项目引用拒绝
T03 卡的要求是"复用上传/确认入口,增加导入清单、定位和冲突候选"。核对后:
导入清单与冲突候选已由 T02/S1 交付,但**"定位"只定义了契约、没有接上**——
parse() 仍只产出自由字符串 locator,SourceLocator 类型化投影是空的。
本次补上这条链路(契约与实现不一致是我的遗留)。

- assistant_materials.parse():每条 chunk 增加 source_locator(kind + 坐标),
  按 T00/04 §5.3 的映射:pdf→page、xlsx 单元格/行与 csv/txt/docx 表格→sheet+cell_range、
  docx 正文段→manual(note)
- material() 补 document_id/document_version 后**按契约校验**;漏了定位或定位不合法
  直接抛错,不落半成品进库
- **locator 自由字符串保留**:enqueue() 依赖它算证据 ID 的稳定哈希,改它会破坏 BR-13

实现中修掉一个自己引入的 bug:类型化定位的辅助函数初版命名为 table,与 docx 分支里
的表格计数器 table 同名,该分支内 helper 被整数遮蔽('int' object is not callable)。
已改名 sheet_loc。

AC-08 补测:跨项目候选引用被 supplement 拒("不属于项目"),同项目可用作对照,
未知 candidate_id 同样被拒。既有 test_project_assistant 只覆盖了跨项目文档下载。

测试:新增 test_sourcelocator.py 13 项,含真实 XLSX/DOCX fixture(zipfile 构造),
覆盖五种格式的定位派生与契约校验。全量 248 项 OK(235 → 248);verify.py 10/10 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:21:51 +08:00
qiaoqichaoandClaude Code 985e2f6a53 feat(v2): S1d 最薄界面——工作台内的材料集合导入面板
T02 收尾子卡。挂在既有 /xingbang-workbench「材料与问题」页内,**不新建路由**,
复用 workspace.css 既有 class(无新增样式表)。

- src/components/xingbang/ImportBatchPanel.tsx:登记清单 → 逐项上传 → 重试/取消 →
  冲突并列展示与裁定。浏览器端用 crypto.subtle 算 sha256 生成清单(服务端仍重算核对)
- src/lib/prescreen.ts:错误信封解包 + 契约类型(**手工对齐**,OpenAPI→TS 生成链
  未建设,已在文件头标注为临时)+ 服务端状态标签
- page.tsx 仅三处小改:导入面板、挂载面板、request() 改用 messageOf
  (兼容信封与既有 detail 的 string/array/object 三种形态,不丢既有信息量)

面向用户的诚实性约束(有源码守卫锁定):明确写出"未上传或未确认的文件不会进入
项目事实""不会按上传先后覆盖""不会自动挑一个";空批次用既有空状态,不绘制虚构行;
面板不含任何审批概率。

验证:
- npx tsc --noEmit 通过;npm run build 通过
- 新增 scripts/test_prescreen_panel.cjs(10 条源码守卫),已加入 verify.py 用例
- scripts/verify.py 10/10 PASS(exit 0)

**未验证**:面板未经浏览器端到端验证。它依赖客户端数据加载,SSR HTML 不含它,
且本项目没有浏览器自动化依赖。目前只有类型检查、构建与源码断言三层证据。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 18:14:14 +08:00
qiaoqichaoandClaude Code ff7894ae1f feat(v2): S1c′ 既有上传入口的批量摄取——S1 首次端到端闭环
T00/04 §4.2 要求的"既有材料上传入口扩展":**不建立平行上传 API**。
POST /documents 增加可选 batch_id / item_id 表单字段;不传时行为完全不变。

- api/prescreen.ingest_into_batch:清单核对 + 状态回写,仍走既有
  ProjectAssistantService.upload(),故解析、同哈希复用原件、pending_candidates、
  data_revision、mark_stale 等既有行为一字未改
- 服务端**重算** sha256 与大小,不信任客户端清单;不符则条目 failed + 422
- 返回体保持 **document 形状**(既有前端读 body.id / body.candidates),
  批次状态作为附加字段 import_batch 给出
- 拒绝重复摄入已解析条目(409)、已取消批次(409)、不在清单中的文件(404)

闭环已成立:登记批次 → 上传 → 解析定位 → 冲突检测 → 人工裁定 → 进事实。

测试:test_prescreen_api.py 新增 BatchIngestTests 10 项(含闭环与既有路径回归)。
全量 235 项 OK(225 → 235);scripts/verify.py 9/9 PASS。
真实 app 冒烟 claude_use/T02/smoke_s1.py 15/15 PASS。

**测试隔离缺陷已修**:BatchIngestTests 初版只 patch 了 prescreen 的 service 工厂,
未 patch api.project_assistant.service,导致不传 batch_id 的上传落到**真实 v2 数据库**。
已补 patch,并清空 v2 数据根从干净状态重跑验证。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 17:43:57 +08:00
qiaoqichaoandClaude Code fcf4d8c948 feat(v2): S1 接口层——材料导入与事实冲突的 8 个端点
T02 第三个子卡。命名空间按 T00/04 §1 定案 P1 挂 project-assistant 之下,
复用现有鉴权与同源代理,鉴权/代理代码零改动。

新增 backend/api/prescreen.py(7 路径 / 8 操作)+ test_prescreen_api.py(27 项)。
app.py 仅新增 1 个 include_router 与 1 个异常处理器注册。

落实:
- 404 统一口径(03 §2):不存在与无访问权一律 404,不泄露对象存在性。
  既有 check_project 抛 403 且被 5 个模块共用,故不改它,由本模块 scope() 包装。
  实测:无权项目返回 404 NOT_FOUND 而非 403。
- 错误信封(D2):只在新路由输出 {error:{code,message,retryable,request_id}}。
- E-09 与 E-05 精确区分:新增 store.IdempotencyConflict,不再靠字符串比对猜码。
- 客户端清单只接受 4 个字段;id/status/received_at 由服务端生成——
  状态机写权不下放。manifest 校验因此从"整对象"改为"4 字段 + 服务端补全"。

**实测发现的缺口并已修复**:Input(extra="forbid") 的校验错误由 FastAPI 校验层在
进入端点前抛出,不经过 run(),导致同一命名空间出现两种错误形状。现注册
RequestValidationError 处理器,但**只在 prescreen 路径生效**,其它路径交回
FastAPI 默认实现——既有端点形状经实测确认未变(含校验错误的形状)。

验证:
- scripts/verify.py 9/9 PASS(exit 0);全量单测 225 项 OK(196 → 225)
- claude_use/T02/smoke_s1.py 在真实 app.py 上 10/10 PASS:覆盖路由注册、
  真实前缀下的 manager 鉴权放行、404 统一、信封形状、以及既有端点未被污染

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 16:45:07 +08:00
qiaoqichaoandClaude Code c59fff68d3 feat(v2): S1 存储层——材料导入批次与事实冲突检测
T02 第二个子卡。复用 assistant_objects(新 kind),**未新建表**;旧库结构不变。

新增服务:
- services/material_import.py 批次生命周期:create/load/listing/mark_item/
  retry/cancel;状态由逐项状态派生(ready/partial/failed/parsing)
- services/fact_conflict.py 冲突检测/阻断/裁定;FactConflictUnresolved(E-17)

解决的**真实缺口**(BR-23 / AC-24):既有 apply_candidate 对 values/facts 是
后写覆盖,sources 虽累积多来源但无人检测分歧、无人阻断。本层在**新路径**前置
检测:冲突时证据仍入 sources(BR-22 留痕)但值不采用(BR-23),已确认值不被覆盖。

增量改动(均为可加性,未改既有语义与调用方行为):
- assistant_store.py:新增 idempotent_lookup / idempotent_remember 共享 helper。
  既有 enqueue 与 create_report 的内联实现**未改写**。用 INSERT OR REPLACE 而非
  裸 INSERT:重试路径上裸 INSERT 会抛 sqlite3.IntegrityError(非 Conflict,
  translate() 无法映射为 409)。
- assistant_materials.apply_candidate 新增 adopt=True 形参。adopt=False 只记证据
  不改值;既有调用方不传参,行为完全不变(有回归测试)。

设计决定:
- T00/04 曾提 3 个 kind;实现时发现契约中 ImportItem 无 revision 且内嵌于批次,
  items 是值对象,故收敛为 2 个 kind(import_batch / fact_conflict)
- E-17 有两个面:确认动作被拒 = 422;运行级结果 = HTTP 200 且冲突存于
  degradations。契约映射与注释均已写明,并有测试锁定

测试:新增 test_prescreen_storage.py(33 项)。全量 196 项 OK(124 → 196)。
scripts/verify.py 9/9 PASS(exit 0)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 14:49:03 +08:00
qiaoqichaoandClaude Code d8a7d3858c feat(v2): 新增 S1 契约层(材料集合导入与事实确认)
T02 首个子卡 = S1 契约层。新增 backend/contracts/prescreen.py(设计指定的
唯一 owner),定义 SourceLocator / ImportItem / ImportBatch / FactConflict
与共用约束、错误码与错误信封。

落实的规格条目:
- BR-22 逐文件保留来源/定位/解析版本与状态
- BR-23 多来源冲突保留候选并要求显式处理(resolved 需说明+选择+人)
- AC-23 反例:绝对路径(C:/、/、//share)、上级引用(..)、超限、空集合、
  failed 缺 error_code、parsed 缺 document_id、parsed 带 error_code
- AC-24 反例:候选值全同不构成冲突;未知用 null 而非 0/空串;
  candidates 必须与 candidate_evidence_ids 同序同集合
- 01 §5 错误码与既有 translate() 的 HTTP 语义对齐;E-17 为运行级、HTTP 200
- 03 §9.1 时间必须带时区;禁止未知字段(E-07)

D3 定案(工程限制,非业务阈值):单文件 ≤10 MiB 沿用既有 LIMIT;单批
≤20 文件 / ≤20 MiB。依据 03 §1 末「管理员只能降低初期限制,放宽须重新验证」,
取保守方向即规格许可;放宽需另立验证。

依赖方向:contracts 不导入 services,标准字段白名单校验留在 service 层。

测试:新增 test_prescreen_contracts.py 38 项,全绿;scripts/verify.py 9/9 PASS。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 14:20:39 +08:00
qiaoqichaoandClaude Code 74430a3b4d fix(v2): 隔离 Compose 资源,使 v2 可与旧版同时运行
原抽取件沿用旧版的容器名/宿主端口/卷名,一旦启动会与旧版直接冲突,
故 v2 在改名完成前不可部署。本次仅改 v2,不触碰旧版。

- 项目名/容器名 mini-openclaw-stable → mini-openclaw-v2
- 宿主端口 3200/8002 → 3212/8012(容器内仍为 3000/8002,健康检查与
  RISK_AGENT_BACKEND_URL 都在容器内解析,故保持不变)
- 卷 xingbang-data/xingbang-logs → xingbang-v2-data/xingbang-v2-logs
- verify.py 的 docker 冒烟改为探测 3212/8012

backend/test_deployment_release.py 的 5 项断言**未修改**仍全绿:该测试锁定的是
aliyun compose 的回环端口行与 CHAT_THINKING_MODE,本次未改这两处。

验证:scripts/verify.py 9/9 PASS(exit 0)
未验证:docker 运行时冒烟(本机 Docker Desktop 未启动,守护进程不可达)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 14:16:51 +08:00
qiaoqichaoandClaude Code bf0549a4d3 fix(v2): 补齐 backend 单测依赖的两个 cjs 脚本
test_chat_repair.py:92 会调用 scripts/test_chat_stream.cjs,而该脚本不在
verify.py 的 9 个用例里,首轮抽取因此漏掉,导致 backend-unit 失败。
同时补上 test_resetdata_ui.cjs 使 cjs 测试集完整。

验证:scripts/verify.py 全部 9 项 PASS(backend-unit 124 tests OK)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 13:12:30 +08:00
qiaoqichaoandClaude Code d56c699ce6 chore(v2): 从兴邦预审v2白名单抽取独立可运行基座
按 docs/v2/05-implementation-plan.md §1 候选迁移表与 claude_use/T00 白名单,
从 55e2cdb 抽取 224 个文件(2.48 MB)到独立目录 F:/mini-OpenClaw-v2。

- 排除:凭据(.env/server-deploy.conf/旧DELIVERY.md)、运行数据(xingbang_data 等
  4 个 SQLite)、依赖(venv/node_modules 符号链接)、归档(_backup*/test-evidence/
  ori_file)、Office 临时文件
- 目标目录独立 git 仓库,初始恢复点;Gitea 远程与分支待 OQ-06 Q2 定案
- 未部署、未启动服务、未调用模型

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-29 12:58:26 +08:00