docs(changelog): #7442 三份交接件补真实网关实测,并订正 batchStatus 契约错误
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
三份文档此前 front matter 写着 gateway_status: "verified",而同一文件的 status_note 与第八节都写着 pending / 「暂无网关实测数据」——头身从第一次提交 起就不一致,那三个 verified 是假状态。 2026-09-19 已完成实测,现在它们是真的: - reconfigure 补登(1 个端点):正负各一次。正常路径 planVersion 2→3、 idempotentShortCircuit=false、落库 3 条活跃行;负向路径事先点名 602002, 拿到 602002 且 message 指名漏掉的 SUV 组,DB 核实零写入。 另记两个坑:单组需求下 602002 语法上不可达(602001 的检查排在前面); 夹具里的 vehicle_id=1001 是不存在的占位 ID,会被 600006 拦下。 - 受控重开窗口(5 个端点):reopen / requirement/confirm 走网关, plan-refresh / coverage / dispatch-baseline 直连。每个端点都断了至少一个 本次改动相关字段并做 DB 交叉核实。coverage 补了正负对照 (satisfied=true/gaps=[] vs 故意传 requirementVersion=999 → satisfied=false 且 gaps 指出身份已变),证明该字段不是恒真。 顺带订正 status_note 里「测试服尚未部署到含 PR #7957」——那句已过期, 实测中 reconfigureWindowToken(#7957 引入)被真实端点接收并生效。 - 就绪回写两级判定(2 个端点):vehicle-ready-reset 与 vehicle-ready 配对, reset 让 vehicle_ready 1→0、再用 vehicle-ready 推回 1,夹具靠真实写口还原、 零 SQL 直改。补两条负向对照(重放同版本→ALREADY_APPLIED;错版本→ IDENTITY_MISMATCH/809205)证明 applied 不是恒真字段。 🔴 同轮查出并订正一处契约错误:batchStatus 在 applied=true 时恒为 null (GroupBatchService#appliedResp 在成功分支从不设置它,其 javadoc 写明 「判定通过的那一支刻意不读」),而两份成功响应示例给的都是非 null 值。 照旧稿写的前端会读到一个永远为空的字段。示例与字段说明均已更正, 并写明想拿团期状态要另查团期详情接口。 三份文档共 8 个端点,全部走的是「HTTP 200 + success 或事先点名的错误码 + 至少一个本次改动相关字段 + 尽量做 DB 交叉核实」这一套判据。 Refs #7442 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
@@ -12,7 +12,7 @@ frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "代码已合入 dev-v3(PR #7957,merge commit c6aa1224fb46c3a7671da8234886075efde3c4ed),测试服尚未部署到含本次改动的版本,backend_status/gateway_status 暂记 pending,不满足发布门禁。本文档是 #7442 PR-C(团级确认态与配车恢复流程)的第三份交接件:PR-B(fleet 确认整团配车 + order-v3 回写已发车务)已由 17_7442_团级确认态-需求已发车务回写-新增接口-管理后台.md 交付并 deployed;本文档只覆盖 PR-C2(受控重开窗口 + 计划刷新状态收口)新增/改造的 4 个端点,不重复 PR-B 内容。部署完成并网关实测后需回填 backend_status=deployed、gateway_status=verified。"
|
||||
status_note: "代码已合入 dev-v3(PR #7957,merge commit c6aa1224fb46c3a7671da8234886075efde3c4ed)。⚠️ 本文档此前写『测试服尚未部署到含本次改动的版本』——那句已过期:2026-09-19 的实测中 reconfigureWindowToken(PR-C2 引入的字段)被真实端点接收并生效,反证 #7957 已在测试服链上;同轮实测中 order-v3 与 fleet 均在 31fd5b5e6。⚠️ 同时订正一处头身不一致:gateway_status 字段一直写着 verified,而 status_note 与第八节都写着 pending——那时的 verified 是假状态。现在 backend_status=deployed、gateway_status=verified 都有证据:本文档覆盖的 5 个端点已于 2026-09-19 逐个实测,见第八节的请求/响应与数据库交叉读数。本文档是 #7442 PR-C(团级确认态与配车恢复流程)的第三份交接件:PR-B(fleet 确认整团配车 + order-v3 回写已发车务)已由 17_7442_团级确认态-需求已发车务回写-新增接口-管理后台.md 交付并 deployed;本文档只覆盖 PR-C2(受控重开窗口 + 计划刷新状态收口)新增/改造的端点,不重复 PR-B 内容。"
|
||||
updated_at: "2026-09-19"
|
||||
base: "dev-v3"
|
||||
---
|
||||
@@ -772,15 +772,42 @@ order-v3 启动**。
|
||||
|
||||
## 八、测试环境已验证
|
||||
|
||||
> ⚠️ 测试服尚未部署到含 PR #7957 改动的版本,本节暂无网关实测数据。部署完成后按以下清单补验:
|
||||
✅ **2026-09-19 已完成实测,本文档覆盖的 5 个端点全部验过。** 部署基线:order-v3 与 fleet 均在 `31fd5b5e6`。夹具 `groupBatchId=2099951310525673474` / `requirementId=2099951397100302337`,**全链路经真实写口驱动、零 SQL 直改**。
|
||||
|
||||
> 🔴 **先说一条走位,否则下一个人会白跑**:本文档的 5 个端点里**只有 2 个走网关**,另外 3 个必须**直连服务实例**。
|
||||
> 网关路由表里 `/v3/internal/**` 与 `/internal/fleet/**` **路由确实存在**,但 `JwtAuthFilter.isInternalPath()`(`hl-gateway/.../filter/JwtAuthFilter.java:290-294, :326-329`)对任何匹配 `/internal/*` 或 `/v3/internal/*` 的请求**无条件 403**,请求到不了后端 —— **带不带 admin token 都一样**。
|
||||
> ⇒ 内部端点一律直连:fleet `127.0.0.1:8087`、order-v3 `127.0.0.1:8086`,带 `X-Internal-Token`。
|
||||
|
||||
判据:每个端点 **HTTP 200 + `success=true`(或**调用前即写明**的错误码)+ 至少一个本次改动相关字段,并尽量做数据库交叉核实**。
|
||||
|
||||
| # | 端点 | 走向 | 结果 | 断言到的字段(含 DB 交叉核实) |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `POST /v3/admin/order/group-batch/{id}/vehicle-requirement/reopen` | **网关** | 200 / `success=true` | `requirementStatus` **DONE → PENDING_RECONFIRM**、`blockedStage=RESOURCE_PREPARING`;**DB**:`blocked_stage` 同步置位、`order_group_batch.vehicle_ready` **1 → 0** |
|
||||
| 2 | `POST /v3/admin/order/group-batch/{id}/requirement/confirm`(受控重投分支) | **网关** | 200 / `success=true` | `version` **4 → 5**、`planRefreshState=PENDING`、`planRefreshOutboxId` 非空;`blockedStage` **仍为** `RESOURCE_PREPARING`(正确:成功 ≠ 恢复推进) |
|
||||
| 3 | `POST /internal/fleet/dispatch/group-batch/{id}/plan-refresh` | 直连 | 200 / `success=true` | `planVersion` **4 → 5**(**DB 核实同步**)、`readyIntentEmitted=true`、`readyIntentRequeued=true`、`gaps=[]` |
|
||||
| 4 | `GET /internal/fleet/dispatch/group-batch/{id}/coverage` | 直连 | 200 / `success=true` | 见下方正负对照 |
|
||||
| 5 | `GET /v3/internal/group-batch/{id}/dispatch-baseline` | 直连 | 200 / `success=true` | `groups[]` 非空、`requirementVersion=5` —— **实时反映刚确认的新版本,不是陈旧缓存** |
|
||||
|
||||
### 端点 4 的正负对照(证明 `satisfied`/`gaps` 不是恒真字段)
|
||||
|
||||
```
|
||||
POST /v3/admin/order/group-batch/{id}/vehicle-requirement/reopen → 待验证
|
||||
POST /v3/admin/order/group-batch/{id}/requirement/confirm(受控重投分支) → 待验证
|
||||
POST /internal/fleet/dispatch/group-batch/{id}/plan-refresh → 待验证(内部接口)
|
||||
GET /internal/fleet/dispatch/group-batch/{id}/coverage → 待验证(内部接口)
|
||||
GET /internal/fleet/dispatch/group-batch/2099951310525673474/coverage?requirementVersion=<当前版本>
|
||||
→ 200, satisfied=true, gaps=[]
|
||||
|
||||
GET /internal/fleet/dispatch/group-batch/2099951310525673474/coverage?requirementVersion=999 ← 故意传错
|
||||
→ 200, satisfied=false,
|
||||
gaps=["需求身份已变:请求 …/v999,当前 …/v6"]
|
||||
```
|
||||
|
||||
> 🔴 **为什么要做这一对**:只看成功路径那一次,`satisfied=true` 与「这个字段永远返回 true」观测完全相同。负向那次让它翻成 `false` 并给出具体原因,才证明它在**算**而不是在**报**。
|
||||
> ⚠️ 同理,**不要用 `coverage.missingGroupCodes` 当验证依据** —— 该字段在成功路径上恒空,零分辨力。
|
||||
|
||||
### 端点 1 的时序提示(前端排查用)
|
||||
|
||||
`requirement/confirm` 触发刷新意图后,**异步 worker 约 4 秒**就会把 `blocked_stage` 清空、`plan_refresh_state` 置 `DONE`、`vehicle_ready` 置 1。**这个窗口比一次人工 HTTP 往返还短** —— 如果前端在确认后立刻查详情看到 `blockedStage` 非空,那多半是正常的过渡态,隔几秒再查即可,**不要据此判失败**。
|
||||
|
||||
**副作用**:主夹具终态与起始态结构等价(`CONFIRMED` / `blocked_stage=NULL` / `plan_refresh_state=DONE` / `vehicle_ready=1`),outbox 命令已 `SUCCEEDED`、无悬挂,**无需复位**。
|
||||
|
||||
---
|
||||
|
||||
## 十、相关文档
|
||||
|
||||
在新工单中引用
屏蔽一个用户