首次用真实 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>
389 lines
28 KiB
Markdown
389 lines
28 KiB
Markdown
# 四批交付记录
|
||
|
||
口径见 [16 交付纠偏规格](16-delivery-corrections.md) §4:每批必须列出**页面入口、操作步骤、
|
||
实际结果、证据位置、剩余缺口**;未接通项标"部分完成"。
|
||
|
||
---
|
||
|
||
## 第一批:接通正常预审执行链
|
||
|
||
状态:**部分完成**(执行链已接通并经真实运行验收;模型类技能已能跑完全程,见文末
|
||
「更正记录」;界面点击本身尚未由自动化驱动,材料确认步骤未在浏览器中完整走一遍)。
|
||
|
||
### 页面入口
|
||
|
||
| 入口 | 位置 |
|
||
|---|---|
|
||
| 发起预审 | `/xingbang-workbench?project=DEMO-B`「材料与问题」页 → 顶部"开始AI预审"按钮 |
|
||
| 查看结果与依据 | 同页「预审与推进沙盘」面板:主审意见、核查结果、核查维度(10)、每条"查看依据" |
|
||
|
||
### 操作步骤(实际执行)
|
||
|
||
1. 启动 v2:后端 `uvicorn app:app --port 8012`(带 `XINGBANG_DEMO_ROLE_LOGIN=1`)、
|
||
前端 `npm run dev -- -p 3212`。
|
||
2. 经前端代理发起预审(与页面按钮同一请求):
|
||
`POST /api/risk-agent/project-assistant/projects/DEMO-B/runs`,角色头 `manager`。
|
||
3. 等 worker 执行结束(轮询运行状态)。
|
||
4. 读取 `GET .../prescreen/projects/DEMO-B/runs/{run_id}`。
|
||
5. 浏览器打开工作台并渲染面板截图。
|
||
|
||
### 实际结果
|
||
|
||
- 运行结束状态 `partial`,视图 `recommendation=supplement`,`probability=null`。
|
||
- **维度 10 个**:5 已核查 / 2 待核实 / 3 存在阻断项;阶段 1–2
|
||
(`corporate.consistency`、`corporate.cashflow`、`corporate.assets`、`corporate.coverage`、
|
||
`skill-quality`、`skill-finance`、`skill-credit`、`demo.coverage`、`rules-corporate`、`corporate.analysis`)。
|
||
- **核查结果 4 条**(`lease.coverage.below_demo_threshold`、`lease.asset.duplicate`、
|
||
`financial.cashflow.missing`、`financial.liabilities.conflict`),各带依据与组件版本。
|
||
- **证据 14 条**随视图返回,界面"查看依据"可展开来源与定位。
|
||
- **未完成项 1 条**:`RUN_STEP_FAILED 金租对公业务综合核查:未配置受信模型,语义核查未执行`
|
||
——模型不可用时如实标未完成,不伪造结论。
|
||
- 缺证 2 项:`financial.operating_cashflow`、存在尚未人工确认的材料候选。
|
||
- 反复发起产生多条记录(本轮 3 条),旧记录仍可读;轨迹引用指向本次运行。
|
||
- 呈现判定:10 维超出雷达可读范围 → 界面改用分组列表并保留全部维度(AC-44 真实分支)。
|
||
|
||
### 证据位置
|
||
|
||
| 内容 | 位置 |
|
||
|---|---|
|
||
| 会话内验证日志 | 本轮运行输出(发起→轮询→读视图) |
|
||
| 端到端测试 | `backend/test_prescreen_from_run.py`(12 项,真实 enqueue + worker 执行) |
|
||
| 界面渲染 | `claude_use/tmp/v2-batch1-panel.png`(本机截图,未入库) |
|
||
| 全量验证 | `test-evidence/20260930-123451-0228966/`(`scripts/verify.py` 11/11 PASS,531 项单测) |
|
||
| 推送状态 | 已推送 `origin/main`:`f118721..c5edb40`;`git ls-remote origin main` 实测与本地 HEAD 一致 |
|
||
|
||
### 剩余缺口
|
||
|
||
- **界面点击未由自动化驱动**:本机无 playwright/puppeteer/chromium-cli,发起预审是通过
|
||
与页面按钮同一条代理请求完成的;"点按钮"这一步没有脚本化证据。
|
||
- **材料确认已走通(部分闭合)**:通过应用自己的入口补齐演示项目缺的字段——
|
||
`POST /documents` 上传按解析器键名书写的材料(`operating_cashflow: 1200`)→
|
||
项目待确认候选 → `POST /supplements` 带 `candidate_ids` 确认 →
|
||
`financial.operating_cashflow` 等 3 个字段生效(revision 5→6)。
|
||
**未闭合部分**:仍是接口调用而非浏览器点击。
|
||
- **演示角色需要 `XINGBANG_DEMO_ROLE_LOGIN=1`**:否则 worker 的 `authorized()` 会把
|
||
演示角色发起的运行判为"权限已撤销"(运行会失败但可读)。这是配置要求,需写入部署说明。
|
||
- **模型已接通并能跑完全程(2026-09-30 第二轮更正,见下方「更正记录」)**:配置 DeepSeek
|
||
(`XINGBANG_LOCAL_MODEL_*`)后,模型类技能 `corporate.analysis` 真实发起调用。
|
||
本轮首测仍报 `模型引用未知字段`——但**根因不是缺 `financial.operating_cashflow`**;
|
||
修复字段表三处缺陷后,模型跑完全程:工具调用 11 次 / 预算 18,降级记录为空。
|
||
- 取消中的运行不产出视图(只处理 completed/partial/failed)。
|
||
|
||
### 更正记录(2026-09-30 第二轮实测)
|
||
|
||
**更正**:本节原先记为"模型已接通,但预算不足",其归因有误。第二轮用真实模型复测后确认:
|
||
|
||
1. **`模型引用未知字段` 与缺 `financial.operating_cashflow` 无关。** "已定义但本次无值"的
|
||
字段,键仍然存在(`backend/services/assistant_materials.py` 的 `apply_candidate` 无条件建键),
|
||
不会触发该守卫;补这个字段因此不可能修好它。实测补件后(revision 2→4,缺证清零)报错照旧。
|
||
2. **真正被拒的是 `repayment.*`,进而是字段表的三处缺陷**:
|
||
- `backend/skills/financial-leasing-*/SKILL.md` 的 `inputs` 声明了 8 个 S1 标准字段表里
|
||
**不存在**的字段:还款来源、涉诉、增信、保证金、保险、客户名称;
|
||
- 字段守卫比对的是"当前恰好有值的字段",而非标准字段表,于是把"标准字段但本次无数据"
|
||
误判为未知字段——与提示词自身"缺失资料标 unknown"**自相矛盾**;
|
||
- 模型从未被告知允许使用的字段名,只能靠猜(实测先猜 `repayment.annual_amount`,
|
||
放开后改猜 `metrics.debt_ratio`)。
|
||
3. **工具预算不是约束**:跑通的那次实际只用了 **11 次**,原值 12 本就够用。
|
||
`max_tool_calls` 12→18、超时 120s→180s 保留作余量,但**不构成修复**。
|
||
|
||
**已修复(4 个文件)**:
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `backend/services/assistant_materials.py` | 补 8 个标准字段;`NUMERIC` 排除两个非数值字段;`legal.case_count` 加非负整数校验 |
|
||
| `backend/services/assistant_model.py` | 守卫改为比对标准字段表;向模型下发 `standard_fields`;提示词加字段约束;删除遮蔽模块级导入的局部导入 |
|
||
| `backend/services/project_assistant.py` | 补 `insurance.`→租赁物、`deposit.`→增信 维度前缀 |
|
||
| `backend/services/component_registry.py` | 方案预算与版本(`1.0.0`→`1.1.0`) |
|
||
|
||
字段表三处是代码层改动,**对既有数据库立即生效**;预算存放在冻结组件里,需走
|
||
`POST /components` 草稿 → publish 才对既有库生效。
|
||
|
||
**实测结果**(一次性临时库 + DeepSeek,演示库未改动):`corporate.analysis` 由 `failed`
|
||
变为 `partial`(部分结果为 `unknown`,属如实标注而非失败),降级记录为空,
|
||
核查结果 3 条 → 14 条。证据:`test-evidence/20260930-171301-962d425/`
|
||
(`scripts/verify.py` 11/11 PASS,531 项单测)。
|
||
|
||
**本轮新发现、尚未修复**:`skill-quality` 的完整性检查只遍历"已存在值的字段"
|
||
(`backend/services/skill_executor.py`),因此**从未提供过的字段永远不会被判为缺失**——
|
||
真实项目下"资料完整性"会漏报。建议单独立项,不并入本批。
|
||
|
||
---
|
||
|
||
## 运行环境配置(本地演示,2026-09-30 实测)
|
||
|
||
复现本记录需要以下环境变量。**密钥一律不入库、不写入任何文件**:本地演示用 shell 变量
|
||
展开传入,正式环境请用部署系统的密钥管理。
|
||
|
||
```bash
|
||
XINGBANG_DEMO_ROLE_LOGIN=1 # 演示角色发起运行必需,否则 worker 判"权限已撤销"
|
||
XINGBANG_LOCAL_MODEL_URL=https://api.deepseek.com/v1
|
||
XINGBANG_LOCAL_MODEL_NAME=deepseek-flash # 可换 deepseek-v4-pro(语义核查质量优先)
|
||
XINGBANG_LOCAL_MODEL_KEY=<你的 DeepSeek API Key>
|
||
# 后端启动前清空代理:实测直连 api.deepseek.com 可用(HTTP 200),
|
||
# 系统代理 127.0.0.1:7890 不可用(HTTP 000,与 AGENTS.md 记录的坑一致)
|
||
```
|
||
|
||
启动:`cd backend && venv/Scripts/python.exe -m uvicorn app:app --host 127.0.0.1 --port 8012`;
|
||
前端:`npm run dev -- -p 3212`,并设 `RISK_AGENT_BACKEND_URL=http://127.0.0.1:8012`(v2 隔离端口)。
|
||
|
||
---
|
||
|
||
## 第二批:完成历史经验加工流程
|
||
|
||
状态:**部分完成**。后端闭环(真实提炼入口 → 候选治理 → 卡片进方案并影响运行)已接通,
|
||
并经真实执行链测试;本模块页面入口已建并通过生产构建与源码守卫。
|
||
**未闭合**:① 真实模型提炼调用尚未实测(需要模型端点,见"剩余缺口");
|
||
② 界面点击未由自动化驱动(本机无浏览器自动化,沿用第一批 F11 口径)。
|
||
|
||
覆盖:AC-50/51/52、BR-48/49、E-28;页面入口部分覆盖 BR-50(三个入口中的第一个)。
|
||
|
||
### 页面入口
|
||
|
||
| 入口 | 位置 |
|
||
|---|---|
|
||
| 历史经验加工 | 顶部导航「历史经验加工」→ `/experience-center?project=<项目>` |
|
||
| 流程四段 | ① 来源:历史过程时间线 → ② 提炼:用真实模型生成候选 → ③ 候选:修订/评测/发布 → ④ 方案:让卡片影响核查 |
|
||
|
||
### 操作步骤(实现并按此验收)
|
||
|
||
1. 「从项目材料重建时间线」→ `POST /prescreen/projects/{id}/case-timeline`(确定性,不调用模型)。
|
||
2. 勾选来源事件、填写提炼要求 →「请求提炼」→ `POST .../knowledge-extractions`。
|
||
3. 候选卡上「自然语言修改适用范围」或「补充独立测试样本」→ `PATCH .../knowledge-candidates/{card_id}`。
|
||
4. 「隔离评测」→ 由**另一位**有发布资格的人「审核发布」→ `POST .../knowledge-candidates/{card_id}/transitions`。
|
||
5. 已发布卡「选入新方案」→「评测方案」→「发布方案」→ `POST .../review-plans` 与 `/review-plans/{id}/transitions`。
|
||
6. 在项目工作台用该方案发起预审;运行结果冻结并记录卡片版本。
|
||
|
||
### 实际结果
|
||
|
||
- **提炼(模型未配置)**:记录 `status=failed`,`candidate_id=null`,degradations 带
|
||
`EXTRACTION_UNAVAILABLE`,文案"本次未能完成经验提炼,请稍后重试或改为人工创建";
|
||
**提炼跑完后库里一张候选草稿都没有**(`test_experience_extraction` 的反例断言)。
|
||
这与第一批"模型不可用如实标未完成"同口径。
|
||
- **提炼(模型可用)**:以假传输层走真实 `agent_manager.invoke_scoped` 路径,
|
||
产出 `origin=history_derived` 且带来源事件 id 的 Skill 候选;记录保存
|
||
`prompt_version=history-extraction.v1` 与模型名,可核对"确实发起了调用"。
|
||
**真实模型调用未实测**(见剩余缺口)。
|
||
- **候选治理**:自然语言修订真的发起一次模型调用(测试断言调用次数为 1);
|
||
模型不可用时**拒绝且卡片一字未改**(比对修订前后 revision 与 conditions);
|
||
修订后仍为 `history_derived` 且保留来源、状态仍为 draft;已发布后修订升版本并记 `parent_version`。
|
||
- **卡片影响核查**:同项目两次运行对照——基座方案 `corporate.pre-review` 不含该卡片,
|
||
运行里没有该核查项;含卡片的新方案运行里出现 1 条 `history.repayment.dependency`,
|
||
其 `basis_ids=[skill.history.repayment@1.0.0]`,`component_versions` 含 `(卡片id, 1.0.0)`。
|
||
- **依赖门禁**:草稿卡片进方案时,发布被 409 拒绝;引用不存在组件时评测 `passed=false` 且发布被拒。
|
||
|
||
### 证据位置
|
||
|
||
| 内容 | 位置 |
|
||
|---|---|
|
||
| 提炼入口(15 项) | `backend/test_experience_extraction.py` |
|
||
| 候选治理与自然语言修订(15 项) | `backend/test_knowledge_governance.py` |
|
||
| 卡片 → 方案 → 运行(6 项) | `backend/test_card_to_run.py` |
|
||
| 界面源码守卫(新增) | `scripts/test_experience_center_ui.cjs`(已登记进 `scripts/verify.py`) |
|
||
| 全量验证 | `test-evidence/20261001-003148-2e7e194/`(`scripts/verify.py` **12/12 PASS**,含 `backend-unit` 全量 567 项、`frontend-build`、新增 `experience-center-ui` 守卫) |
|
||
|
||
### 剩余缺口
|
||
|
||
- **真实模型提炼未实测(P0)**:AC-50 的"若模型已配置则实际调用"需要一次真实调用证据。
|
||
本轮机器上没有设置 `XINGBANG_LOCAL_MODEL_*`,因此只交付了"不可用路径"与"假传输成功路径"。
|
||
实测方法:带 `XINGBANG_DEMO_ROLE_LOGIN=1` 与三个模型变量启动后端,再走上面步骤 2;
|
||
在此之前不得宣称"真实提炼已跑通"。
|
||
- **界面点击未由自动化驱动**:本机无 playwright/puppeteer/chromium-cli。界面证据是
|
||
"源码守卫 + 生产构建(`/experience-center` 6.08 kB)+ 代码走查",**不是**端到端点击证明;
|
||
本批的"页面入口/操作步骤"是按实现与接口核对写出的,不是浏览器截图。
|
||
- **例外边界未进入可求值条件语言**:注册表条件只支持数值阈值算子,`present/absent` 被既有断言
|
||
锁定拒绝,因此模型给出的例外保存为文本 `exception_note`,供专家修订,不作为可执行条件。
|
||
- **卡片适用条件不参与运行内逐项判定**:`conditions` 目前只用于域/范围/有效期过滤
|
||
(`knowledge_cards.effective()`);运行内条件求值需独立设计,不在本批冒充完成。
|
||
- **治理状态只实现 draft/published**:`in_review`/`rejected`/`withdrawn` 在注册表没有落地表达,
|
||
候选状态机因此只提供 `evaluate` 与 `publish`,不造一个假状态掩盖。
|
||
- **规则类(Rule)候选不在本批**:数值阈值与正式依据门禁(`_check_hard_basis`)需要单独设计,
|
||
本批只产出 Skill 类候选(可验证的缺件核查动作)。
|
||
- **顺带发现、未修**:`01-requirements.md` 的 E-18 写作 `HARD_RULE_BASIS_REQUIRED`,
|
||
但代码走的是 `ValueError` → 422 `INVALID_REQUEST`,错误码未对齐(既有问题,非本批引入)。
|
||
|
||
## 第三批:按已确认原型完成新版界面
|
||
|
||
状态:**部分完成**。深色导航、三个模块的独立入口、轨迹回放界面已接通并通过
|
||
生产构建与源码守卫。**未闭合**:界面仍未经浏览器点击/截图验证(同 F11,本机无浏览器自动化);
|
||
轨迹与会议结果的**录入**属第四批;工作台旧的「评审经验」页签未下线。
|
||
|
||
覆盖:AC-53/54/55、BR-50。
|
||
|
||
### 页面入口
|
||
|
||
| 入口 | 位置 |
|
||
|---|---|
|
||
| 业务工作区首页 | `/`(三个模块入口卡片;`?project=` 携带项目上下文) |
|
||
| AI 预审 | 深色导航「AI 预审」→ `/prescreen-workbench` |
|
||
| 历史经验加工 | 深色导航「历史经验加工」→ `/experience-center`(第二批交付) |
|
||
| 轨迹复盘 | 深色导航「轨迹复盘」→ `/trajectory-center` |
|
||
| 原落地页内容 | `/assistant`(保留,不再是默认首页) |
|
||
|
||
### 操作步骤(实现并按此核对)
|
||
|
||
1. 打开 `/` → 看到三个模块入口卡片与"当前项目上下文"提示。
|
||
2. 进入任一模块 → 深色导航高亮当前模块;`?project=` 在模块之间保持。
|
||
3. AI 预审:选项目 → 选方案 → 填本次要求 → 发起预审 → 下方结果面板给出
|
||
概率状态与依据、动态维度、推进沙盘、每条"查看依据"。
|
||
4. 轨迹复盘:选运行 → 步骤流(序号 / 类型 / `组件@版本` / 状态 / 错误码 / 证据数 / 成本 / 耗时)
|
||
→ 加载更多 → 会议结果只读对照。
|
||
|
||
### 实际结果
|
||
|
||
- 导航为深色(`nav.bg #102B27`、选中 `#244D41`、`muted #B1C6BE`),工作区画布保持浅色
|
||
`#f5f7f9`;导航内的身份选择器改用深色变体,避免深底白字不可读。
|
||
- 三个模块各有独立路由并各自渲染**复用**的组件(`PrescreenPanel` / `ImportBatchPanel` /
|
||
`ExperienceCenter` / `TrajectoryPanel`),路由里没有再写一份实现。
|
||
- 已合并的旧页 `/trajectory`、`/review-workbench`、`/report-workbench`、`/collateral-workbench`
|
||
**仍是重定向**,没有被复活(AC-55 的防重复页面)。
|
||
- 轨迹面板:失败/跳过步骤照常列出并带错误码;成本缺失显示"未记录(不填 0)";
|
||
展示服务端"不包含模型内部推理过程"的说明;无任何写操作。
|
||
- 生产构建产物(实测):`/` 1.98 kB、`/prescreen-workbench` 2.36 kB、
|
||
`/trajectory-center` 3.87 kB、`/experience-center` 7.48 kB、`/assistant` 6.08 kB。
|
||
- 首页入口卡片沿用了既有的 `.xb-project-card`,但该类此前只用于 `<button>`;
|
||
作为 `<a>` 会带上浏览器默认下划线,因此补 `display:block;text-decoration:none`
|
||
(只影响该类,按钮用法不受影响)。
|
||
- 现有 7 项界面守卫全部继续通过(可读性、S1 面板、预审面板、加工中心、评审工作台、身份恢复、助手访问)。
|
||
|
||
### 证据位置
|
||
|
||
| 内容 | 位置 |
|
||
|---|---|
|
||
| 模块壳与三入口源码守卫(新增) | `scripts/test_module_shell_ui.cjs`(已登记 `scripts/verify.py`,共 **13** 项检查) |
|
||
| 全量验证 | `test-evidence/20261001-005027-ae89462/`(`scripts/verify.py` **13/13 PASS**,含 `backend-unit` 全量 567 项、`frontend-build`、新增 `module-shell-ui` 守卫) |
|
||
|
||
### 剩余缺口
|
||
|
||
- **界面仍未经浏览器验证(F11 未变)**:深色导航与三个模块都只有"源码守卫 + 生产构建 + 代码走查"
|
||
三层证据,**没有浏览器点击或截图**;原型本身也没有视觉门禁(04-ui-spec §7 已声明不以原型替代验收)。
|
||
深色导航的文字对比度已改为**机械断言**(守卫内按 WCAG 公式实算,阈值 AA 4.5:1):
|
||
未选中 12.03:1、选中 9.49:1、muted 8.37:1、品牌 13.91:1,全部达标——但这证明的是配色可用,
|
||
不等于版面在实机上的观感已验收。
|
||
- **轨迹与会议结果的录入属第四批**:本批只做只读回放与只读对照,界面上写明了这一点。
|
||
- **工作台仍保留旧「评审经验」页签**(走 `assistant_experiences`,与第二批的知识卡片治理不是同一套)。
|
||
新旧并存会造成"哪里才是正门"的困惑;但删除是用户可见的破坏性动作,本批不擅自下线,留待确认。
|
||
- **`AgentLoopFlow.tsx`(`src/components/trajectory/`)仍是零引用死代码**:本批没有复用它,
|
||
也没有删除——它不挡事,清理不属于本批交付范围。
|
||
- **原型顶部的演示提示条未实现**:原型有"原型演示 · 未连接真实数据与模型"横幅;
|
||
本批只做了导航与工作区骨架,未加该横幅(各模块内部已有等价的域与来源标识)。
|
||
- **首页默认路由发生变化**:`/` 由聊天页改为业务工作区,原内容移到 `/assistant`。
|
||
这是**用户可见的行为变化**;若部署脚本、书签或外部链接依赖旧的 `/`,需另行确认。
|
||
|
||
## 第四批:接通评审反馈与改进发布
|
||
|
||
状态:**部分完成**(较本轮初版有实质性推进)。会议结果可从页面录入并与材料版本对照;
|
||
改进候选走**真实知识发布入口**,发布后新运行使用新版本、旧运行仍可回放——两条断言都由
|
||
真实执行链(enqueue + worker)证明。**本批首次做了真实浏览器端到端验证(F11 对这两个表面已关闭)**,
|
||
并因此发现并修掉 5 个源码守卫与生产构建都看不出的缺陷(见下「浏览器验证发现的问题」)。
|
||
**未闭合**:会议结果是**模拟录入**,未经真实会议系统;`/experience-center` 与 `/prescreen-workbench`
|
||
虽在同一次浏览器验证中被顺带修好,但其自身交互仍未逐项点过。
|
||
|
||
覆盖:AC-56、AC-57、BR-51;并顺带修复 AC-53/AC-55 的运行时缺陷。
|
||
|
||
### 页面入口
|
||
|
||
| 入口 | 位置 |
|
||
|---|---|
|
||
| 轨迹复盘(既有入口,**不新增第四个**) | 深色导航「轨迹复盘」→ `/trajectory-center` |
|
||
| 会议结果录入与对照 | 同页 `TrajectoryPanel` 下半部「会议结果对照」→「追加会议结果」表单 |
|
||
| 改进对照与发布 | 同页 `ImprovementPanel`「改进对照与发布」 |
|
||
|
||
置于轨迹复盘之内而非新开模块:14 §7 本就把「轨迹、会议记录与反向改进」写在同一节,
|
||
AC-53 又要求恰好三个模块入口。`AgentNav.tsx` 未改动。
|
||
|
||
### 操作步骤(实现并按此核对)
|
||
|
||
1. **录入会议结果**:选项目 → `TrajectoryPanel` 底部填原始结果码、会议编号、可从
|
||
`project.runs[].input_snapshot_id` 选「对应的材料版本」→ 保存。
|
||
2. **更正**:在「更正哪条记录」里选旧记录 → 保存为**追加**并带 `supersedes_id`,历史不被覆盖。
|
||
3. **提改进候选**:`ImprovementPanel` ① 选来源运行/会议结果(必填其一)、改进目标、
|
||
要发布的草稿版本、变更说明 → 「提出改进候选」。
|
||
4. **两道门**:② 「对草稿做隔离评测」(发布门禁)与「提交旧/新对照」(候选门禁)是两件事,缺一不可。
|
||
5. **审核与发布**:提交审核 → 由**另一位**身份「通过审核」→「审核发布」。
|
||
发布请求体**只有 action**,界面不提交任何版本号。
|
||
|
||
### 实际结果
|
||
|
||
- **发布是真的发布**(本批核心):端点把 `_knowledge_publisher` 注入 `improvements.transition`,
|
||
publisher 用候选声明的 `proposed_revision_ref` **精确**定位草稿(`组件id@版本`,
|
||
不按组件 id 猜"最新草稿",否则会出现"审核的是 A、发布的是 B"),再调
|
||
`knowledge_cards.publish` → `component_registry.release`:自批拒绝、隔离评测门禁、
|
||
依赖可解析三道既有保证原样生效,写入不可变 `component_version` 并**覆盖 `release` 指针**。
|
||
- **不接受自报版本号**:release 请求带 `released_ref` 一律 422 `INVALID_REQUEST`,
|
||
候选状态不前进、不产生任何组件版本(反例已测)。
|
||
- **发布失败保留旧版**:未过隔离评测的草稿 → 409 `IMPROVEMENT_NOT_VALIDATED`,
|
||
`release` 指针仍指旧版本,候选仍是 `approved`。候选状态与组件版本写在**同一个 `_db()`
|
||
连接/事务**里,publisher 抛异常即整体回滚,不会出现"版本已发布、候选没标记"。
|
||
- **非知识类目标诚实拒绝**:`orchestration` / `question_profile` 无真实发布入口 →
|
||
409 并说明原因,不用"改状态"冒充发布。
|
||
- **AC-57 端到端**(`test_improvement_release.py`,真实 enqueue + `DurableWorker.process_next()`):
|
||
同一个已发布方案,发布前运行的 `component_versions` 含 `卡片@1.0.0`、
|
||
`basis_ids=[卡片@1.0.0]`;经改进候选发布 `1.0.1` 后**再跑一次**得到 `卡片@1.0.1`;
|
||
回放第一次运行仍是 `1.0.0`,其冻结版本未被改写(`replay.read_only=true`)。
|
||
- **AC-56**:会议结果按 `matched` / `unmatched` 分组;未匹配的单列并显示「不计入分母」,
|
||
与服务端 `denominator()` 一致(未送审、撤回、附条件、未知与未匹配都不进分母)。
|
||
- **真实服务器冒烟**(不是单测的替代,脚本 `scripts/xingbang_batch4_smoke.py`):
|
||
对运行中的 uvicorn 按界面同一串请求走通
|
||
建卡 → 隔离评测 → 发布 → 结构化修订 → 录入会议结果 → 提候选 → 对照 → 换身份审核
|
||
→ 发布(不带版本号);服务端返回 `released_ref=卡片@1.0.1`,且 `release` 指针实测指向 `1.0.1`。
|
||
只用了脚本新建的组件 id,未触碰既有组件的发布指针。
|
||
**副作用**:它在演示库(`backend/xingbang_data/project_assistant.sqlite3`)新建了若干
|
||
「冒烟:回款集中依赖核查」卡片与 `SMOKE-4` 会议结果;重复运行会累积。
|
||
这些是演示库里的可见脏数据,需要时可删——本记录如实列出,不做隐藏。
|
||
|
||
### 证据位置
|
||
|
||
| 内容 | 位置 |
|
||
|---|---|
|
||
| AC-57 端到端与四条反例(4 项) | `backend/test_improvement_release.py`(新增) |
|
||
| 自报版本号被拒(API 层) | `backend/test_improvements.py` `test_client_supplied_released_ref_is_rejected` |
|
||
| 界面源码守卫(新增) | `scripts/test_improvement_panel.cjs`(已登记 `scripts/verify.py`,共 **14** 项检查) |
|
||
| 轨迹面板守卫(改:区分「回放只读」与「结果只可追加」) | `scripts/test_module_shell_ui.cjs` |
|
||
| 全量验证 | `test-evidence/20261001-030127-ff59d7e/`(`scripts/verify.py` **14/14 PASS**,含 `backend-unit` 全量 **572** 项) |
|
||
| 真实服务器冒烟 | `scripts/xingbang_batch4_smoke.py`(对 127.0.0.1:8012 实跑,退出码 0) |
|
||
| **真实浏览器端到端** | `scripts/browser-e2e.cjs`(系统 Chrome;**19/19 PASS**);截图与 `result.json` 在 `test-evidence/e2e-batch4/` |
|
||
|
||
### 浏览器验证发现的问题(源码守卫与生产构建都查不出来)
|
||
|
||
首次用真实 Chrome 打开 `/trajectory-center` 后暴露的缺陷。「看起来正常的空态」是它们的共同点——
|
||
`/projects` 读错了字段,页面安静地显示"当前身份没有可访问的项目",构建与守卫全都通过。
|
||
|
||
| # | 问题 | 归属 | 处理 |
|
||
|---|---|---|---|
|
||
| 1 | 三个模块页读 `list.items`,而 `/projects` 返回的是 `{projects, identity}` → 项目列表恒为空,**整个模块页渲染不出任何面板** | 第二/三批引入(prescreen-workbench、experience-center、trajectory-center 三处) | 改为 `list.projects` |
|
||
| 2 | `TrajectoryPanel` 没被传 `identity`,`canRecord` 恒假 → **会议结果录入表单永远不出现** | 本批 | 传入 `identity` |
|
||
| 3 | `ImprovementPanel` 的草稿下拉以组件 id 作 key/value,同一组件有多个版本草稿时**撞 React key**,也选不准要发布哪一版 | 本批 | 改以 `组件id@版本` 为键值 |
|
||
| 4 | JSX 文本里写 `**强调**` 会**原样显示星号**(JSX 不渲染 Markdown),共 9 处 | 第一/二批 5 处、本批 4 处 | 改为 `<b>`(字符串上下文处直接去掉标记) |
|
||
| 5 | 深色导航的模块名被 flex 压缩**折行**("AI 预审"断成两行),三个入口读不清 | 第三批 | `flex:0 0 auto; white-space:nowrap` |
|
||
|
||
此外还修掉一个**既有测试脆弱点**:`test_trajectory.py` 的更正用例断言"哪条排前面",
|
||
而两条记录可能落在同一时钟刻度、排序随之翻转,曾让 `scripts/verify.py` 偶发失败。
|
||
改为断言"两条都在、更正指向旧记录",与排序无关;连跑 5 次稳定通过。
|
||
|
||
回归防线:第 5 项已补进 `scripts/test_module_shell_ui.cjs` 的源码断言;
|
||
`scripts/test_ui_readability.cjs` 的导航字号断言改为不把 `min-height` 钉在规则首位
|
||
(否则它会因新增属性而误报)。第 1–4 项属于"只有浏览器能看见"的一类,
|
||
目前只由 `scripts/browser-e2e.cjs` 覆盖——该脚本**刻意不接入 verify.py**。
|
||
|
||
### 剩余缺口
|
||
|
||
- **F11 对本批两个表面已关闭,但未全面关闭**:`/trajectory-center` 已由 `scripts/browser-e2e.cjs`
|
||
在真实 Chrome 里走过(19/19),有截图;`/experience-center` 与 `/prescreen-workbench`
|
||
只验证到"能被本次路由改动修好、能渲染",其自身交互没有逐项点过,**仍记 F11 未闭合**。
|
||
另外该脚本**不在 `verify.py` 里**,也就是说这条证据不会随强制门禁自动重跑——
|
||
它需要本机 Chrome 与一次性 `npm i --no-save puppeteer-core`。
|
||
- **浏览器验证只覆盖到"能走通"这一层**:没有做视觉回归(无基线截图比对)、没有多分辨率、
|
||
没有键盘可达性与屏幕阅读器检查。深色导航对比度仍是守卫内按 WCAG 实算,不是实测。
|
||
- **会议结果是模拟录入**:AC-56 验的是"录入后与材料版本对照"的机制,不是真实会议系统对接;
|
||
真实标签映射与客户身份权限仍待确认(M5/M6)。
|
||
- **对照样本是人工录入的 JSON**,不是真实保留集;`evaluation.independent` 仍是**客户端声明**
|
||
的布尔(既有设计)——界面不把它包装成"已证明独立",但服务端也确实无法自证。
|
||
- **改进端点仍无角色门禁**:既有 `transition_knowledge_candidate` / `transition_review_plan` 对
|
||
评测与发布有 `role()` 门禁,改进端点(propose/evaluate/approve/release)只做项目范围检查。
|
||
本批给 release 接上真实发布后这个缺口的后果变重了,但加门禁会改变既有端点行为
|
||
(现有 API 测试以 `manager` 身份调用),**未擅自扩大改动**,留待确认。安全上真正关键的
|
||
"不自批"已由服务端强制(`must_not_self_approve` + `registry.release()` 的 `edited_by == actor`)。
|
||
- **题库/编排无真实发布入口**:已按 409 诚实拒绝,非假接通;需要时另行设计。
|
||
- **浏览器 E2E 尚未固化为项目门禁**:是否把它接进 `verify.py`、是否把 `puppeteer-core`
|
||
写进 `package.json`,是产品/工程决策,本批**没有替用户决定**,只提供可选脚本。
|