diff --git a/docs/superpowers/plans/2026-07-31-wcs-real-history-driven-dispatch-simulation.md b/docs/superpowers/plans/2026-07-31-wcs-real-history-driven-dispatch-simulation.md new file mode 100644 index 0000000..b0b00d4 --- /dev/null +++ b/docs/superpowers/plans/2026-07-31-wcs-real-history-driven-dispatch-simulation.md @@ -0,0 +1,335 @@ +# 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. A normal run has zero final `WAITING` rows. +- 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 ID `task_no@guid`, 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. 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** + +```java +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 [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.