docs(javaTest): plan dispatch completion audit
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
# javaTest 调度闭环完成审计实施计划
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 在不改变已确认的历史字段和中心选车语义的前提下,补齐路线输入安全、反向活动冲突和历史调度边界的可执行证据,并完成全量验收。
|
||||
|
||||
**Architecture:** 保留 `RouteCandidatePlanner` 负责地图候选、`RouteQualityEvaluator` 负责同一交通快照下的字典序质量、`HistoricalDispatchSimulator` 负责真实业务闭环。新增约束集中在质量评价入口;新增业务测试使用小型 `HistoricalSimulationInput` 夹具,避免修改 240 条真实历史基线。报告和页面只验证 Java 已产生的证据,不在前端复制算法。
|
||||
|
||||
**Tech Stack:** Java 8、Maven Surefire、JUnit 5、Jackson、现有 vanilla HTML/JavaScript、Playwright 浏览器 QA。
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- 历史 `path_info` 不得作为新规划输入。
|
||||
- 历史 `agv_id` 不得强制绑定车辆。
|
||||
- `finish_date` 和历史完成状态不得推进仿真完成。
|
||||
- 路线质量不使用故障或等待时间。
|
||||
- 临时冲突必须 HOLD;只有永久地图不可达才 `NO_ROUTE` 失效关闭。
|
||||
- 所有修改限制在 `javaTest`、本审计设计/计划文档和本轮新增测试;保留用户已有 `docs/*.html`。
|
||||
- Java 编译目标保持 8,不新增生产依赖。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 锁定路线评价输入和反向活动冲突
|
||||
|
||||
**Files:**
|
||||
- Modify: `javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficRouteSnapshot.java`
|
||||
- Modify: `javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluator.java`
|
||||
- Modify: `javaTest/src/test/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluatorTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- `TrafficRouteSnapshot` 新增包内查询 `hasOppositeActiveRoute(String from, String to, String taskId)`。
|
||||
- `RouteQualityEvaluator.evaluate(...)` 继续返回 `RouteQuality`;非法节点、非邻接边或距离不一致时抛 `IllegalArgumentException`。
|
||||
|
||||
- [ ] **Step 1: 写失败测试**
|
||||
|
||||
增加三个测试:活动路线 `D -> B -> A` 对候选 `A -> B -> D` 计入对向冲突;候选包含未知站点或断边时被拒绝;候选声明距离与地图距离不一致时被拒绝。现有同向活动路线仍只计重合,不重复计对向。
|
||||
|
||||
- [ ] **Step 2: 运行 RED**
|
||||
|
||||
```bash
|
||||
mvn -f javaTest/pom.xml -Dtest=RouteQualityEvaluatorTest test
|
||||
```
|
||||
|
||||
预期新增断言失败或编译失败,证明测试没有被旧实现意外满足。
|
||||
|
||||
- [ ] **Step 3: 实现最小修复**
|
||||
|
||||
在快照中遍历其他活动路线的有向相邻边,只有 `to -> from` 命中时返回对向;在评价入口调用 `RouteCandidatePlanner.pathDistance(map, path)` 校验路径连续性和距离,使用数值容差 `1e-6`,再执行现有质量元组计算。对已识别的对向边跳过不兼容预约重复计数。
|
||||
|
||||
- [ ] **Step 4: 运行 GREEN**
|
||||
|
||||
```bash
|
||||
mvn -f javaTest/pom.xml -Dtest=RouteQualityEvaluatorTest,RouteCandidatePlannerTest test
|
||||
```
|
||||
|
||||
预期所有路线单测通过,并保留原有确定性、110%边界和候选上限行为。
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficRouteSnapshot.java javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluator.java javaTest/src/test/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluatorTest.java
|
||||
git commit -m "fix(javaTest): validate route quality inputs"
|
||||
```
|
||||
|
||||
### Task 2: 补齐真实调度边界集成测试
|
||||
|
||||
**Files:**
|
||||
- Modify: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java`
|
||||
- Modify: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationTaskQueueTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- 不新增生产 API;测试通过现有 `HistoricalSimulationInput`、`SimulationConfig` 和 `HistoricalDispatchSimulator.simulate(...)` 验证业务闭环。
|
||||
|
||||
- [ ] **Step 1: 写未来到达与优先级测试**
|
||||
|
||||
构造两个站点路线和两条任务:低优先级任务在 `t=0` 到达,高优先级任务在仿真时间 `t=5000` 到达。断言 `t<5000` 的事件中不存在高优先级任务 `ASSIGN`,任务到达后它按优先级先获得 `ASSIGN`;另保留队列 aging 单测证明长期低优先级任务不会饥饿。
|
||||
|
||||
- [ ] **Step 2: 写无路失效关闭测试**
|
||||
|
||||
构造已知但被 `GridMap.block(target)` 永久阻断的服务目标,运行模拟并断言该任务为 `FAILED`、reason=`NO_ROUTE`、无 `ASSIGN`/`COMPLETE`,且结果数量仍保持闭环。对未知站点输入继续由 normalizer 形成 `HistoricalDispatchFailure`,断言同样进入明确失败结果而不是等待。
|
||||
|
||||
- [ ] **Step 3: 写 PLC 重试边界测试**
|
||||
|
||||
使用现有 `DeterministicFaultPlan` 注入一次 `SEND_FAILURE`,断言任务保持未移动并在后续 tick 产生 `PLC_RETRY`;使用重试上限夹具验证超过上限时 reason 非空且不伪造 `COMPLETED`。
|
||||
|
||||
- [ ] **Step 4: 运行专项 GREEN**
|
||||
|
||||
```bash
|
||||
mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulatorTest,SimulationTaskQueueTest,HistoricalDispatchFaultMatrixTest test
|
||||
```
|
||||
|
||||
预期新旧测试全部通过;若生产代码行为与测试暴露的状态不一致,先添加最小生产修复,再重新运行同一命令。
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationTaskQueueTest.java
|
||||
git commit -m "test(javaTest): prove history dispatch boundary states"
|
||||
```
|
||||
|
||||
### Task 3: 资源和重规划集成门禁
|
||||
|
||||
**Files:**
|
||||
- Modify: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/CorridorReservationManagerTest.java`
|
||||
- Modify: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java`
|
||||
- Modify: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationProgressWatchdogTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- 保持 `CorridorReservationManager.replaceRoute(...)` 原子接口和 `TrafficHoldTracker` 第三次触发协议不变。
|
||||
|
||||
- [ ] **Step 1: 锁定旧预约回滚**
|
||||
|
||||
在替换失败测试中同时断言旧路线每条边仍由原任务持有、其他同向持有者仍存在、没有新路线残留;在成功测试中断言不再使用的旧边释放且共享边保留。
|
||||
|
||||
- [ ] **Step 2: 锁定 HOLD 集成行为**
|
||||
|
||||
扩展模拟测试断言第三次相同交通 HOLD 产生一次 `REROUTE_TRIGGER`,失败替换产生 `REROUTE_REJECTED` 且原路线继续执行;成功替换后在下一次 MOVE 前不重复产生普通重规划。
|
||||
|
||||
- [ ] **Step 3: 锁定死锁 watchdog**
|
||||
|
||||
增加连续无进展达到阈值才判死锁、未来到达任务不判死锁、车辆 MOVE 后计数清零的测试;确认 `SimulationInvariantSummary.deadlocks` 与异常路径均可追溯。
|
||||
|
||||
- [ ] **Step 4: 运行专项 GREEN**
|
||||
|
||||
```bash
|
||||
mvn -f javaTest/pom.xml -Dtest=CorridorReservationManagerTest,HistoricalDispatchSimulatorTest,SimulationProgressWatchdogTest,TrafficHoldTrackerTest test
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 提交**
|
||||
|
||||
```bash
|
||||
git add javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation
|
||||
git commit -m "test(javaTest): lock reroute and resource safety gates"
|
||||
```
|
||||
|
||||
### Task 4: 报告、API、浏览器和真实负载验收
|
||||
|
||||
**Files:**
|
||||
- Modify only if an acceptance check fails: `javaTest/src/main/java/com/ft546/wcs/shadow/history/visualizer/*`, `javaTest/src/main/resources/visualizer/*`, `javaTest/scripts/visualizer_browser_qa.py`
|
||||
- Generated and removed after audit: `javaTest/outputs/acceptance-final`, `javaTest/outputs/browser-qa-final`
|
||||
|
||||
**Interfaces:**
|
||||
- HTTP `GET /api/health` remains `UP/mapLoaded/simulationBusy`.
|
||||
- Simulation output remains `summary.json`, `route-decisions.json`, `task-results.csv`, `tick-events.csv`, `invariant-results.json`, `manifest.sha256`.
|
||||
|
||||
- [ ] **Step 1: Run clean full suite**
|
||||
|
||||
```bash
|
||||
mvn -f javaTest/pom.xml clean test
|
||||
```
|
||||
|
||||
Record the actual Surefire count; never reuse an earlier count.
|
||||
|
||||
- [ ] **Step 2: Run one fresh 240-task replay**
|
||||
|
||||
```bash
|
||||
mvn -f javaTest/pom.xml compile exec:java "-Dexec.mainClass=com.ft546.wcs.shadow.history.simulation.HistoricalDispatchSimulationApplication" "-Dexec.args=outputs/acceptance-final 100"
|
||||
```
|
||||
|
||||
Parse the generated JSON with a structured parser and assert task totals, per-vehicle totals, route candidate bounds, safety invariants, archive count, WMS idempotence and nonblank failure/HOLD/retry reasons.
|
||||
|
||||
- [ ] **Step 3: Run browser black-box QA**
|
||||
|
||||
```bash
|
||||
python "C:/Users/13623/.agents/skills/webapp-testing/scripts/with_server.py" --server 'mvn compile exec:java "-Dexec.mainClass=com.ft546.wcs.shadow.history.visualizer.HistoricalDispatchVisualizerApplication" "-Dexec.args=18086"' --port 18086 --timeout 120 -- python scripts/visualizer_browser_qa.py http://127.0.0.1:18086 outputs/browser-qa-final
|
||||
```
|
||||
|
||||
Check desktop and mobile map rendering, route layer visibility, full-map viewport, route evidence and console error count.
|
||||
|
||||
- [ ] **Step 4: Verify health and repository state**
|
||||
|
||||
```powershell
|
||||
Invoke-RestMethod http://127.0.0.1:18086/api/health
|
||||
git status --short
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Only pre-existing user `docs/*.html` may remain untracked.
|
||||
|
||||
- [ ] **Step 5: Commit only implementation/test changes**
|
||||
|
||||
Use a focused commit for any production fix and a separate commit for tests. Do not stage generated reports or user documents.
|
||||
|
||||
## Completion Audit
|
||||
|
||||
Before claiming completion, map every original requirement to fresh evidence: `create_date` admission, priority/aging, vehicle selection, route stages, node/edge/opposite arbitration, HOLD/reroute, PLC retry, MOVE/release, archive/WMS idempotence, fault matrix, no-route closure, report/API/UI evidence, 240-task totals, route quality comparison, timing as operational-only evidence, and offline boundary.
|
||||
@@ -0,0 +1,64 @@
|
||||
# javaTest 调度闭环完成审计设计
|
||||
|
||||
**日期:** 2026-08-06
|
||||
**状态:** 已确认并进入执行
|
||||
**范围:** `javaTest` 历史负载驱动中心调度仿真、路线质量和可视化验收
|
||||
|
||||
## 1. 目标
|
||||
|
||||
在现有真实历史任务全链路仿真的基础上,补齐上线前最关键的可证明边界:
|
||||
|
||||
1. `create_date` 未来任务不能提前进入调度,优先级排序仍受饥饿保护影响。
|
||||
2. 已选路线必须是权威地图上的连续合法路径,公开质量评价接口不能接受非法候选。
|
||||
3. 活动任务的反向剩余路线必须被识别为对向风险,且优先级高于一般路线重合。
|
||||
4. 已知地图但无路可达的历史任务必须以明确 `FAILED/NO_ROUTE` 结束并进入报告。
|
||||
5. 第三次同一交通 HOLD 的集成重规划、预约失败回滚和移动后防抖必须有可复现证据。
|
||||
6. 240 条真实历史任务仍然全部经过中心重新选车、重新规划、交通裁决、PLC/ACK、逐节点移动、资源释放、归档和幂等 WMS 回调。
|
||||
|
||||
## 2. 保留的业务语义
|
||||
|
||||
- `task_no`、任务类型、物理起点、物理终点和优先级是业务输入。
|
||||
- `create_date` 只控制任务到达顺序,并按 10x/100x 加速;不截断真实相邻时间差。
|
||||
- 历史 `agv_id` 只做对照;历史 `path_info` 只做权威地图上的公平比较,不进入新算法输入。
|
||||
- 历史完成状态和 `finish_date` 不推进仿真;仿真完成只由 PLC/ACK 和逐节点移动产生。
|
||||
- 车辆资格和中心选车规则保持现有 `VehicleAssignmentService` 作为权威策略。
|
||||
- 路线质量只使用固定字典序元组,不使用受故障影响的耗时。
|
||||
|
||||
## 3. 技术设计
|
||||
|
||||
### 3.1 路线质量输入边界
|
||||
|
||||
`RouteQualityEvaluator` 在计算前校验候选路径的每个站点存在、每条相邻边存在且候选距离与权威地图坐标距离一致。非法候选直接抛出 `IllegalArgumentException`,防止调用方绕过 `RouteCandidatePlanner` 把任意节点序列参与排序。
|
||||
|
||||
活动路线的相邻有向边与候选边方向相反时,计入 `oppositeDirectionConflictCount`;同方向或仅物理边重合仍计入 `activeRouteOverlapEdgeCount`。已计入对向风险的边不再重复计入不兼容边预约。
|
||||
|
||||
### 3.2 调度端到端证据
|
||||
|
||||
在 `HistoricalDispatchSimulatorTest` 中增加小型权威地图夹具:
|
||||
|
||||
- 一个未来到达的高优先级任务和一个已到达的低优先级任务,验证未来任务不在其 `create_date` 前产生 `ASSIGN`,到达后按有效优先级选择。
|
||||
- 一个已知但被永久阻断的目标,验证结果为 `FAILED`、原因 `NO_ROUTE`,并且没有 `ASSIGN` 或 `COMPLETE`。
|
||||
- 一个相同交通 HOLD 连续三次的活动冲突,验证 `REROUTE_TRIGGER`、严格更优路线、原子替换失败时旧路线保持不变,以及成功换路后移动前不再次换路。
|
||||
|
||||
这些测试不改变真实历史数据,只补足真实回放无法自然覆盖的可控边界。
|
||||
|
||||
### 3.3 报告与浏览器
|
||||
|
||||
现有 JSON/CSV/API/HTML 继续消费 Java 产生的 `plannedPath`、候选、质量、事件和不变量证据。新增测试只验证这些字段在上述边界下不会丢失;浏览器继续显示完整地图、历史参考、当前规划、接近路径、MOVE/HOLD 和重规划前后路线。
|
||||
|
||||
## 4. 风险与降级
|
||||
|
||||
- 临时资源冲突仍然进入 HOLD,不转换为 `NO_ROUTE`。
|
||||
- 无严格更优路线或原子预约替换失败时保留旧路线和旧资源。
|
||||
- PLC 失败、断线、重启、低电量和车辆故障不进入交通 HOLD 计数。
|
||||
- 真实 240 条回放若出现等待或失败,必须保留明确原因,不能用历史完成状态补齐。
|
||||
- 本设计仍是离线内存仿真,不构成生产 SQL Server、PLC、WMS、HIL 或 ACTIVE 证据。
|
||||
|
||||
## 5. 验收门禁
|
||||
|
||||
1. Maven 全量测试失败、错误、跳过均为 0。
|
||||
2. 240 条历史任务的完成、等待、失败之和等于 240;默认真实负载全部完成。
|
||||
3. 每个路线阶段候选唯一选中,选中距离不超过最短距离 110%。
|
||||
4. 节点双占、边容量、对向换边和死锁均为 0。
|
||||
5. 归档数等于完成数,重复 WMS 投递不产生重复业务效果。
|
||||
6. 浏览器桌面和移动 QA 通过,完整地图与路径图层开关不改变权威拓扑。
|
||||
Reference in New Issue
Block a user