# WCS Dispatch and Traffic Demo Implementation Plan > **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:** 在工作树根目录创建独立的 Java 8 Maven Demo,用真实 JUnit 5 测试模拟 LEGACY WCS 的中心调度、确定性选车、路径交通管制、避让和队列生命周期。 **Architecture:** `LegacyDispatchCenter` 是单周期入口,只调用一次任务准入,再稳定处理车辆和活动队列。`VehicleAssignmentService`、`TrafficController`、`GridPathPlanner`、`SimulatedProtocolAdapter` 均为纯 Java 边界;`InMemoryWcsState` 保存模拟任务、队列、车辆和历史,不连接生产数据库或 PLC。 **Tech Stack:** Java 8、Maven 3.6、JUnit Jupiter 5.10.2、Maven Surefire 3.2.5、Exec Maven Plugin 3.1.0。 ## Global Constraints - 生产控制模式保持 LEGACY;Demo 不修改生产 WCS 源码。 - 不连接 SQL Server、PLC、WMS 或 Spring,不产生真实设备写入。 - 不建立生产中央路权服务,不写交通运行表,不启用 SHADOW/ACTIVE。 - 不使用 `default02` 至 `default08` 保存新增交通状态。 - 所有源码使用 Java 8 可用语法与 API。 - `mvn test` 的真实测试数必须大于 0,failures 和 errors 必须为 0。 - 车辆资格固定为 connected、`workMode=5`、`status=1`、`allowSend=true`、`battery>30`。 - 选择顺序固定为同层、绝对楼层差、Y 距离、X 距离、vehicleId。 - 队列状态保持旧语义:新建 `issued=0/executionStatus=1`,下发 `1/3`,完成 `1/4` 后归档删除。 --- ## File Map ### Build and documentation - `javaTest/pom.xml`:独立 Maven 构建、JUnit 5、Surefire、Exec 插件。 - `javaTest/README.md`:运行方式、场景、LEGACY 安全边界。 ### Domain - `javaTest/src/main/java/com/ft546/wcs/demo/model/Site.java`:站点、楼层和坐标值对象。 - `javaTest/src/main/java/com/ft546/wcs/demo/model/VehicleSnapshot.java`:不可变车辆执行快照。 - `javaTest/src/main/java/com/ft546/wcs/demo/model/DispatchTask.java`:业务任务及准入状态。 - `javaTest/src/main/java/com/ft546/wcs/demo/model/DispatchQueueEntry.java`:活动队列及旧状态码流转。 - `javaTest/src/main/java/com/ft546/wcs/demo/model/DecisionCode.java`:调度和交通决策码。 ### State and scheduling - `javaTest/src/main/java/com/ft546/wcs/demo/repository/InMemoryWcsState.java`:车辆、任务、队列、历史和每周期事件。 - `javaTest/src/main/java/com/ft546/wcs/demo/center/VehicleAssignmentDecision.java`:确定性选车结果和理由。 - `javaTest/src/main/java/com/ft546/wcs/demo/center/VehicleAssignmentService.java`:车辆资格过滤和稳定比较器。 - `javaTest/src/main/java/com/ft546/wcs/demo/center/QueueAdmissionService.java`:每周期把一个待处理任务转为活动队列。 - `javaTest/src/main/java/com/ft546/wcs/demo/center/CycleResult.java`:单周期已处理车辆和事件快照。 - `javaTest/src/main/java/com/ft546/wcs/demo/center/LegacyDispatchCenter.java`:单周期中心调度入口。 ### Traffic and protocol - `javaTest/src/main/java/com/ft546/wcs/demo/traffic/GridMap.java`:站点、边和静态障碍。 - `javaTest/src/main/java/com/ft546/wcs/demo/traffic/GridPathPlanner.java`:确定性广度优先最短路。 - `javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficDecision.java`:路径、HOLD 或避让结果。 - `javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficController.java`:剩余路径锁、离线点、通道冲突和避让去重。 - `javaTest/src/main/java/com/ft546/wcs/demo/simulation/SimulatedProtocolAdapter.java`:可注入失败的无 I/O 下发适配器。 - `javaTest/src/main/java/com/ft546/wcs/demo/DemoApplication.java`:构造场景、推进周期和打印结果。 ### Tests - `javaTest/src/test/java/com/ft546/wcs/demo/VehicleAssignmentServiceTest.java` - `javaTest/src/test/java/com/ft546/wcs/demo/TrafficControllerTest.java` - `javaTest/src/test/java/com/ft546/wcs/demo/LegacyDispatchCenterTest.java` - `javaTest/src/test/java/com/ft546/wcs/demo/QueueLifecycleTest.java` - `javaTest/src/test/java/com/ft546/wcs/demo/DemoScenarioTest.java` --- ## Task 1: Bootstrap Real JUnit 5 and Domain Models **Files:** - Create: `javaTest/pom.xml` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/model/Site.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/model/VehicleSnapshot.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/model/DispatchTask.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/model/DispatchQueueEntry.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/model/DecisionCode.java` - Test: `javaTest/src/test/java/com/ft546/wcs/demo/QueueLifecycleTest.java` **Interfaces:** - Produces: `Site(String id, int floor, int x, int y, String channel)` - Produces: `VehicleSnapshot(String vehicleId, int floor, String currentSite, int workMode, int status, int battery, boolean connected, boolean allowSend, boolean cargo)` - Produces: `DispatchTask(String taskId, TaskType type, String sourceSite, String targetSite, int floor, int priority)` - Produces: `DispatchQueueEntry.business(DispatchTask task, String vehicleId)` - Produces: `markIssued(List path)`, `markCompleted()`, `isIssued()`, `getExecutionStatus()` - [ ] **Step 1: Add Maven build and write the failing lifecycle test** `pom.xml` must set `maven.compiler.source` and `target` to `1.8`, add `org.junit.jupiter:junit-jupiter:5.10.2`, configure `maven-surefire-plugin:3.2.5`, and configure `exec-maven-plugin:3.1.0` with main class `com.ft546.wcs.demo.DemoApplication`. The first test: ```java @Test void queueUsesLegacyLifecycleCodes() { DispatchTask task = new DispatchTask("T-1", TaskType.OUTBOUND, "A", "B", 1, 2); DispatchQueueEntry queue = DispatchQueueEntry.business(task, "1"); assertEquals(0, queue.getIssued()); assertEquals(1, queue.getExecutionStatus()); queue.markIssued(Arrays.asList("A", "B")); assertEquals(1, queue.getIssued()); assertEquals(3, queue.getExecutionStatus()); queue.markCompleted(); assertEquals(4, queue.getExecutionStatus()); } ``` - [ ] **Step 2: Run the focused test and verify RED** Run: `cd javaTest && mvn -Dtest=QueueLifecycleTest test` Expected: FAIL during test compilation because domain classes do not exist. - [ ] **Step 3: Implement immutable inputs and guarded queue transitions** Implement nested enum `DispatchTask.TaskType { INBOUND, OUTBOUND, RELOCATION }`. Reject blank IDs, battery outside 0–100, non-positive floors and `markCompleted()` before issue with `IllegalStateException`. Copy path input into an unmodifiable list. - [ ] **Step 4: Run the focused test and verify GREEN** Run: `cd javaTest && mvn -Dtest=QueueLifecycleTest test` Expected: tests=1, failures=0, errors=0. - [ ] **Step 5: Commit** ```bash git add javaTest/pom.xml javaTest/src/main/java/com/ft546/wcs/demo/model javaTest/src/test/java/com/ft546/wcs/demo/QueueLifecycleTest.java git commit -m "test: bootstrap wcs demo domain" ``` ## Task 2: Deterministic Vehicle Assignment **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/demo/center/VehicleAssignmentDecision.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/center/VehicleAssignmentService.java` - Test: `javaTest/src/test/java/com/ft546/wcs/demo/VehicleAssignmentServiceTest.java` **Interfaces:** - Consumes: `DispatchTask`, `VehicleSnapshot`, `Map` - Produces: `VehicleAssignmentDecision select(DispatchTask task, List vehicles, Map sites)` - Produces: `DecisionCode.ASSIGNED`, `HOLD_NO_ELIGIBLE_VEHICLE`, `REJECT_INVALID_SITE` - Produces: `Optional getVehicle()`, `DecisionCode getCode()`, `String getReason()` - [ ] **Step 1: Write failing assignment tests** Tests must assert: ```java assertEquals("2", service.select(task, Arrays.asList(crossFloor, sameFloor), sites) .getVehicle().get().getVehicleId()); ``` ```java assertEquals("1", service.select(task, Arrays.asList(vehicle2, vehicle1), sites) .getVehicle().get().getVehicleId()); ``` Also assert ineligible vehicles are excluded and a missing source site returns `REJECT_INVALID_SITE`. - [ ] **Step 2: Run and verify RED** Run: `cd javaTest && mvn -Dtest=VehicleAssignmentServiceTest test` Expected: FAIL because assignment types do not exist. - [ ] **Step 3: Implement stable assignment** Eligibility is exactly `connected && workMode == 5 && status == 1 && allowSend && battery > 30`. Sort by: ```java Comparator.comparingInt(candidate -> candidate.sameFloorPenalty) .thenComparingInt(candidate -> candidate.floorDistance) .thenComparingInt(candidate -> candidate.yDistance) .thenComparingInt(candidate -> candidate.xDistance) .thenComparing(candidate -> candidate.vehicle.getVehicleId()); ``` Distances use `Site` coordinates; never parse malformed numeric substrings from site IDs. Return a reason string containing the chosen comparison values. - [ ] **Step 4: Run and verify GREEN** Run: `cd javaTest && mvn -Dtest=VehicleAssignmentServiceTest test` Expected: all assignment tests pass. - [ ] **Step 5: Commit** ```bash git add javaTest/src/main/java/com/ft546/wcs/demo/center javaTest/src/test/java/com/ft546/wcs/demo/VehicleAssignmentServiceTest.java git commit -m "feat: add deterministic vehicle assignment demo" ``` ## Task 3: Grid Path Planning and Traffic Control **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/demo/traffic/GridMap.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/traffic/GridPathPlanner.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficDecision.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficController.java` - Test: `javaTest/src/test/java/com/ft546/wcs/demo/TrafficControllerTest.java` **Interfaces:** - Consumes: sites, adjacency, static blocks, vehicles and active queues - Produces: `List shortestPath(GridMap map, String start, String end, Set blocked)` - Produces: `TrafficDecision plan(VehicleSnapshot vehicle, DispatchQueueEntry queue, Collection vehicles, Collection queues)` - Produces: `PATH_READY`, `HOLD_NO_PATH`, `HOLD_CHANNEL_BLOCKED`, `AVOIDANCE_CREATED` - [ ] **Step 1: Write failing path and traffic tests** Cover: ```java assertEquals(Arrays.asList("A", "D", "C"), planner.shortestPath(map, "A", "C", Collections.singleton("B"))); ``` ```java TrafficDecision decision = controller.plan(car1, car1Queue, vehicles, queues); assertEquals(DecisionCode.AVOIDANCE_CREATED, decision.getCode()); assertEquals(9, decision.getAvoidanceQueue().get().getPriority()); ``` Also test offline current-site locking, no route, avoidance de-duplication, and successful re-plan after avoidance queue deletion. - [ ] **Step 2: Run and verify RED** Run: `cd javaTest && mvn -Dtest=TrafficControllerTest test` Expected: FAIL because traffic types do not exist. - [ ] **Step 3: Implement deterministic BFS and occupancy view** `GridPathPlanner` visits neighbors sorted by site ID. `TrafficController` blocks: 1. static map obstacles, 2. disconnected vehicle current sites, 3. every other active queue path from that vehicle's current-site index onward. Before planning a business queue, detect a same-floor vehicle at a different site with the same target channel. If it has no active queue, create `DispatchQueueEntry.avoidance(...)` to a configured cache site, priority 9. If it already has an avoidance queue, return `HOLD_CHANNEL_BLOCKED` without creating another. - [ ] **Step 4: Run and verify GREEN** Run: `cd javaTest && mvn -Dtest=TrafficControllerTest test` Expected: all traffic tests pass. - [ ] **Step 5: Commit** ```bash git add javaTest/src/main/java/com/ft546/wcs/demo/traffic javaTest/src/test/java/com/ft546/wcs/demo/TrafficControllerTest.java git commit -m "feat: simulate wcs traffic control" ``` ## Task 4: In-Memory State, Admission, and Cycle Coordinator **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/demo/repository/InMemoryWcsState.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/center/QueueAdmissionService.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/center/CycleResult.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/center/LegacyDispatchCenter.java` - Create: `javaTest/src/main/java/com/ft546/wcs/demo/simulation/SimulatedProtocolAdapter.java` - Test: `javaTest/src/test/java/com/ft546/wcs/demo/LegacyDispatchCenterTest.java` **Interfaces:** - Produces: `CycleResult runCycle()` - Produces: `int getAdmissionInvocationCount()` - Produces: `Optional createPendingQueue(InMemoryWcsState state)` - Produces: state methods to add/update vehicles and tasks, query active queues/history/events - Produces: `SimulatedProtocolAdapter.ProtocolResult send(DispatchQueueEntry queue, List path)` - [ ] **Step 1: Write failing coordinator tests** The first test: ```java CycleResult result = center.runCycle(); assertEquals(1, admission.getInvocationCount()); assertEquals(Arrays.asList("1", "2", "3"), result.getProcessedVehicleIds()); assertEquals(1, state.getActiveQueues().size()); ``` Also test protocol failure leaves `issued=0/executionStatus=1`, the next cycle retries successfully, and reaching the destination archives and deletes the queue exactly once. - [ ] **Step 2: Run and verify RED** Run: `cd javaTest && mvn -Dtest=LegacyDispatchCenterTest test` Expected: FAIL because coordinator types do not exist. - [ ] **Step 3: Implement one-admission-per-cycle coordinator** `runCycle()` must: 1. call admission exactly once, 2. freeze and sort vehicle IDs, 3. add any avoidance queue returned by traffic control, 4. only send a queue when `PATH_READY`, 5. leave HOLD queues unchanged, 6. call protocol once per unissued ready queue, 7. complete and archive an issued queue only when vehicle current site equals queue end site. `SimulatedProtocolAdapter.failNextSend()` injects one failure and records every attempted queue ID without I/O. - [ ] **Step 4: Run and verify GREEN** Run: `cd javaTest && mvn -Dtest=LegacyDispatchCenterTest,QueueLifecycleTest test` Expected: coordinator and lifecycle tests pass. - [ ] **Step 5: Commit** ```bash git add javaTest/src/main/java/com/ft546/wcs/demo/repository javaTest/src/main/java/com/ft546/wcs/demo/center javaTest/src/main/java/com/ft546/wcs/demo/simulation javaTest/src/test/java/com/ft546/wcs/demo/LegacyDispatchCenterTest.java git commit -m "feat: add legacy dispatch cycle demo" ``` ## Task 5: Executable Scenarios and End-to-End Test **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/demo/DemoApplication.java` - Create: `javaTest/src/test/java/com/ft546/wcs/demo/DemoScenarioTest.java` - Create: `javaTest/README.md` **Interfaces:** - Produces: `DemoApplication.runScenario(PrintStream out)` - Produces: console lines beginning `CYCLE`, `ASSIGN`, `PATH`, `HOLD`, `AVOID`, `SEND`, `COMPLETE`, `SUMMARY` - [ ] **Step 1: Write failing end-to-end test** ```java ByteArrayOutputStream output = new ByteArrayOutputStream(); DemoApplication.runScenario(new PrintStream(output)); String text = new String(output.toByteArray(), StandardCharsets.UTF_8); assertTrue(text.contains("ASSIGN")); assertTrue(text.contains("AVOID")); assertTrue(text.contains("HOLD")); assertTrue(text.contains("SEND")); assertTrue(text.contains("COMPLETE")); assertTrue(text.contains("SUMMARY")); ``` - [ ] **Step 2: Run and verify RED** Run: `cd javaTest && mvn -Dtest=DemoScenarioTest test` Expected: FAIL because `DemoApplication` does not exist. - [ ] **Step 3: Implement the complete console scenario** Create a two-lane map with a cache point and three vehicles. Run sequential phases for deterministic assignment, same-channel avoidance, avoidance completion, protocol failure/retry, business completion and no-path HOLD. Print every event and a final summary containing cycle count, active queue count and history count. `README.md` must document: ```bash mvn test mvn exec:java ``` and explicitly state the Demo never connects to production systems. - [ ] **Step 4: Run focused and full verification** Run: ```bash cd javaTest mvn -Dtest=DemoScenarioTest test mvn test mvn exec:java ``` Expected: focused test passes; full Surefire summary has tests > 0, failures=0, errors=0; console output contains all required event types and exits 0. - [ ] **Step 5: Commit** ```bash git add javaTest/src/main/java/com/ft546/wcs/demo/DemoApplication.java javaTest/src/test/java/com/ft546/wcs/demo/DemoScenarioTest.java javaTest/README.md git commit -m "feat: add executable wcs dispatch simulation" ``` ## Task 6: Completion Audit **Files:** - Verify: `javaTest/**` - Verify: `docs/superpowers/specs/2026-07-30-wcs-dispatch-traffic-demo-design.md` **Interfaces:** - Consumes: all earlier tasks - Produces: objective-by-objective evidence - [ ] **Step 1: Verify repository and Java compatibility** Run: ```bash git rev-parse --is-inside-work-tree mvn -f javaTest/pom.xml clean test ``` Expected: Git prints `true`; Maven exits 0 and compiles with source/target 1.8. - [ ] **Step 2: Verify real test counts** Inspect `javaTest/target/surefire-reports/TEST-*.xml`; sum `tests`, `failures`, `errors`, and `skipped`. Expected: tests > 0, failures=0, errors=0. - [ ] **Step 3: Verify executable behavior** Run: `mvn -f javaTest/pom.xml exec:java` Expected: output includes `CYCLE`, `ASSIGN`, `PATH`, `HOLD`, `AVOID`, `SEND`, `COMPLETE`, and `SUMMARY`, with process exit 0. - [ ] **Step 4: Verify production isolation** Run: ```bash git diff 7b36dfa --name-only ``` Expected: only `javaTest/**` and the implementation plan are added or modified; no production `ruoyi-*` code changes. - [ ] **Step 5: Final commit if verification updates documentation** ```bash git add javaTest docs/superpowers/plans/2026-07-30-wcs-dispatch-traffic-demo.md git commit -m "docs: finalize wcs demo verification" ```