17 KiB
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; support10x; 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. A normal run has zero final
WAITINGrows. - 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
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<HistoricalSimulationTask> SimulationTaskQueue.readyAt(long nowMillis)orders effective priority, arrival, task number, GUID. -
Step 1: Write failing time-scaling tests
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
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
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
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. 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. Normal termination requires no waiting tasks; deadlock/tick limit snapshots remaining tasks as WAITING and increments deadlock evidence.
- 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
assertEquals(240, result.getTaskResults().size());
assertEquals(0, result.getWaitingCount());
assertTrue(result.getCompletedCount() >= 50);
assertTrue(result.getReassignmentCount() > 0);
assertTrue(result.getReplannedCount() > 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 <outputDir> [acceleration=100]. -
Outputs:
summary.json,task-results.csv,tick-events.csv,invariant-results.json,manifest.sha256. -
Step 1: Write failing hand-calculated metrics tests
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-<runId>/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.