11 KiB
11 KiB
QA 设计审查报告:Gateway 收口(2026-05-08)
阶段门控结论:REQUEST_CHANGES 是否可进入 Engineer 实现:否
审查范围
- PM 收口文档:/home/long/project/supply-intelligence/prd/PM_GATEWAY_CLOSURE_PRD_2026-05-08.md
- TechLead 设计:/home/long/project/supply-intelligence/tech/TECHLEAD_GATEWAY_CLOSURE_DESIGN_2026-05-08.md
- 真源索引:/home/long/project/supply-intelligence/tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md
- 消费闭环决议:/home/long/project/supply-intelligence/tech/GATEWAY_CONSUMER_DECISION_2026-05.md
- 收口执行板:/home/long/project/supply-intelligence/tech/PRODUCTION_LAUNCH_CLOSURE_BOARD_2026-05-08.md
- 真实代码链路抽检:
- /home/long/project/supply-intelligence/internal/httpapi/server.go
- /home/long/project/supply-intelligence/internal/gatewayconsumer/service.go
- /home/long/project/supply-intelligence/internal/poller/gateway_package_poller.go
- /home/long/project/supply-intelligence/internal/poller/runtime.go
- /home/long/project/supply-intelligence/internal/publish/service.go
- /home/long/project/supply-intelligence/internal/repository/interfaces.go
- /home/long/project/supply-intelligence/internal/repository/postgres.go
- /home/long/project/supply-intelligence/internal/metrics/metrics.go
- /home/long/project/supply-intelligence/internal/app/app.go
- /home/long/project/supply-intelligence/internal/httpapi/postgres_e2e_test.go
设计覆盖检查
- 契约边界:已覆盖
- PM/TechLead 均明确了 published != applied、pending/applied/failed 语义。
- 证据:PM 文档 4.2/4.3;TechLead 文档 2.2/2.3。
- 失败重试:部分覆盖,未闭合
- PM 定义了可重试/不可重试、3 次上限、退避窗口。
- TechLead 也识别出现有代码缺少重试元数据和重试结构。
- 但设计仍停留在建议层,未与现有接口/表结构形成可执行的最小实现闭环。
- 证据:TechLead 3.2~3.7。
- 灰度/回滚:部分覆盖,缺少可执行入口
- PM 给出暂停/回滚判定线。
- TechLead 提出 runbook 脚本与 runtime pause/resume API 建议。
- 但当前真实代码没有 runtime-status/pause/resume 入口,也没有脚本文件。
- 证据:server.go 仅有 /gateway/consume-once 和 health/metrics 等路径;未见 runtime control 路由。
- 巡检门禁:部分覆盖,缺少真实指标接入
- 文档定义了 24h/72h 巡检项。
- 但 metrics.go 只是声明指标,调用链中没有任何实际打点。
- 证据:metrics.go;全文搜索未命中 GatewayEventsProcessedTotal / GatewayEventLatencySeconds 的使用点。
风险与保护检查
-
风险 1:发布完成与消费完成仍可被误判
- 保护:admission-state 暴露 last_event.gateway_sync_status,且 E2E 覆盖 publish -> consume -> ack。
- 缺口:failed 重试后如何重新进入自动消费未实现。
-
风险 2:失败分类不足导致重试/终态策略无法落地
- 保护:文档已定义失败分类模型和上限。
- 缺口:代码层无 retry_count / next_retry_at / failure_category 持久化字段,无对应 repository 方法。
-
风险 3:无法暂停放量或受控回滚
- 保护:poller/runtime 已有 Start/Stop。
- 缺口:没有 pause/resume 或 runtime-status,Stop 是进程级粗粒度停机,不符合 runbook 设计要求。
-
风险 4:观测不可执行
- 保护:/metrics 存在。
- 缺口:指标未接调用链,无法支撑“15 分钟 applied 比例 < 95%”等门禁判断。
交接物可用性
- 可用:
- 发布、拉取、ack、admission-state 的基础闭环存在。
- 真实代码路径可定位,且有 PostgreSQL E2E 证明基本链路。
- 不足:
- 缺少可执行 runbook 文件。
- 缺少桌面演练 / 巡检 / 回滚脚本。
- 缺少 runtime 控制接口。
- 缺少重试状态持久化与失败分类存储。
关键调用链路核查(定义 / 装配 / 调用 / 入口)
链路 A:package 发布
- 定义:/home/long/project/supply-intelligence/internal/publish/service.go
- PublishDraft / RecordPackagePublished
- 装配:/home/long/project/supply-intelligence/internal/app/app.go
- buildApp() 注入 publish.NewService(repo)
- 调用:/home/long/project/supply-intelligence/internal/httpapi/server.go
- handlePublishPackageEvent() -> publishService.PublishDraft(...)
- 入口:/home/long/project/supply-intelligence/internal/httpapi/server.go
- Route: POST /internal/supply-intelligence/publish/package-event
- 结论:已闭合
链路 B:package changes 拉取
- 定义:/home/long/project/supply-intelligence/internal/repository/interfaces.go
- ListPackageEventsAfter
- 装配:/home/long/project/supply-intelligence/internal/app/app.go
- gatewayconsumer.NewService(repo)
- 调用:/home/long/project/supply-intelligence/internal/httpapi/server.go
- handleListPackageChanges() -> repo.ListPackageEventsAfter(...)
- gatewayconsumer.Service.ConsumeOnce() -> repo.ListPackageEventsAfter(...)
- 入口:/internal/supply-intelligence/gateway/package-changes
- 结论:已闭合,但仅支持 cursor 流读取,不支持 retry due filtering
链路 C:ack 回写
- 定义:/home/long/project/supply-intelligence/internal/repository/interfaces.go
- AckPackageEvent
- 装配:/home/long/project/supply-intelligence/internal/app/app.go
- gatewayconsumer.NewService(repo)
- 调用:/home/long/project/supply-intelligence/internal/httpapi/server.go::handleAckPackageChange
- repo.AckPackageEvent(...)
- /home/long/project/supply-intelligence/internal/gatewayconsumer/service.go::ConsumeOnce
- repo.AckPackageEvent(...)
- 入口:POST /internal/supply-intelligence/gateway/package-changes/{event_id}/ack
- 结论:已闭合
链路 D:默认消费方与 poller/runtime
- 定义:/home/long/project/supply-intelligence/internal/gatewayconsumer/service.go::ConsumeOnce
- 装配:/home/long/project/supply-intelligence/internal/app/app.go
- NewGatewayPackagePoller(gatewayConsumerService)
- NewRuntime(gatewayPoller, time.Second)
- 调用:/home/long/project/supply-intelligence/internal/poller/gateway_package_poller.go::PollOnce
- p.consumer.ConsumeOnce(...)
- 入口:/home/long/project/supply-intelligence/internal/poller/runtime.go::Start
- 周期定时触发 PollOnce
- 结论:已闭合,但运行时只能 start/stop,不能按 runbook 语义暂停/恢复
链路 E:admission-state
- 定义:/home/long/project/supply-intelligence/internal/httpapi/server.go::handleModelAdmissionState
- 装配:/home/long/project/supply-intelligence/internal/app/app.go
- 调用:server.go 内直接读取 repo.GetLatestDiscoveryCandidateContext / GetSupplyPackage / GetLatestPackageEvent
- 入口:GET /internal/supply-intelligence/models/{platform}/{model}/admission-state
- 结论:已闭合,适合作为发布后状态核验入口
问题清单
Critical
- 缺少重试状态机的真实持久化与调度闭环
- 证据:tech/TECHLEAD_GATEWAY_CLOSURE_DESIGN_2026-05-08.md 3.2~3.7 仅为建议;internal/repository/interfaces.go 仅有 AckPackageEvent,没有 retry_count/next_retry_at/get retryable pending 接口;internal/repository/postgres.go AckPackageEvent 只更新 ack_status/consumer/detail/time。
- 影响:PM 定义的 3 次自动重试、退避、终态 failed 无法按设计执行。
- 结论:阻断进入实现。
- 缺少可执行的灰度/回滚运行时控制入口
- 证据:server.go Routes 未暴露 runtime-status/pause/resume;runtime.go 仅有 Start/Stop;app.go 仅在启动时自动 StartBackground。
- 影响:无法按 PM 要求执行“暂停放量但不立即回滚”“受控恢复”等门禁动作。
- 结论:阻断进入实现。
- 观测指标未接入真实调用链
- 证据:internal/metrics/metrics.go 声明了 GatewayEventsProcessedTotal/GatewayEventLatencySeconds/AccountsByStatus/RoutingEnabledAccounts;全文搜索未命中这些指标的实际使用点。
- 影响:无法验证 15 分钟 applied 比例、重试积压、失败趋势等关键门禁。
- 结论:阻断进入实现。
Important
- 失败分类模型未落地到 repository/domain
- 证据:TechLead 3.3 仅建议新增 failure category 枚举;当前 domain/repository 未见对应字段或接口。
- 影响:retryable/non-retryable 分流只能靠 consumer 内部临时判断,无法审计与追踪。
- 已失败事件缺少再次进入自动重试的机制
- 证据:TechLead 2.4 指出 ListPackageEventsAfter 会返回 failed 事件,但 consumer 仅消费 pending;gatewayconsumer/service.go 124-126 明确跳过 non-pending。
- 影响:failed 一旦写回后不可恢复自动重试,和 PM 的“人工处置入口/受控重试”设计不一致。
- runbook 依赖脚本文件但仓库中未见对应交付物
- 证据:TechLead 4.2 建议新增 scripts/gateway_closure_smoke.sh / inspect.sh / rollback.sh 和 runbook 文档;当前未发现这些文件。
- 影响:交接物不可直接执行,只能纸面审查。
- PM 文档中的 24h/72h 巡检指标部分仍偏结果导向,缺少来源字段定义
- 证据:PM 7.1/7.2 仅描述“持续增长/稳定/是否出现”,未绑定具体采样接口与阈值归属。
- 影响:QA 与 Engineer 容易产生不同解释。
Minor
- 真源索引文件路径存在历史仓库前缀表述差异
- 证据:/home/long/project/supply-intelligence/tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md 第 5 行出现“/home/long/project/立交桥/projects/supply-intelligence/”。
- 影响:容易造成阅读者路径混淆。
- TechLead 文档中提议的指标命名与现有 metrics 命名风格不完全一致
- 证据:3.2/5.2 建议使用 supply_intelligence_gateway_* 命名;现有 metrics 已有 supply_intelligence_ 前缀但具体标签规划未统一。
- 影响:实现时需统一命名规范,避免重复与歧义。
Gap Taxonomy Summary
- Contract gap:published/pending/applied/failed 语义已定义,但 retry/终态语义未形成代码闭环。
- Execution gap:灰度、暂停、回滚需要 runtime control 与脚本,当前只有基础 Start/Stop。
- Observability gap:指标声明存在,实际打点不存在。
- Data-model gap:缺少 retry_count、next_retry_at、failure_category 等字段。
- Operational gap:runbook 交付物缺失,无法直接演练。
- Verification gap:有 E2E 证明基础闭环,但没有覆盖失败重试/回滚/巡检门禁的实证。
最终门禁结论
- 设计覆盖:部分通过
- 风险保护:不足
- 交接可用性:不足
- 阶段门控结论:REQUEST_CHANGES
- 是否可进入 Engineer 实现:否
备注
本次审查已抽样核查真实调用链,不是仅基于文档判断;但由于重试、runtime control、observability 三条主链仍未在代码层闭合,因此不能给 APPROVED。