# ai-customer-service 最新审查报告（2026-05-06）

> 审查时间：2026-05-06  
> 代码基线：`ee3a31e77c00d47802e7b3a54057467b3a713400`  
> 审查方式：小龙主审 + 双视角 QA 复核 + 现有门禁文档对照  
> 目标：给出当前代码与放行状态的真实结论，回收过期结论，并把问题转成可执行整改基线。  
> 配套任务板：`docs/REMEDIATION_TASK_BOARD_2026-05-06.md`

---

## 0. 阶段门控结论

### 总结论
- **代码级门禁：PARTIAL / 不稳定**
- **sub2api 单平台主链：PASS WITH RISKS**
- **newapi 平台能力：FAIL**
- **真实共享预生产 Gate B：FAIL**
- **生产灰度 Gate C：FAIL**

### 是否可进入下一阶段
- **是否可按“整体生产可上线”口径放行：否**
- **是否可按“多平台能力已完成”口径汇报：否**
- **是否可按“sub2api 单平台代码级链路已可用”口径汇报：是，但必须同时声明关键风险与未完成门禁**

### 当前最小可接受口径
1. 代码级门禁已通过
2. sub2api 的 webhook → outbox → callback worker 主链已接通
3. newapi 当前未通过，不应按已接入汇报
4. 真实共享预生产 / 灰度环境证据未闭环，因此不能按生产可上线口径放行

---

## 1. 审查输入与证据来源

### 1.1 已读取的关键代码
- `cmd/ai-customer-service/main.go`
- `internal/app/app.go`
- `internal/http/router.go`
- `internal/http/handlers/platform_webhook_handler.go`
- `internal/http/handlers/platform_webhook_security.go`
- `internal/platformadapter/sub2api_adapter.go`
- `internal/platformadapter/newapi_adapter.go`
- `internal/service/platformevents/builder.go`
- `internal/service/platformdelivery/worker.go`
- `internal/store/postgres/platform_event_store.go`

### 1.2 已读取的关键文档
- `docs/CODE_REVIEW_REPORT.md`
- `docs/RECTIFICATION_REVIEW_REPORT_V2.md`
- `docs/REVIEW_REPORT_2026-05-04.md`
- `docs/P0_P1_P2_RECTIFICATION_EXECUTION_BOARD.md`
- `docs/PRODUCTION_LAUNCH.md`
- `test/QA_GATE_STATUS.md`
- `prd/PRODUCTION_CHECKLIST.md`

### 1.3 已采纳的实测依据
- 本轮主审曾捕获两次 `go test ./...` 失败信号：
  - `test/e2e/sub2api_callback_flow_test.go:186`
  - 一次实际 `event[0].type = message.processing`，预期 `message.received`
  - 本轮复核再次实际 `event[0].type = reply.generated`，预期 `message.received`
  - 两次都伴随 `platform callback event delivery failed` 与 `sql: database is closed`
- 曾有并行 QA 复核在当时现态仓库上复跑 `go test ./... -count=1`：通过
- 但本轮再次实测 `go test ./... -count=1`：失败
- 因此当前最真实口径应为：`go build ./...`、`go vet ./...` 通过；`go test ./...` 存在不稳定失败，代码级门禁不能再写成稳定 PASS

### 1.4 证据解释原则
- `go build ./...`、`go vet ./...` 当前可支持通过结论
- `go test ./...` 当前不能稳定支持通过口径，应视为不稳定失败状态
- 真实失败信号不能被抹掉，应作为当前事实与稳定性风险保留
- 不以历史报告或角色自报覆盖当前代码与命令事实

---

## 2. 当前真实状态

### 2.1 已成立的事实
1. `sub2api` 主链路已真实接通，不是只有定义没有调用
2. `newapi` 不是“待联调”，而是“入口未实现但装配可开”的未通过状态
3. 代码级门禁与本地/仓库内验证不能等同于真实预生产或生产放行
4. 当前最主要的阻塞，不再是早期报告中的旧 P0，而是：
   - 平台能力口径失真
   - callback / outbox 一致性与扩展性边界未收口
   - 真实环境放行证据未闭环

### 2.2 已不应继续沿用的旧结论
以下表述对当前代码已不再成立，不应继续作为“当前事实”引用：
1. `RateLimiter` 存在 P0 并发写问题
2. ticket resolve/close 不区分不存在与状态冲突
3. 后台接口“完全无鉴权”
4. prod 默认仍可 fallback 到 memory
5. readiness 相关生产约束仍未收紧

说明：
- 这些项在旧报告中曾成立或部分成立，但已与当前代码和现有门禁文档不一致
- 继续引用会造成报告漂移

### 2.3 仍然成立的高层判断
1. 当前项目还不是完整 PRD 意义上的完整 AI 客服系统
2. 当前不能按“整体生产可上线”口径放行
3. 文档漂移仍是风险，只是漂移重心已经从早期代码 P0 转向旧报告口径过期

---

## 3. 关键调用链路核查

### 3.1 sub2api 主链路核查

#### 结论
- **PASS WITH RISKS**

#### 四层核查
1. 定义
   - `PlatformAdapter` 接口存在
   - `Sub2APIAdapter` 已实现
   - `Worker`、`PlatformEventStore`、event builder 均存在
2. 装配
   - `internal/app/app.go` 会在配置开启时注册 `sub2api` adapter
   - 在 `platformEvents != nil` 且配置满足时启动 `sub2api` worker
3. 调用
   - `router` → `PlatformWebhookHandler`
   - `PlatformWebhookHandler` → `registry.Resolve(platform)` → adapter `ParseInbound`
   - `dialog.Process` 后进入 `BuildInboundEvents`
   - `InsertPendingBatch` 写入 outbox
   - worker `RunOnce` / `deliver` 发起 callback
4. 入口
   - `/api/v1/customer-service/platforms/sub2api/webhook`

#### 结论解释
- 这条链路是实链路，不是“有结构、没接线”
- 但它仍然带有一致性、并发和稳定性风险，不能直接放大为“平台回调系统已生产级完成”

### 3.2 newapi 主链路核查

#### 结论
- **FAIL**

#### 直接证据
1. `internal/platformadapter/newapi_adapter.go:20-21`
   - `ParseInbound` 直接返回 `501 not implemented`
2. `internal/app/app.go:129-130`
   - 当 `cfg.PlatformAdapters.NewAPI.Enabled` 时，仍会注册 `newapi` adapter
3. `internal/app/app.go:186-187`
   - `startWorker("newapi", cfg.PlatformAdapters.NewAPI)` 仍可能启动 `newapi` callback worker

#### 结论解释
- 当前状态不是“newapi 已接通但未验证”，而是“配置上看似支持，真实入口未实现”
- 这是典型 `call_chain_gap + implementation_gap`

---

## 4. 自动化与验证结果结论

| 检查项 | 结论 | 说明 |
|---|---|---|
| 代码级门禁 | PARTIAL / 不稳定 | `go build ./...`、`go vet ./...` 当前通过；`go test ./... -count=1` 本轮再次失败于 `test/e2e/sub2api_callback_flow_test.go:186` |
| sub2api 主链存在性 | PASS | 入口、调用、outbox、worker 四层均可追踪 |
| newapi 平台能力 | FAIL | 入口未实现但装配仍可打开 |
| callback worker 基本投递能力 | PASS | 成功/失败/重试/死信路径存在 |
| callback_target 契约一致性 | FAIL | 字段存在，但 worker 不消费该字段 |
| outbox 并发投递安全性 | PARTIAL | `ListDue` 无 claim / `skip locked`，多实例下有重复投递窗口 |
| outbox 强一致性 | PARTIAL | 非严格 transactional outbox |
| 真实共享预生产 Gate B | FAIL | 当前仍缺真实共享预生产复跑与留痕 |
| 生产灰度 Gate C | FAIL | 当前仍缺真实监控接线、灰度稳定性与回滚证据 |

---

## 5. 问题清单

### Critical

#### C-01 真实共享预生产 / 生产放行证据未闭环
- 影响：不能按“生产可上线”口径放行
- 证据：
  - `test/QA_GATE_STATUS.md`
  - `prd/PRODUCTION_CHECKLIST.md`
- 当前状态：代码级通过，但真实共享预生产 Gate B 和生产 Gate C 仍未通过
- 建议：继续按 Gate B / Gate C 在真实共享环境复跑并留痕

### Important

#### I-01 newapi 平台入口未实现但仍可装配/启动 worker
- 影响：对外口径容易失真，误报为“平台已支持”
- 证据：
  - `internal/platformadapter/newapi_adapter.go:20-21`
  - `internal/app/app.go:129-130`
  - `internal/app/app.go:186-187`
- 建议：二选一收口
  1. 禁止未实现平台被注册/启动 worker
  2. 补完整 newapi ingress 实现与对等测试

#### I-02 平台启用状态与真实可用能力未统一建模
- 影响：未完成平台也可能启动 callback worker，形成半接通状态
- 证据：`internal/app/app.go:158-187`
- 建议：把 adapter 注册条件、worker 启动条件、入口可用条件收成同一门控

#### I-03 `callback_target` 契约与运行时行为不一致
- 影响：数据模型表达了能力，运行时并未支持，后续易造成静默错投或错误认知
- 证据：
  - event builder 写入 `callback_target`
  - `worker.go` 实际只使用 `Worker.CallbackURL`
- 建议：删除伪能力，或真正按 event target 路由

#### I-04 outbox 多实例并发投递风险未收口
- 影响：水平扩展时可能重复投递
- 证据：`internal/store/postgres/platform_event_store.go:78-86` 的 `ListDue` 仅查询，不做 claim / 锁定
- 建议：补 claim 机制、`FOR UPDATE SKIP LOCKED` 或显式限定单实例运行边界

#### I-05 严格事务外盒未成立
- 影响：业务主写成功但 outbox 写失败时，一致性不可保证
- 证据：业务处理与 `InsertPendingBatch` 不在同一事务中
- 建议：后续评估 transactional outbox 或明确记录一致性边界

#### I-06 sub2api callback E2E 已再次复现失败，说明链路存在现实不稳定性
- 影响：当前 `go test ./...` 不能稳定通过，代码级门禁不能再按稳定 PASS 对外汇报
- 证据：本轮复核再次在 `test/e2e/sub2api_callback_flow_test.go:186` 失败，实际出现 `reply.generated` 先于 `message.received`，并伴随 `sql: database is closed`
- 建议：先把该问题提升为当前优先闭环项，做定向稳定性定位与修复，再恢复代码级门禁口径

### Minor

#### M-01 旧 review 文档存在显著漂移
- 影响：继续引用会误导后续判断
- 典型文档：
  - `docs/CODE_REVIEW_REPORT.md`
  - `docs/PRODUCTION_EXECUTION_PLAN.md`
- 建议：以后续新报告和任务板为准，逐步回收旧结论

---

## 6. Gap Taxonomy Summary

| Gap Type | 具体表现 | 主责任方向 |
|---|---|---|
| design_gap | 平台启用 / 平台可用性门控未统一；多实例投递策略未正式定义 | TechLead |
| implementation_gap | newapi 入口未实现；callback_target 运行时未消费 | Engineer |
| test_gap | newapi 缺对等测试；sub2api callback E2E 已复现不稳定失败，需优先定位与修复 | QA / Engineer |
| evidence_gap | 真实共享预生产 / 灰度环境证据未闭环 | QA / DevOps |
| call_chain_gap | newapi 看似支持但入口未接通 | TechLead / Engineer |
| contract_gap | callback_target 字段与 worker 真实行为不一致 | TechLead |

---

## 7. 与旧报告的关系

### 7.1 可以继续保留的主结论
- 当前不能按“整体生产可上线”口径放行
- 代码级通过不等于预生产和生产放行通过
- 文档漂移仍需持续治理

### 7.2 必须回收的过期口径
- 旧版把若干已修复问题继续当作当前 P0
- 旧版把“无鉴权 / prod fallback / readiness 过宽”继续描述为当前代码事实
- 旧版若暗示“修完早期两个 P0 即可灰度”，现阶段已不再成立

### 7.3 新基线文件
后续应以以下文件作为当前基线：
- `docs/REVIEW_REPORT_2026-05-06.md`
- `docs/REMEDIATION_TASK_BOARD_2026-05-06.md`
- `test/QA_GATE_STATUS.md`
- `prd/PRODUCTION_CHECKLIST.md`

---

## 8. 后续执行建议

### 最短闭环顺序
1. 先定位并修复 `sub2api` callback E2E 不稳定失败，恢复 `go test ./...` 稳定通过能力
2. 收口平台能力矩阵
3. 收口平台启用 / worker 启动统一门控
4. 处理 newapi 假接通
5. 补 newapi 对等验证
6. 在共享预生产环境复跑 Gate B 并留痕
7. 在共享预生产 / 灰度环境补监控接线与回滚证据

### 对应任务板
- 详见：`docs/REMEDIATION_TASK_BOARD_2026-05-06.md`

---

## 9. 最终判定

**当前项目应被定义为：**

> **`go build ./...` 与 `go vet ./...` 当前通过，但 `go test ./...` 已再次实测失败，说明代码级门禁并不稳定；sub2api 单平台回调主链已可用，但仍带重要一致性/并发/稳定性风险；newapi 当前未通过；真实共享预生产与生产放行门禁未闭环，因此不能按“整体生产可上线”或“多平台已完成”口径汇报。**

正式门控结论：
- **代码级门禁：部分通过 / 当前不稳定**
- **sub2api 单平台主链：通过，但带重要风险且 E2E 当前不稳定**
- **newapi 平台能力：未通过**
- **真实共享预生产门禁：未通过**
- **生产放行门禁：未通过**
