# 人工复核

## 入口结果边界

Gateway 必须先校验 `source_message.source_message_id`。该值为 `null`、空字符串或纯空白时，直接返回 `00-output-contract.md` 定义的 `infrastructure_input_error`；不得读取正文、附件、OCR、历史或系统上下文，也不得调用 Main Agent 或 `booking-desk-event` skill。

source message identity 合法后，Main Agent 才完成支持范围分类：

- 当前输入可理解，但没有匹配 active event 时，输出 `S10`。
- 当前输入不足，无法判断是否匹配 active event 时，输出 `S99`。
- `S10` 和 `S99` 都展示源邮件并由用户自行决定是否回复或进行其他处理。
- `S10` 和 `S99` 不由 `booking-desk-event` skill 输出。

Thank you、裸 FYI、acknowledgement、Noted、Received 等没有具体预订业务信息的文字，以及一般咨询和当前不支持的 Booking Confirmation Request，都不匹配 Trace。FYI 或单纯告知中包含与明确预订对象相关的具体补充信息时，匹配 `Trace`。正文只有 `see attached` 且附件无法取得、无法识别业务方向时走 `S99`。

需要酒店批准的价格、退款、减免、账期、付款政策或合同条件询问不是 Trace。此类具有当前业务意义但没有任务卡承接的内容必须保留在 `unknowns`：同邮件存在支持事件时输出到 `unhandled_current_intents`，整封邮件没有支持事件时走 S10。意图清楚但不受支持不等于业务判断不安全，不得仅因此输出业务人工复核。

## 两种业务人工复核

### 已知业务卡型的人工复核

只要业务 `event_type` 和 subtype 已经能够确定，就必须保留该业务事件，继续输出能够安全抽取的字段，并令该 event 的 `manual_review` 为完整 `business_event_review` 对象。不得仅因为房型、Rate Code、目标对象或某项证据存在歧义，就把事件改成 `Need Manual Review`。

常见情形包括：

- target object 不明确或不唯一，但业务卡型已确定；
- current/history 边界不明确，但业务卡型已确定；
- 已确定业务卡型，但其附件、OCR、表格或必要证据不可读；
- required room type、Rate Code、settlement price 或其他必需字段无法唯一确定；
- QBD/LianTai row、highlight 或 current-row evidence 缺失或歧义；
- system context 显示 duplicate、pending/open task、active workflow、lock 或 conflict。

例如，正文明确 `please update the booking as attached`，因此业务卡型已经确定为 Update；附件不可读时仍输出对应 Update event，把安全取得的订单号、客人名等保留下来，并附非空 `manual_review`。Adapter 据此派生 `manual_review + 原业务 task_type + 原业务 subtype`，而不是 Fallback。

### 业务类型或 subtype 未知的 Fallback

只有业务 `event_type` 或 subtype 本身无法确定时，才输出 `event_type=Need Manual Review`。Adapter 将其派生为：

```text
manual_review + Fallback + business_event_review
```

例如，同一段 current action 同时可能表示 New Booking 或 Update，且没有足够证据裁决，业务类型无法确定，此时才走 Fallback。

不得为了满足 Main Agent 的 skill-call gate 而制造 `Need Manual Review`。如果 Main 给出的所有粗候选都被 skill 否定，skill 返回内部 `no_supported_event` disposition，由 Main 转成 S10。

## 必要结构和字段类型

业务级 `manual_review` 必须完整包含九个字段：

```json
{
  "reason_code": "room_type_mapping_multiple_candidates",
  "visible_reason": "房型原文可识别，但无法唯一映射到当前有效 PMS 房型代码。",
  "review_record_type": "business_event_review",
  "missing_fields": [
    "/extracted_fields/room_items/0/pms_room_type_code"
  ],
  "blocking_points": [
    "pms_room_type_code is required before Preflight"
  ],
  "conflicting_points": [],
  "suggested_human_actions": [
    "select_room_type_from_active_pms_catalog"
  ],
  "evidence_to_check": [
    "current_body",
    "current_attachments"
  ],
  "known_fields": {
    "room_type_raw": "SUITE"
  }
}
```

固定规则：

- 九个字段必须全部存在。
- `reason_code` 和 `visible_reason` 必须是非空字符串。
- `review_record_type` 固定为 `business_event_review`。
- `missing_fields`、`blocking_points`、`conflicting_points`、`suggested_human_actions`、`evidence_to_check` 固定为字符串数组；无内容时使用空数组。
- `known_fields` 固定为对象；没有已知值时使用空对象。
- `missing_fields[]` 每一项必须是指向当前 event 的 RFC 6901 JSON Pointer，例如 `/extracted_fields/room_items/0/pms_room_type_code`。不得填写人类说明、点号路径或根邮件路径。
- 不新增 `required_user_inputs`；前端业务卡字段注册表负责将 pointer 映射到可编辑控件。
- pointer 无法映射到该业务卡的已知可编辑字段时，属于 adapter contract error，不能展示一个无法完成的复核卡。

## 房型和其他必需字段

房型原文可以识别但映射不唯一时：

- 保留 `room_type_raw`；
- `pms_room_type_code=null`；
- 在 `manual_review.missing_fields` 中登记对应的 JSON Pointer；
- 用户只能从信息系统提供的当前有效 PMS 房型目录中选择，不得由 Agent 猜测，也不得允许用户自由填写 PMS code。

Rate Code、价格或其他业务必需字段遵循相同原则：保留安全抽取值，待用户确认的目标字段置为 `null` 并用 pointer 标记。`requires_downstream_hard_validation` 不能替代这些字段的人工确认；也不得写成“人工复核或 downstream validation 二选一”。

一个 event 进入人工复核时，不得清空同邮件中的 sibling events。每个 event 独立派生路由：确定且完整的 sibling 仍为 normal task，需要确认的 sibling 保留其业务 task type/subtype 并进入 manual-review mode。

## 同卡解阻状态

Agent 输出只描述初始业务判断，保持不可变。信息系统在同一张业务卡上维护复核状态，初始为：

```json
{
  "review_status": "pending",
  "review_resolution": null
}
```

用户确认后保存：

```json
{
  "review_status": "resolved",
  "review_resolution": {
    "field_overrides": [
      {
        "field_pointer": "/extracted_fields/room_items/0/pms_room_type_code",
        "value": "SU1"
      }
    ],
    "resolved_by": "<user_id>",
    "resolved_at": "<ISO-8601>"
  }
}
```

固定规则：

- 原 Agent payload 和初始 `result_type=manual_review` 不得改写；当前页面模式由 `review_status` 控制。
- `field_overrides[].field_pointer` 必须与待解决字段 pointer 对应，覆盖值和审计信息由信息系统持有。
- 只有所有缺失字段完成、目录值校验通过、依赖字段重新校验通过后，才允许进入现有 Preflight。
- 在 Preflight 完成前不得写 PMS。
- 不创建第二张 linked normal task；解决后仍是同一张业务卡。
- 业务字段可以按权限编辑；邮件原文、raw evidence、source ID 和审计字段只读。

## 常见 Reason Code

- `current_history_boundary_unclear`
- `target_object_unclear`
- `multiple_target_candidates`
- `attachment_or_ocr_unreadable`
- `event_type_conflict_unclear`
- `subtype_unresolved`
- `room_type_mapping_unconfirmed`
- `room_type_mapping_multiple_candidates`
- `rate_code_unconfirmed`
- `rate_code_rule_not_covered`
- `settlement_price_required`
- `manual_price_unconfirmed`
- `composite_unit_price_unconfirmed`
- `fix_charge_unconfirmed`
- `qbd_liantai_row_evidence_unreadable`
- `parent_child_split_evidence_unclear`
- `stay_date_inference_unclear`
- `existing_order_record_found`
- `pending_or_active_workflow_found`
