完成 M002 V3 同卡复核解阻

This commit is contained in:
andy
2026-07-11 20:11:03 +08:00
parent 6416c1b78a
commit 705f779b32
21 changed files with 1150 additions and 23 deletions

View File

@@ -34,8 +34,8 @@
- M002 V3 新入口采用结构化 `S10/S99``S10` 表示未匹配当前支持的业务事件,`S99` 表示输入不足或无法形成业务素材包;旧 `S000/S999` 继续按历史数据兼容展示。
- `S10/S99` 后端会创建只读源邮件通知卡,任务列表可见,订单列表不可见;当前代码中的旧 `SOURCE_MESSAGE_ONLY` 任务仍按同一只读语义展示。
- 源邮件只读通知卡不允许编辑、确认、人工转换订单、执行 OPERA 或重试 OPERA不参与订单任务执行队列不阻塞其他任务也不被其他任务阻塞。
- type-known manual review 后续应展示为原业务任务卡的复核模式,不应统一展示成 Fallback。只有业务类型或 subtype 本身未知时才进入 Fallback。
- 复核场景下允许用户确认订单归属;不等于开放普通任务任意切换订单。
- type-known manual review 已支持同卡复核解阻第一版:应展示为原业务任务卡的复核模式,不应统一展示成 Fallback。只有业务类型或 subtype 本身未知时才进入 Fallback。
- 复核场景下允许用户确认订单归属;当前第一版只允许确认当前任务所属订单,不等于开放普通任务任意切换订单。
- 历史 Message Notification 挂临时订单,只读展示,不参与订单任务执行队列,不阻塞其他任务,也不被其他任务阻塞。
- Fallback / manual_review 转为 New / Update / Cancel 时需要展示审计轨迹;登录权限底座已提供,具体业务审计 actor 迁移仍后置。
- 普通任务切换订单接口已确认后置,前端第一版不要把普通任务拖拽或切换订单做成可提交能力。
@@ -50,10 +50,11 @@
| `GET /api/reservation/orders` | 查询订单列表 | 默认返回全部订单状态;`open_task_count` 排除 `COMPLETED``FAILED`;隐藏技术订单不返回,因此 S10/S99 和旧 S000/S999 不会在订单列表形成订单。 |
| `GET /api/reservation/tasks` | 查询任务列表 / 工作台 | 用 `can_process``readonly_reason_code` 控制入口按钮;列表不返回 AI 原始 payload、邮件正文或附件 URL已返回来源邮件会话摘要字段并支持 `order_status` 按任务所属订单状态筛选;旧 S000/S999 和新 S10/S99 都以 `task_type=SOURCE_MESSAGE_ONLY` 只读任务返回,列表已透出 `result_type``ai_task_type``route_code``system_process_category`。 |
| `GET /api/reservation/orders/{orderId}` | 查询订单详情与任务时间线 | `include_tasks=false` 可只取订单摘要;时间线按后端队列顺序返回,前端不要自行按创建时间重排;`tasks[]` 已返回来源邮件会话摘要字段和 V3 路由字段;隐藏技术订单详情不可作为普通订单页打开。 |
| `GET /api/reservation/tasks/{taskId}` | 查询任务详情 | 以返回的可处理状态和只读原因控制按钮,不只看任务状态;`fields[]` 已包含 P0 字段元数据;源邮件只读通知卡字段列表和 OPERA 操作列表为空;结构化 S10/S99 通过 `source_message_only_result.agent_assessment``notification``manual_review` 展示;普通业务任务可通过 `adapter_contract_errors[]``unhandled_intents[]` 查看同批次未建任务的诊断信息。 |
| `GET /api/reservation/tasks/{taskId}` | 查询任务详情 | 以返回的可处理状态和只读原因控制按钮,不只看任务状态;`fields[]` 已包含 P0 字段元数据;源邮件只读通知卡字段列表和 OPERA 操作列表为空;结构化 S10/S99 通过 `source_message_only_result.agent_assessment``notification``manual_review` 展示;普通业务任务可通过 `adapter_contract_errors[]``unhandled_intents[]` 查看同批次未建任务的诊断信息type-known manual review 会返回顶层 `review_status``review_resolution``manual_review`。 |
| `PUT /api/reservation/tasks/{taskId}/draft` | 保存任务草稿 | 只保存草稿,不代表用户最终确认。 |
| `POST /api/reservation/tasks/{taskId}/confirm` | 最终确认任务 | 后端会做第一版字段校验,通过后进入 `READY`。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | Fallback 人工转换 | 只用于 manual_review / fallback不用于普通任务切换订单。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | type-known manual review 同卡复核解阻 | 只用于已知业务类型的 `result_type=manual_review` 任务;提交 `field_overrides[]` 和当前订单归属确认,通过后进入 `READY` 并生成两条 OPERA 模拟操作。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 执行 OPERA 模拟操作 | 当前是模拟,不调用真实 OPERA。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 重试失败 OPERA 模拟操作 | 重试会追加 attempt 历史,前端不要覆盖旧失败记录。 |
| `GET /api/reservation/tasks/{taskId}/audits` | 查询任务审计流水 | 用于展示人工确认、转换、模拟操作等轨迹。 |
@@ -146,6 +147,33 @@ POST /api/auth/logout
- 任务列表、订单任务时间线和任务详情顶层已透出 `result_type``ai_task_type``route_code``system_process_category`。前端展示任务卡标题和标签时优先用这些稳定 code不要只靠旧 `task_type` 判断。
- `adapter_contract_errors[]``unhandled_intents[]` 只在任务详情返回,表示同一 SuperAgent 入站批次中没有生成业务任务的诊断块;前端只读展示并提供来源邮件入口,不显示保存、确认、执行或重试按钮。
### 5.5.1 Type-known manual review 同卡复核解阻接入注意
- `result_type=manual_review``system_task_type` 不是 `MANUAL_REVIEW` 时,前端应在原业务任务卡上展示复核模式,不要跳到 Fallback 转换页面。
- 任务详情顶层返回 `review_status``PENDING` 表示等待用户补字段或确认订单归属;`RESOLVED` 表示同卡复核已解阻。
- 任务详情顶层 `manual_review` 返回 SuperAgent 原始复核原因、缺失字段、阻塞点和建议动作,前端只读展示;不要把它当成可编辑表单直接提交。
- 解阻接口使用 `POST /api/reservation/tasks/{taskId}/manual-review-resolutions`。请求体:
```json
{
"confirmed_order_id": "20001",
"reason": "确认 PMS 房型代码后解阻。",
"field_overrides": [
{
"field_pointer": "/extracted_fields/pms_room_type_code",
"value": "RM3"
}
]
}
```
- `field_pointer` 必须是 RFC 6901 JSON Pointer并且只能指向当前任务卡可编辑字段后端会映射到矩阵 `field_path`。非法或只读字段会返回 `TASK_REVIEW_POINTER_INVALID`
- `confirmed_order_id` 第一版必须等于当前任务的 `order_id`;如果前端需要选择其他订单,仍属于后续“复核场景订单归属选择”细化,不要复用普通任务切换订单能力。
- 解阻成功后返回 `task_status=READY``review_status=RESOLVED``review_resolution.field_overrides[]``confirmed_payload` 和两条 `opera_operations[]`。前端应刷新任务详情并显示 OPERA 模拟操作入口。
- 解阻过程不改写 `ai_payload_json`;用户修正值保存在 `review_resolution``confirmed_payload.field_values` 中。
- `review_resolution.resolved_at` 是 UTC `Z` 时间点。
- type-known manual review 不允许调用通用 `POST /api/reservation/tasks/{taskId}/confirm`;前端必须使用本节解阻接口,否则后端返回 `TASK_REVIEW_RESOLUTION_REQUIRED`
### 5.6 前端联调演示数据 seed 接口
后端提供一个受控的 dev/test 演示数据入口,方便前端在空库或本地环境快速看到页面效果。
@@ -270,7 +298,7 @@ run_label: 可选调试标签
## 7. 需要持续提醒的后置事项
- 普通任务切换订单接口继续后置。
- M002 V3 的结构化 `S10/S99` 入站、42 路由枚举 / 稳定配置、`UNHANDLED_CURRENT_INTENT``adapter_contract_error` transition 最小落库,以及任务列表 / 订单时间线 / 任务详情 V3 路由字段和只读诊断块透出已完成;type-known manual review 同卡解阻、复核场景订单归属确认仍需后续后端 checkpoint
- M002 V3 的结构化 `S10/S99` 入站、42 路由枚举 / 稳定配置、`UNHANDLED_CURRENT_INTENT``adapter_contract_error` transition 最小落库任务列表 / 订单时间线 / 任务详情 V3 路由字段和只读诊断块透出type-known manual review 同卡解阻第一版均已完成
- 系统管理后台 V1 已完成后续若要做用户搜索更多筛选、批量操作、密码策略增强、MFA、登录设备管理应单独开需求。
- 现有 Reservation / SourceMessage 业务接口的强制登录、强制权限和业务审计 actor 全量迁移仍后置。
- 真实 OPERA / OHIP 接入继续后置。

View File

@@ -17,6 +17,7 @@
| 联调 | 演示数据 seed 接口 `POST /api/system/reservation/demo-data` | 本地 / test 前端页面看效果 | 已完成;仅 dev/test 受控使用 |
| 联调 | Debug EML 上传接口 `POST /api/system/debug/eml-superagent-runs` | Debug 页面上传 `.eml` 看 SuperAgent 结果 | 已完成第一版;仅 dev/test 受控使用 |
| P1 | S10/S99 源邮件只读通知卡与旧 S000/S999 兼容 | 任务列表、任务详情来源邮件查看 | 已完成第一版:旧 S000/S999 兼容,新结构化 S10/S99 可入站并在任务列表 / 详情只读展示 |
| P1 | type-known manual review 同卡复核解阻 | 任务详情复核 | 已完成第一版原业务任务卡复核、字段修正、订单归属确认、READY 流转 |
| P1 | 任务卡前端字段白名单元数据接口 | 字段白名单调试、版本对齐 | 未完成;若任务详情已透出完整元数据,可后置 |
| 后置 | 普通任务切换订单接口 | 任务详情订单归属调整 | 未完成;已确认后置 |
@@ -35,6 +36,7 @@
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 已完成第一版模拟操作 | 可以 | 暂无;真实 OPERA 写入另行确认。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 已完成第一版模拟重试 | 可以 | 暂无;真实 OPERA 重试另行确认。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | 已完成 | 可以 | 暂无。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | 已完成第一版 | 可以 | 只用于 type-known manual review第一版 `confirmed_order_id` 必须等于当前任务订单,不开放普通任务任意切换订单。 |
| `GET /api/source-messages` | 已完成安全摘要列表 | 可以 | 不能替代邮件会话全文接口。 |
| `GET /api/source-messages/{id}` | 已完成单条安全摘要 | 可以 | 不能替代邮件会话全文接口。 |
| `GET /api/source-messages/{id}/original` | 已完成单封原文受控读取 | 谨慎接入 | 只能读单封邮件,不能返回同一 conversation 全量邮件。 |
@@ -326,8 +328,8 @@ POST /api/system/reservation/demo-data
| 42 路由元数据 | 任务列表筛选、订单任务时间线、任务详情标题、字段展示 | 已完成第一版 | 后端保存并返回 AI 原始 `result_type/ai_task_type/task_subtype``route_code` 和系统处理分类;前端不要只依赖系统主任务类型判断卡片。 |
| `unhandled_current_intents[]` 展示块 | 任务详情 | 已完成第一版 | 后端保存并在任务详情 `unhandled_intents[]` 返回未覆盖业务意图,只用于展示和源邮件查看,不自动建业务任务卡。 |
| `adapter_contract_error` | 任务详情、错误提示 | 已完成第一版 | 命中 P1/P2 未闭合或路由冲突时,任务详情 `adapter_contract_errors[]` 返回稳定错误 code 和原始片段,不转成 Fallback。 |
| type-known manual review 同卡解阻 | 任务详情复核 | 后置 | `manual_review` 不再全部等同 Fallback已知业务卡型返回原业务卡信息、`review_status``review_resolution` 和可编辑 pointer 字段。 |
| 复核场景订单归属确认 | 任务详情复核 | 后置 | 后端提供复核确认时的订单归属确认 / 选择能力;这不等于普通任务任意切换订单。 |
| type-known manual review 同卡解阻 | 任务详情复核 | 已完成第一版 | `manual_review` 不再全部等同 Fallback已知业务卡型返回原业务卡信息、`review_status``review_resolution` 和可编辑 pointer 字段,解阻后进入 `READY`。 |
| 复核场景订单归属确认 | 任务详情复核 | 已完成第一版 | 后端提供复核确认时的订单归属确认;当前第一版只能确认当前任务所属订单,后续如要选择其他订单需另行细化。 |
前端注意:不要把访问口令写入前端仓库、浏览器环境变量或构建产物;该接口只能由本地联调人员手动调用或由受控测试脚本调用。
@@ -445,6 +447,7 @@ GET /api/reservation/tasks/{taskId}
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/execute` | 执行 OPERA 模拟操作。 | 已完成第一版模拟。 |
| `POST /api/reservation/tasks/{taskId}/opera-operations/{operationId}/retry` | 重试失败的 OPERA 模拟操作。 | 已完成第一版模拟。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-conversions` | 将 Fallback / manual_review 转换为具体任务类型。 | 已完成。 |
| `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` | type-known manual review 在原业务任务卡上提交字段修正和订单归属确认。 | 已完成第一版。 |
已完成的 `fields[]` 字段:
@@ -487,6 +490,82 @@ GET /api/reservation/tasks/{taskId}
| `fields[]` | `task_subtype` | 3.0 字段表中的任务 subtype / 业务动作。 |
| `fields[]` | `default_value_source` | 3.0 字段表中的默认值 / 回显来源。 |
### 8.1 Type-known manual review 同卡复核解阻
当前状态:后端已完成第一版。`result_type=manual_review``system_task_type` 不是 `MANUAL_REVIEW` 时,前端在原业务任务卡上展示复核模式,不进入 Fallback 转换页面。
任务详情增量字段:
| 字段 | 说明 |
| --- | --- |
| `review_status` | `PENDING` 表示等待复核,`RESOLVED` 表示已解阻。 |
| `review_resolution` | 已解阻后的复核结果;未解阻时为 `null`。 |
| `manual_review` | SuperAgent 原始复核说明、缺失字段、阻塞点、建议人工动作;只读展示。 |
解阻接口:
```text
POST /api/reservation/tasks/{taskId}/manual-review-resolutions
Content-Type: application/json
```
请求示例:
```json
{
"confirmed_order_id": "20001",
"reason": "确认 PMS 房型代码后解阻。",
"field_overrides": [
{
"field_pointer": "/extracted_fields/pms_room_type_code",
"value": "RM3"
}
]
}
```
返回示例:
```json
{
"task_id": "10001",
"order_id": "20001",
"task_status": "READY",
"review_status": "RESOLVED",
"review_resolution": {
"schema_version": "manual-review-resolution-v1",
"confirmed_order_id": "20001",
"resolved_at": "2026-07-11T00:00:00Z",
"field_overrides": [
{
"field_pointer": "/extracted_fields/pms_room_type_code",
"field_path": "extracted_fields.pms_room_type_code",
"value": "RM3"
}
]
},
"confirmed_payload": {
"schema_version": "field_path-v1",
"field_values": {
"extracted_fields.pms_room_type_code": "RM3"
}
},
"opera_operations": [
{"operation_code": "SIMULATE_PRECHECK"},
{"operation_code": "SIMULATE_WRITE"}
]
}
```
前端注意:
- `field_pointer` 必须是 RFC 6901 JSON Pointer并且只能指向任务详情 `fields[]` 中当前可编辑字段;只读字段或未知字段会返回 `TASK_REVIEW_POINTER_INVALID`
- `confirmed_order_id` 第一版必须等于当前任务 `order_id`;普通任务任意切换订单继续后置。
- type-known manual review 不能调用通用 `POST /api/reservation/tasks/{taskId}/confirm`;必须调用本节解阻接口,否则后端返回 `TASK_REVIEW_RESOLUTION_REQUIRED`
- `review_resolution.resolved_at` 是 UTC `Z` 时间点。
- 解阻成功后刷新任务详情,按钮状态以新的 `task_status=READY``availability` 为准。
- `confirmed_payload.field_values` 仍按矩阵 `field_path` 保存,不是 OPERA 最终参数。
建议返参增量示例:
```json

View File

@@ -6,7 +6,7 @@
| --- | --- |
| 文档版本 | 0.1 |
| 日期 | 2026-07-11 |
| 状态 | 0711 P0 基线确认版;后端已完成 M002 V3 CP1-CP4 入站、路由持久化列表 / 详情展示基线 |
| 状态 | 0711 P0 基线确认版;后端已完成 M002 V3 CP1-CP5 入站、路由持久化列表 / 详情展示和同卡复核解阻第一版 |
| 适用范围 | SourceMessage 之后的 SuperAgent 输出适配、任务路由、只读通知卡、人工复核同卡解阻、前后端协作边界 |
| 主要读者 | 产品、后端、前端、测试、SuperAgent 对接方、后续协作 agent |
@@ -252,7 +252,7 @@ Agent payload 不可变。本系统在同一张卡上维护复核状态:
```json
{
"review_status": "pending",
"review_status": "PENDING",
"review_resolution": null
}
```
@@ -261,14 +261,16 @@ Agent payload 不可变。本系统在同一张卡上维护复核状态:
```json
{
"review_status": "resolved",
"review_status": "RESOLVED",
"review_resolution": {
"field_overrides": [
{
"field_pointer": "/extracted_fields/room_items/0/pms_room_type_code",
"field_path": "extracted_fields.room_items[].pms_room_type_code",
"value": "SU1"
}
],
"confirmed_order_id": "10001",
"resolved_by": "<user_id>",
"resolved_at": "2026-07-11T00:00:00Z"
}
@@ -280,10 +282,44 @@ Agent payload 不可变。本系统在同一张卡上维护复核状态:
- 不改写 `ai_payload_json`
- 不创建第二张 linked normal task。
- `missing_fields[]` 必须是 RFC 6901 JSON Pointer。
- Pointer 必须能映射到该业务卡已知可编辑字段,否则为 `adapter_contract_error`
- 订单归属确认可作为复核解阻的一部分保存,但不得打开普通任务随意切换订单能力
- 入站阶段 `missing_fields[]` 不完整或不是 RFC 6901 Pointer 时,按 `adapter_contract_error` fail closed不创建业务任务
- 解阻接口提交的 Pointer 必须能映射到该业务卡当前可展示且可编辑字段,否则返回 `TASK_REVIEW_POINTER_INVALID`
- 订单归属确认可作为复核解阻的一部分保存;当前第一版只允许确认当前任务所属订单,不开放普通任务随意切换订单能力。
- 全部缺失字段、订单归属、目录值和依赖校验通过后,才进入 Preflight / READY。
### 9.3 后端第一版接口
```text
POST /api/reservation/tasks/{taskId}/manual-review-resolutions
Content-Type: application/json
```
请求示例:
```json
{
"confirmed_order_id": "20001",
"reason": "确认 PMS 房型代码后解阻。",
"field_overrides": [
{
"field_pointer": "/extracted_fields/pms_room_type_code",
"value": "RM3"
}
]
}
```
响应要点:
- `task_status=READY`
- `review_status=RESOLVED`
- `review_resolution.field_overrides[]` 同时返回 `field_pointer`、矩阵 `field_path` 和人工值。
- `review_resolution.resolved_at` 使用带 `Z` 的 UTC 时间点。
- `confirmed_payload.field_values` 使用矩阵 `field_path` 保存,不按 `write_path` 生成 OPERA 参数。
- 自动生成第一版固定两条 OPERA 模拟操作。
- 写入 `MANUAL_REVIEW_RESOLVE` 审计。
- type-known manual review 不允许走通用 `POST /api/reservation/tasks/{taskId}/confirm`,否则会返回 `TASK_REVIEW_RESOLUTION_REQUIRED`
## 10. P1/P2 未闭合范围处理
0711 导入包已经明确 P1/P2 未闭合。后端、前端、Adapter 都不得自行发明规则。
@@ -326,7 +362,7 @@ V3 建议拆成以下 checkpoint避免一次性重构过大
| M002-V3-CP2 | 入站解析兼容 | 已完成:正式回调支持结构化 S10/S99 和 V3 业务根,保留旧 S000/S999 兼容 |
| M002-V3-CP3 | 路由持久化 | 已完成第一版:已保存 AI 原始三元组、route_code、system_process_category、unhandled_current_intents 和 adapter_contract_error |
| M002-V3-CP4 | 列表 / 详情展示 | 已完成第一版:任务列表、订单任务时间线和任务详情透出 V3 路由字段;任务详情支持 S10/S99 入口通知结构、unhandled intent 展示块和 adapter contract error 展示块 |
| M002-V3-CP5 | 同卡复核解阻 | 支持 review_status、field_overrides、复核场景订单归属确认和 READY 流转 |
| M002-V3-CP5 | 同卡复核解阻 | 已完成第一版:支持 review_status、review_resolution.field_overrides[]、复核场景订单归属确认、JSON Pointer 校验和 READY 流转 |
| M002-V3-CP6 | P0 fixtures 回归 | 引入 0711 P0 fixtures / validator 作为后端适配测试参考,补充项目级测试 |
## 13. 明确不做
@@ -343,7 +379,7 @@ V3 P0 不做以下事项:
## 14. 当前代码现状提醒
截至 M002 V3 CP4 落地后,当前后端已经实现:
截至 M002 V3 CP5 落地后,当前后端已经实现:
- `S000/S999` 文本结果兼容处理。
- 结构化 `S10/S99` 入站处理,复用 `SOURCE_MESSAGE_ONLY` 只读特殊任务。
@@ -354,13 +390,12 @@ V3 P0 不做以下事项:
- 任务列表、订单任务时间线和任务详情顶层透出 `result_type``ai_task_type``task_subtype``route_code``system_process_category`
- `SOURCE_MESSAGE_ONLY` 任务详情透出 `source_message_only_result.result_type``route_code``agent_assessment``notification``manual_review``raw_answer`
- 业务任务详情按同一 AI 批次透出 `adapter_contract_errors[]``unhandled_intents[]` 只读展示块。
- type-known manual review 创建在原业务任务卡上,任务详情返回 `review_status``review_resolution``manual_review`
- `POST /api/reservation/tasks/{taskId}/manual-review-resolutions` 支持字段修正、当前订单归属确认、JSON Pointer 到可编辑字段校验、READY 流转、confirmed payload 写入、两条 OPERA 模拟操作创建和审计记录。
- 订单 / 任务列表、任务详情、草稿保存、最终确认、OPERA 模拟骨架和审计列表。
- SuperAgent 查询上下文接口 1、2以及邮件会话相关查询。
仍需后续 checkpoint 实现:
- type-known review 同卡解阻、`review_status``review_resolution.field_overrides[]`
- 复核场景订单归属确认。
- `manual_review.missing_fields[]` 到任务卡可编辑字段白名单的完整映射校验。
- `source_message.source_message_id` 缺失时按 V3 typed `infrastructure_input_error` 结构响应。
- 真实 OPERA / OHIP、普通任务任意切换订单、P0 fixtures / validator 全量回归。