Files
ai-customer-service/docs/RECTIFICATION_REVIEW_REPORT_V2.md
Your Name 142b991334 fix(config+app): production fail-fast + readiness收紧
1. config.go: AI_CS_ENV runtime mode with production restriction
   - New RuntimeConfig.Env field (AI_CS_ENV / AI_CS_RUNTIME_ENV)
   - production + Postgres.Enabled=false → Load() returns error
   - production + empty webhook secret → Load() returns error
   - normalizeRuntimeEnv: dev/dev/ → development, prod/production → production, test → test

2. app.go: probe.SetReady only when store is confirmed ready
   - Postgres.Enabled: probe.SetReady(true) after DB+migration OK
   - Memory mode: probe.SetReady(false) — not production-ready

3. health_handler_test.go: add probe live+ready state transition tests

4. config_test.go: add TestLoad_RejectsProdWhenPostgresDisabled,
   TestLoad_RejectsProdWhenWebhookSecretMissing

5. app_test.go: add TestNew_RejectsMemoryModeWithoutExplicitNonProdEnv,
   TestNew_AllowsMemoryModeInTestEnv, TestNew_WithPostgresEnabled_*
   for invalid DSN and migration-failure paths

Phase 1 (code gate) objectives met:
 prod cannot fall back to memory store
 readiness reflects actual store readiness
 both changes have test coverage
2026-05-04 07:38:10 +08:00

465 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ai-customer-service 整改版审查报告 v2
**角色框架:小龙 / PM / TechLead / QA / DevOps**
**审查目标:从“可跑通”提升到“生产可控、可灰度、可追责、不可默默降级”**
---
## 0. 阶段门控结论
**当前结论REQUEST_CHANGES**
**是否可直接按“生产已具备上线条件”放行:否**
### 当前真实状态
- **代码主链**:已基本打通
- **关键测试**:已实跑通过
- **生产落地控制**:仍有明显缺口
- **团队流程一致性**:存在文档漂移与门禁失真
### 本轮阻塞上线的核心原因
1. **默认允许 memory store 启动,存在生产级降级失控**
2. **readiness 不能证明“生产依赖已就绪”**
3. **QA / 上线文档与真实代码状态存在漂移**
4. **环境变量与部署文档口径不一致,存在实施误配风险**
5. **后台操作鉴权与运维级控制尚未形成完整闭环**
---
## 1. 本次复核依据与已验证证据
### 1.1 已实际读取的关键实现
重点核查:
- `internal/app/app.go`
- `internal/config/config.go`
- `internal/http/router.go`
- `internal/http/handlers/webhook_handler.go`
- `internal/http/handlers/webhook_security.go`
- `internal/http/handlers/health_handler.go`
- `internal/http/handlers/session_handler.go`
- `internal/http/handlers/ticket_handler.go`
- `internal/service/dialog/service.go`
- `internal/service/handoff/service.go`
- `internal/store/postgres/*`
- `internal/store/memory/*`
- `db/migration/0001_init.up.sql`
文档对照:
- `prd/PRODUCTION_CHECKLIST.md`
- `test/QA_GATE_STATUS.md`
### 1.2 已实际执行的验证
已通过 ASCII symlink 规避中文路径工具限制后执行:
```bash
go test -count=1 ./...
go test -count=1 ./test/e2e -run 'TestFullTicketFlow_E2E|TestSecurity_.*' -v
go test -count=1 ./test/integration -run 'TestHealthCheck_.*|TestDialogService_.*|TestTicketAssignResolve.*|TestSessionHandler.*' -v
```
### 实测结论
- 全仓测试通过
- 工单 E2E 主链通过
- Webhook 安全 E2E 通过
- Health/readiness 集成测试通过
- Session / Dialog / Ticket 关键集成测试通过
---
## 2. 审查后的总判断
### 2.1 已落实部分
#### A. 功能主链已存在
- webhook 收消息
- dialog 识别意图
- handoff 创建 ticket
- ticket assign / resolve / close / get
- stats / feedback / manual handoff 基本能力已落地
#### B. 基础安全入口已存在
- webhook HMAC
- timestamp 窗口校验
- dedup 幂等
- body limit
- rate limit
#### C. Postgres 持久化路径已接通
- `AI_CS_POSTGRES_ENABLED=true` 时走 postgres store
- migration 启动执行
- session / ticket / audit / dedup 均有 PG 实现
### 2.2 当前不能判定“生产可放心上线”的核心原因
#### A. 降级失控
**生产默认可退化为 memory store且服务仍能成功启动并 ready。**
#### B. readiness 语义过宽
**只能证明“进程能收请求”,不能证明“生产依赖与安全前置条件已满足”。**
#### C. 文档与代码状态漂移
**团队已有“测试失败/允许上线”等结论与当前代码真实状态不一致。**
#### D. 部署契约未收敛
**文档写的环境变量名与代码真实读取项不完全一致。**
#### E. 后台操作的真实性边界不足
**ticket / session 相关后台接口仍偏内网占位实现,缺少真正的操作鉴权闭环。**
---
## 3. 角色化整改方案
### 3.1 小龙CEO / 统筹者)整改责任
#### 核心问题
当前团队最大问题不是“没人干活”,而是:
- 修了代码但没同步门禁文档
- 跑通了链路但仍以“允许上线”模糊放行
- 角色产出没有被强制做事实校准
#### 小龙必须承担的整改动作
##### XL-P0-1建立“代码事实高于报告”的门禁
今后任何“已完成 / 可上线 / 已通过”的结论,必须满足:
1. 有实际文件证据
2. 有实际命令输出
3. 有当前版本时间点的校准
4. 有至少一次小龙抽样自验
##### XL-P0-2重写阶段状态口径
把当前项目阶段结论统一收敛成三层:
- **代码主链状态**
- **预生产验证状态**
- **生产上线状态**
禁止再用单句“允许上线”覆盖全部层次。
##### XL-P1-1强制角色交付模板
后续 PM / TechLead / QA / DevOps 输出必须固定带:
- 结论
- 证据
- 阻塞项
- 下一阶段条件
- 责任人
- 时间要求
##### XL-P1-2增加“实施漂移复核点”
每次关键修复后,小龙必须做 3 件事:
1. 复跑最小必要测试
2. 复核关键配置契约
3. 更新门禁文档状态
#### 小龙验收标准
- [ ] 所有“完成/通过”结论都有命令或文件证据
- [ ] 文档状态与当前代码状态一致
- [ ] 不再使用“允许上线”作为模糊总括结论
- [ ] 每个整改项都有明确责任角色和验收人
### 3.2 PM产品经理整改责任
#### 当前 PM 问题
不是没有文档,而是**文档覆盖面和交付口径不够硬**
- 上线检查项有,但和代码契约未完全对齐
- 对“Phase1 可上线”表述偏乐观
- 对“dev fallback 与 prod 要求差异”没有明确写成产品/交付边界
- 对“上线前必须真实环境验证”的门槛定义不够强
#### PM 必须承担的整改动作
##### PM-P0-1修正文档中的上线口径
将现有文档中的“允许上线”改成分层表述:
- 代码级门禁通过
- 仓库内测试门禁通过
- 真实环境门禁未闭环
- 仅允许进入预生产/灰度准备
##### PM-P0-2补“运行模式约束”
在 PRD / checklist / status 中明确写入:
- `memory mode` 仅用于开发 / 测试
- `prod` 环境不允许无持久化运行
- 若缺少 DB / secret / 关键依赖,系统应 fail-fast不得 silent degrade
##### PM-P1-1补齐“上线运营口径与观察指标”
新增明确观察项:
- 工单创建量是否异常偏低/偏高
- handoff 比率是否异常
- audit 写入是否持续
- dedup 是否稳定
- readiness 是否真实反映依赖状态
- 实例重启后数据是否仍在
##### PM-P1-2统一环境变量文档契约
所有面向部署的文档,必须统一写成代码真实读取的变量名,例如:
- `AI_CS_POSTGRES_ENABLED`
- `AI_CS_POSTGRES_DSN`
- `AI_CS_POSTGRES_MIGRATION_DIR`
- `AI_CS_WEBHOOK_SECRET`
- `AI_CS_WEBHOOK_MAX_SKEW_SECONDS`
禁止再用泛化口径替代真实配置契约。
#### PM 验收标准
- [ ] 文档中不再出现“仅凭仓库内测试即可认定生产可上线”的表述
- [ ] 文档中的环境变量名与 `config.go` 完全一致
- [ ] 明确区分 dev/test 与 prod 运行要求
- [ ] 上线观察指标、失败判定线、回滚触发条件都已写清
### 3.3 TechLead技术经理整改责任
#### 当前 TechLead 问题
TechLead 已把主链做起来,但**没有把“生产默认安全”做成系统约束**。
#### 必须整改的技术项
##### TL-P0-1禁止生产默认退化到 memory store
目标:
- 生产模式下,不允许 `Postgres.Enabled=false` 仍正常启动
建议实现方向:
1. 增加运行模式,例如:
- `AI_CS_RUNTIME_MODE=dev|test|prod`
2.`prod` 模式下强制校验:
- `AI_CS_POSTGRES_ENABLED=true`
- `AI_CS_POSTGRES_DSN` 非空
- migration dir 可用
3. 不满足则 `app.New()` 直接返回错误
**验收标准**
- [ ] prod 下未启用 Postgres 时服务启动失败
- [ ] 错误信息明确说明缺失项
- [ ] 有对应测试覆盖
##### TL-P0-2收紧 readiness 语义
当前 `probe.SetReady(true)` 太早,必须改。
建议:
- 启动完成后不直接 ready
- ready 的条件至少包含:
- DB 已连接
- migration 已成功
- 关键配置已完整
- 运行模式合法
- 如启用 webhook auth则 secret 已配置
可选策略:
- `health` 保持诊断信息
- `ready` 专门作为流量门禁
**验收标准**
- [ ] 缺 DB / 缺 secret / 缺关键配置时 ready=DOWN
- [ ] ready 不再仅因为进程启动成功就返回 UP
- [ ] 有集成测试覆盖关键失败场景
##### TL-P0-3统一配置契约与部署文档
TechLead 要输出一份**代码视角的配置契约基线**,作为 PM / DevOps / QA 的唯一来源。
至少包括:
- 变量名
- 默认值
- 是否允许默认值出现在 prod
- 是否阻断启动
- 对应组件
- 风险等级
示例字段:
- `AI_CS_POSTGRES_ENABLED`
- `AI_CS_POSTGRES_DSN`
- `AI_CS_POSTGRES_MIGRATION_DIR`
- `AI_CS_WEBHOOK_SECRET`
- `AI_CS_MAX_BODY_BYTES`
**验收标准**
- [ ] 有单独配置契约表
- [ ]`config.go` 实际实现一致
- [ ] 明确哪些默认值仅限 dev/test
##### TL-P1-1补后台接口鉴权设计
当前:
- `actor_id` 主要来自 query param
- 更接近内部占位实现,而不是正式后台控制面接口
需明确:
- 是仅内网可调
- 还是后台服务调用
- 还是运营台使用
- 对应认证方式是什么
至少补设计:
- 内部 token / service auth / gateway auth
- 操作审计字段真实性
- actor 来源不可伪造
**验收标准**
- [ ] ticket/session 后台接口有明确 auth 模式
- [ ] actor_id 不再只是前端随便传
- [ ] 权限边界写入设计文档
##### TL-P1-2补多实例与恢复场景验证设计
需要明确验证:
- dedup 在多实例下是否稳定
- ticket / session / audit 在重启后是否一致
- migration 重复执行是否幂等
- 故障恢复后 ready 恢复逻辑是否正确
### 3.4 QA质量经理整改责任
#### 当前 QA 问题
QA 不是没工作,而是**结论闭环不够硬**
- 文档中存在过时结论
- “允许上线”没有严格区分代码门禁与生产门禁
- 没把“memory fallback 风险”上升为真正阻断项
#### QA 必须承担的整改动作
##### QA-P0-1重做上线门禁文档
重写 `QA_GATE_STATUS`,按以下结构:
1. 当前代码事实
2. 实测命令
3. 通过项
4. 未通过项
5. 文档漂移项
6. 生产阻断项
7. 下一阶段建议结论
必须明确区分:
- **仓库内验证通过**
- **真实环境未验证**
- **生产阻断未解除**
##### QA-P0-2把“降级失控”列为 Critical
以下情形必须判定为 Critical
- prod 可在 memory mode 启动
- ready 不能区分关键依赖缺失
- 部署文档与配置契约不一致
- 文档已允许上线,但真实环境门禁未验证
##### QA-P1-1建立“文档漂移检测”检查项
今后每次 QA 审查必须加一栏:
- 代码状态 vs status 文档是否一致
- 测试状态 vs 报告状态是否一致
- 配置项 vs checklist 是否一致
##### QA-P1-2增加真实环境前置门禁
上线前 QA 必须强制检查:
- 使用真实环境变量启动一次
- ready / health 返回符合预期
- Postgres migration 执行成功
- webhook 签名真实联调成功
- audit / ticket 实际入库成功
#### QA 验收标准
- [ ] QA 报告明确区分代码门禁 / 生产门禁
- [ ] 文档漂移项被单独列出
- [ ] memory fallback 风险被列为 Critical 直到修复
- [ ] 不再用“允许上线”掩盖真实环境未验证
### 3.5 DevOps运维 / SRE整改责任
#### 当前 DevOps 问题
仓库中有上线清单,但还不是实际运维闭环。
#### DevOps 必须承担的整改动作
##### DO-P0-1形成真实部署基线
需要明确:
- 启动命令
- 必填环境变量
- secret 注入方式
- Postgres 连通性检查
- migration 执行方式
- readiness / liveness 探针路径
- 灰度方式
- 回滚方式
##### DO-P0-2把“关键配置缺失即启动失败”纳入部署标准
即使代码修完,部署侧也要加保护:
- 若 prod 缺少 `AI_CS_POSTGRES_DSN` / `AI_CS_WEBHOOK_SECRET`
- CI/CD 或启动脚本应直接 fail
##### DO-P1-1补监控与告警
最少补这些:
- 5xx rate
- webhook reject rate
- handoff rate
- ticket create rate
- audit write error
- DB connect / migration error
- ready down duration
##### DO-P1-2补 runbook
必须有:
- 启动失败排查
- migration 失败回滚
- DB 不可用处理
- webhook auth 失败联调
- 实例重启后数据一致性检查
#### DevOps 验收标准
- [ ] 有真实部署基线文档
- [ ] prod 关键配置缺失时不会“假成功启动”
- [ ] 有最小监控告警集
- [ ] 有回滚与故障 runbook
---
## 4. P0 / P1 / P2 总整治清单
### P0上线前必须完成
1. **禁止 prod 退化为 memory mode**
2. **收紧 readiness改成真实依赖门禁**
3. **修正文档:状态、测试、环境变量口径统一**
4. **QA 重做门禁结论,撤销过宽“允许上线”表述**
5. **建立部署侧关键配置 fail-fast 机制**
### P1灰度前应完成
1. 后台操作接口鉴权边界明确
2. 真实环境 DB / migration / webhook 联调
3. 监控告警最小闭环
4. 文档漂移检测纳入 QA 常规项
5. runbook 与回滚路径补齐
### P2全量上线后持续补
1. 更完整威胁建模
2. 多实例一致性与恢复测试
3. store/app 层覆盖率继续补齐
4. 敏感字段脱敏、审计治理、保留策略完善
5. 更细粒度容量与可观测性建设
---
## 5. 整改后阶段门禁定义
### Gate A代码级通过
满足:
- 主链测试通过
- 安全测试通过
- prod 不允许 memory fallback
- readiness 逻辑收紧
- 配置契约与代码一致
### Gate B预生产通过
满足:
- 真实 Postgres 联通
- migration 成功
- webhook 签名联调成功
- audit / ticket 入库成功
- ready / live 行为符合预期
- 最小监控已接通
### Gate C生产灰度通过
满足:
- 5% 灰度稳定
- handoff / ticket / audit 指标正常
- 无异常 5xx / reject 激增
- 回滚演练已通过
---
## 6. 最终整改版结论
**ai-customer-service 当前应被定义为:**
**“代码主链可用,适合进入生产整改与预生产验证阶段;但尚不应被标记为生产可直接放心上线。”**
更准确地说:
- **不是没做成**
- **也不是 demo 空壳**
- **但现在离生产级放心放量,还差最后一层关键控制:禁止隐式降级、收紧 readiness、统一配置契约、修正文档漂移、补部署门禁。**