# WCS Real History-Driven Dispatch Simulation 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:** Drive all 240 frozen FT546 history rows through deterministic task arrival, priority scheduling, vehicle selection, route planning, traffic arbitration, simulated PLC/vehicle execution, resource release, archive, and idempotent WMS completion. **Architecture:** Add a focused event-driven simulation package under the existing history module. It adapts verified history rows into business tasks, reuses the existing assignment/planning/SHADOW resource components, and isolates time, faults, PLC, WMS, archive, metrics, and reporting behind small deterministic classes. **Tech Stack:** Java 8, Maven, Jackson 2.17.2, JUnit 5.10.2, existing FT546 demo/SHADOW classes, bundled spreadsheet runtime for the final `.xlsx`. ## Global Constraints - Use the committed 240-row snapshot; never connect to SQL Server, a real PLC, WMS, or `ruoyi-*` production modules. - Default acceleration is `100x`; support `10x`; preserve source, simulated, and scale-adjusted time values. - Historical `agv_id`, `path_info`, `finish_date`, and completion status are comparisons only. - `task_no`, type, business start/end, and priority remain business inputs. - Unknown map and unreachable routes fail closed. `WAITING` is allowed only with recorded deadlock/tick-limit evidence. - Priority aging raises effective priority every 30 simulated seconds. - Node and undirected edge capacity are 1; opposite-direction simultaneous traversal is forbidden. - Fault schedules are deterministic. PLC retries are bounded to 3 attempts. - Every completed task has exactly one archive row and one WMS business side effect; duplicate WMS deliveries are intentionally exercised. - Same input and configuration must produce identical canonical results. --- ### Task 1: Preserve Verified Map Details and Convert Historical Inputs **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/HistoricalMapSite.java` - Modify: `javaTest/src/main/java/com/ft546/wcs/shadow/history/HistoricalQueueDataset.java` - Modify: `javaTest/src/main/java/com/ft546/wcs/shadow/history/HistoricalQueueLoader.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalSimulationTask.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalSimulationInput.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalSimulationInputFactory.java` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalSimulationInputFactoryTest.java` **Interfaces:** - `HistoricalSimulationInput HistoricalSimulationInputFactory.create(HistoricalQueueDataset dataset)` - Input exposes immutable schedulable tasks, failed inputs, grid/traffic maps, and initial vehicles. - [ ] **Step 1: Write failing loader and conversion tests** ```java assertEquals(1129, dataset.getMapSiteDetails().size()); assertEquals(240, input.getTasks().size() + input.getFailedInputs().size()); assertEquals(240, input.allSimulationIds().stream().distinct().count()); assertEquals(Arrays.asList("1", "2", "3"), input.vehicleIds()); ``` - [ ] **Step 2: Run RED** Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalSimulationInputFactoryTest test` Expected: compilation fails because the new input types do not exist. - [ ] **Step 3: Implement immutable map loading and task conversion** Parse SHA-verified map details into an insertion-ordered immutable map. Map task types `1/2/3`, preserve raw business fields, assign stable per-row ID `task_no@guid#stableSequence` because the snapshot contains repeated task/GUID pairs, parse `create_date`, and retain `finish_date/agv_id/path_info` only in comparison fields. - [ ] **Step 4: Build replannable topology and explicit endpoint mapping** Build topology from unique valid historical adjacent edges. Route directly from `start_site/end_site` when physical; otherwise store an explicit business-to-physical endpoint mapping to the reference path endpoints. Reject blank, unknown, or malformed mappings as `FAILED/UNKNOWN_MAP`. - [ ] **Step 5: Run GREEN and commit** Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalSimulationInputFactoryTest test` Commit: `git commit -m "feat: prepare verified history simulation inputs"` --- ### Task 2: Implement Accelerated Event Time and Starvation-Safe Queueing **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationConfig.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationClock.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationTaskQueue.java` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationClockTest.java` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationTaskQueueTest.java` **Interfaces:** - `SimulationConfig.defaults()` returns acceleration 100, aging interval 30 seconds, retry limit 3, no-progress 500, tick limit 20000. - `long SimulationClock.toSimulationMillis(LocalDateTime createdAt)` preserves relative arrivals and caps source gaps above 30 minutes. - `List SimulationTaskQueue.readyAt(long nowMillis)` orders effective priority, arrival, task number, GUID. - [ ] **Step 1: Write failing time-scaling tests** ```java assertEquals(100L, clock.toSimulationMillis(base.plusSeconds(10))); assertEquals(18_000L, clock.toSimulationMillis(base.plusHours(2))); assertEquals(clock10.sourceDurationMillis(1_000L), 10_000L); ``` - [ ] **Step 2: Run clock RED, implement, and run GREEN** Run: `mvn -f javaTest/pom.xml -Dtest=SimulationClockTest test` - [ ] **Step 3: Write failing priority/aging tests** ```java queue.add(lowPriorityAtZero); queue.add(highPriorityAtTwentySeconds); assertEquals(highPriorityAtTwentySeconds, queue.readyAt(20_000L).get(0)); assertEquals(lowPriorityAtZero, queue.readyAt(90_000L).get(0)); ``` - [ ] **Step 4: Implement stable queue ordering and requeue** Keep original priority immutable. Derive `effectivePriority = max(HIGHEST, priority - floor(wait/30s))`; requeue after HOLD without changing original arrival or losing accumulated age. - [ ] **Step 5: Run GREEN and commit** Run: `mvn -f javaTest/pom.xml -Dtest=SimulationClockTest,SimulationTaskQueueTest test` Commit: `git commit -m "feat: add accelerated starvation-safe simulation queue"` --- ### Task 3: Implement PLC, Vehicle Fault, Archive, and WMS Simulators **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/DeterministicFaultPlan.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulatedPlcGateway.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulatedVehicleRuntime.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationArchive.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/IdempotentWmsCompletionReceiver.java` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationAdaptersTest.java` **Interfaces:** - PLC result reasons: `ACK`, `SEND_FAILURE`, `ACK_TIMEOUT`, `ACK_LOST`, `STALE_BOOT_ID`. - Vehicle states: connected, boot ID, battery, faulted, current node; health decides assignment eligibility. - `SimulationArchive.complete(taskId, result)` is idempotent and stores one terminal row. - `IdempotentWmsCompletionReceiver.receive(taskId)` counts delivery attempts separately from business effects. - [ ] **Step 1: Write failing PLC retry and stale-boot tests** ```java assertEquals(SEND_FAILURE, plc.send(command).getReason()); assertEquals(ACK, plc.send(command).getReason()); runtime.restart(); assertEquals(STALE_BOOT_ID, plc.accept(oldAck).getReason()); ``` - [ ] **Step 2: Run RED, implement deterministic PLC behavior, run GREEN** Run: `mvn -f javaTest/pom.xml -Dtest=SimulationAdaptersTest test` - [ ] **Step 3: Add failing disconnect, low-battery, fault, archive, and WMS tests** ```java runtime.disconnect(); assertFalse(runtime.isAssignmentEligible()); runtime.setBattery(29); assertFalse(runtime.isAssignmentEligible()); runtime.fail(); assertFalse(runtime.isAssignmentEligible()); archive.complete("T1", result); archive.complete("T1", result); wms.receive("T1"); wms.receive("T1"); assertEquals(1, archive.size()); assertEquals(2, wms.getDeliveryAttempts()); assertEquals(1, wms.getBusinessEffects()); ``` - [ ] **Step 4: Implement adapters and run GREEN** Run: `mvn -f javaTest/pom.xml -Dtest=SimulationAdaptersTest test` - [ ] **Step 5: Commit** Commit: `git commit -m "feat: simulate PLC vehicle archive and WMS behavior"` --- ### Task 4: Build the Full Event-Driven Dispatch Simulator **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulator.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulationResult.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationTaskResult.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationTickEvent.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationInvariantSummary.java` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java` **Interfaces:** - `HistoricalDispatchSimulationResult simulate(HistoricalSimulationInput input, SimulationConfig config, DeterministicFaultPlan faults)` - Result exposes task/vehicle results, events, HOLD/retry reasons, archive/WMS counts, assignments/routes, and invariant counters. - [ ] **Step 1: Write failing multi-task completion test** Use a hand-checked `A-B-C` plus `B-D` graph with two vehicles and three arrivals. Assert all complete, priority order is correct, at least one HOLD occurs, and old nodes/edges are released after each move. - [ ] **Step 2: Run RED** Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulatorTest test` - [ ] **Step 3: Implement arrival, selection, replanning, and SHADOW arbitration** At each event time inject arrivals, assign every idle healthy vehicle, plan `vehicle -> source -> target`, build fresh snapshots/candidates, and apply GRANT segments to the authoritative ledger. HOLD an admission whose full route has an opposite shared edge with an active remaining route. Treat historical vehicle/path only as report comparisons. - [ ] **Step 4: Implement ACK movement and rolling resource release** Reserve current node, undirected edge, and next node. After ACK move one node, release the prior node and traversed edge, retain the new node. Assert capacity, node uniqueness, opposite-edge exclusion, and one active task per vehicle after every event. - [ ] **Step 5: Implement HOLD re-dispatch and fault recovery** On resource HOLD, PLC retry exhaustion, disconnect, low battery, or vehicle fault, release unexecuted reservations and requeue with preserved wait age. Reject stale ACK after boot changes. Resume/reselect/replan after recovery. - [ ] **Step 6: Implement completion, archive, WMS idempotency, and termination** Complete only when simulated movement reaches target. Atomically archive, deliver WMS twice in the acceptance path, and assert one business effect. Deadlock/tick limit snapshots remaining tasks as `WAITING` and increments deadlock evidence. Progress is based on terminal task count, so vehicle oscillation cannot mask a livelock. - [ ] **Step 7: Run GREEN and commit** Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulatorTest test` Commit: `git commit -m "feat: run deterministic full-chain dispatch simulation"` --- ### Task 5: Verify Failure Modes and All 240 Real Tasks **Files:** - Create: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchFaultMatrixTest.java` - Create: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulationRealDataTest.java` **Interfaces:** - Fault matrix uses the same simulator with controlled plans for disconnect, restart, low battery, vehicle fault, send failure, ACK timeout/loss, unknown map, and no route. - Real-data test runs the frozen 240-row workload twice and compares canonical results. - [ ] **Step 1: Write and run the fault-matrix tests** Assert each recoverable fault releases resources and completes after redispatch; unknown map/no route end as `FAILED`; stale feedback cannot move a vehicle; all invariant counters remain zero. Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchFaultMatrixTest test` - [ ] **Step 2: Write the 240-row parameterized and aggregate tests** ```java assertEquals(240, result.getTaskResults().size()); assertEquals(240, result.getCompletedCount() + result.getWaitingCount() + result.getFailedCount()); assertTrue(result.getCompletedCount() > 0); assertTrue(result.getReassignmentCount() > 0); assertTrue(result.getRetryCount() > 0); assertEquals(0, result.getInvariants().totalSafetyViolations()); assertEquals(result.canonicalView(), secondRun.canonicalView()); ``` - [ ] **Step 3: Run real data and existing safety suites** Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulationRealDataTest,ShadowSimulationDataTest test` - [ ] **Step 4: Commit** Commit: `git commit -m "test: verify history simulation and fault recovery"` --- ### Task 6: Produce Metrics and Auditable Machine-Readable Reports **Files:** - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationMetrics.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulationReportWriter.java` - Create: `javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulationApplication.java` - Modify: `javaTest/README.md` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/SimulationMetricsTest.java` - Test: `javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulationReportWriterTest.java` **Interfaces:** - Metrics use nearest-rank `ceil(p*n)-1`; empty series returns JSON null. - CLI: `HistoricalDispatchSimulationApplication [acceleration=100]`. - Outputs: `summary.json`, `task-results.csv`, `tick-events.csv`, `invariant-results.json`, `manifest.sha256`. - [ ] **Step 1: Write failing hand-calculated metrics tests** ```java assertEquals(3.0, metrics.average(Arrays.asList(1L, 3L, 5L))); assertEquals(5L, metrics.percentile(Arrays.asList(1L, 3L, 5L), 0.95)); assertNull(metrics.percentile(Collections.emptyList(), 0.99)); ``` - [ ] **Step 2: Implement metrics and run GREEN** Run: `mvn -f javaTest/pom.xml -Dtest=SimulationMetricsTest test` - [ ] **Step 3: Write failing report contract tests** Parse generated JSON/CSV and assert the 240 status counts, per-vehicle totals, reassignments/routes, safety counters, waiting/completion average/P95/P99, HOLD/retry reasons, historical-vs-simulated duration, archive totals, WMS attempts/effects, source boundary, and sorted hashes. - [ ] **Step 4: Implement reports, CLI, README, and run GREEN** Run: `mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulationReportWriterTest test` Commit: `git commit -m "feat: report auditable dispatch simulation metrics"` --- ### Task 7: Generate the Readable Workbook and Perform Final Verification **Files:** - Generate: `outputs/wcs-history-driven-dispatch-simulation-/readable-report.xlsx` - Modify: `docs/superpowers/plans/2026-07-31-wcs-real-history-driven-dispatch-simulation.md` - [ ] **Step 1: Run fresh full verification** Run: `mvn -f javaTest/pom.xml clean test` Require failures/errors/skips 0 and separately report the 240-row and fault-matrix counts. - [ ] **Step 2: Generate a fresh unique evidence directory** Run the CLI at acceleration 100. Do not overwrite prior replay/simulation evidence. - [ ] **Step 3: Build and verify the workbook** Create sheets `测试总览`, `任务结果`, `车辆统计`, `重新选车与路径`, `等待与重试`, `安全与归档`, `数据问题`, `来源与边界`. Reconcile formulas and values against JSON/CSV, verify 241 task rows including header, ensure no formula error tokens, and include one status chart. - [ ] **Step 4: Audit evidence and repository scope** Recalculate manifests, scan output for secrets, verify the report answers every required question, and prove `git diff --name-only -- 'ruoyi-*'` is empty. - [ ] **Step 5: Update this checklist and commit final evidence-related changes** Commit: `git commit -m "test: verify real history dispatch simulation"` --- ## Final Verification Checklist - [ ] All 240 history rows enter once and have completed/waiting/failed totals. - [ ] Priority ordering and 30-second aging protection are proven. - [ ] Automatic vehicle selection and route replanning differ from history at least once. - [ ] Node, edge, opposite-direction, double-occupancy, and deadlock evidence is reported; safety violations are zero. - [ ] HOLD redispatch, PLC retry, disconnect, restart, low battery, and vehicle fault recovery are proven. - [ ] Unknown map and no route fail closed. - [ ] Waiting/completion average, P95, P99 and history-vs-simulation duration are reported. - [ ] Every completed task has one archive row and one WMS business effect despite duplicate delivery. - [ ] Two runs are canonically identical, all Maven tests pass, and no production module changed.