26 KiB
javaTest Bounded Conflict-Aware Routing 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: Replace the historical replay's final BFS route choice with deterministic, 110%-bounded, traffic-aware approach and service route selection, add safe third-HOLD rerouting, and expose auditable evidence in reports and the full-map browser.
Architecture: Keep GridPathPlanner unchanged as the compatibility shortest-edge baseline. Add a pure traffic-package candidate generator and quality evaluator, then adapt the historical simulator through immutable planning evidence and an atomic corridor-reservation replacement operation. Reporting and the browser consume stored decisions and events; neither layer reruns the planner or invents route evidence.
Tech Stack: Java 8, Maven, JUnit 5, Jackson already present in javaTest, vanilla HTML/CSS/JavaScript, Playwright/browser verification, no new production dependency.
File Map
New traffic-domain files:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RoutePlanningPolicy.java: immutable 110% and 32-candidate limits.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidate.java: one immutable loopless path and coordinate distance.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidateSet.java: shortest baseline plus bounded candidates and limit evidence.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidatePlanner.java: deterministic Dijkstra baseline and K-shortest loopless enumeration.javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficRouteSnapshot.java: immutable occupied-node, directed-reservation and active-route evidence.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteQuality.java: comparable business tuple.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidateEvaluation.java: candidate plus quality.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RoutePlanDecision.java: selected candidate and all decision evidence.javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluator.java: metric calculation and lexicographic selection.
New simulation-domain files:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/RoutePlanningEvidence.java: immutable approach/service planning record with version and reroute outcome.javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/TrafficHoldTracker.java: exact three-consecutive-cycle trigger keyed by task, vehicle, resource and reason.javaTest/src/main/java/com/ft546/wcs/shadow/history/visualizer/HistoricalRouteQualityMapper.java: authoritative historical comparability and quality classification.
Modified files:
CorridorReservationManager.java: reservation snapshot plus atomicreplaceRoute.HistoricalDispatchSimulator.java: candidate-based initial planning, traffic snapshot construction, third-HOLD rerouting, movable active route, evidence capture.SimulationTaskResult.java: expose approach/service decisions and reroute count without changing existing fields.HistoricalDispatchSimulationReportWriter.java: add route-quality/comparability and reroute sections.SimulationVisualizationMapper.java: add decision evidence and fair historical comparison to JSON.RouteTopologyEvidenceMapper.java: reuse authoritative endpoint/edge validation for comparability.javaTest/src/main/resources/history-visualizer/index.html: add route decision and reroute inspector sections.javaTest/src/main/resources/history-visualizer/app.js: render selected candidates, path versions, HOLD point and before/after reroute.javaTest/src/main/resources/history-visualizer/app.css: restrained table, badge and route-layer styling.
Task 1: Deterministic Bounded Candidate Generation
Files:
-
Create:
javaTest/src/test/java/com/ft546/wcs/demo/traffic/RouteCandidatePlannerTest.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RoutePlanningPolicy.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidate.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidateSet.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidatePlanner.java -
Step 1: Write focused failing tests
Create hand-checked fixtures covering Euclidean distance, an exactly-110% route, an over-limit route, loop rejection, stable canonical ordering, 32-candidate truncation, unknown endpoints and permanent blocked nodes. The primary public contract is:
RouteCandidateSet result = new RouteCandidatePlanner().plan(
map, "A", "D", Collections.<String>emptySet(),
new RoutePlanningPolicy(1.10d, 32));
assertEquals(Arrays.asList("A", "B", "D"), result.getShortestPath());
assertEquals(2.0d, result.getShortestPhysicalDistance(), 0.000001d);
assertEquals(Arrays.asList("A", "B", "D"), result.getCandidates().get(0).getPath());
assertTrue(result.getCandidates().stream()
.allMatch(candidate -> candidate.getPhysicalDistance() <= 2.2d + 0.000001d));
- Step 2: Verify RED
Run:
mvn -f javaTest/pom.xml -Dtest=RouteCandidatePlannerTest test
Expected: compilation fails because RouteCandidatePlanner and its DTOs do not exist.
- Step 3: Implement the pure candidate module
Use Euclidean edge distance from Site.x/y. Compute the deterministic Dijkstra baseline with (distance, canonicalPath) ordering. Implement Yen's K-shortest loopless algorithm: for each accepted path, remove the root-prefix edges/nodes needed for each spur calculation, run the same deterministic Dijkstra for the spur path, deduplicate by complete node sequence, and order the candidate heap by (distance, canonicalPath). Discard candidates above shortestDistance * detourRatio, stop after 32 accepted candidates, and set candidateLimitReached only if another admissible path exists. Treat GridMap.getBlockedSites() plus the supplied permanent-block set as static exclusions, while allowing the start node itself.
Public signatures:
public RouteCandidateSet plan(GridMap map, String source, String target,
Set<String> permanentlyBlockedSites,
RoutePlanningPolicy policy);
public double pathDistance(GridMap map, List<String> path);
All returned lists are defensive, unmodifiable copies. Empty candidates and empty shortest path mean permanent map unreachability.
- Step 4: Verify GREEN and compatibility
mvn -f javaTest/pom.xml -Dtest=RouteCandidatePlannerTest,TrafficControllerTest test
Expected: all selected tests pass; existing BFS tests remain unchanged.
- Step 5: Commit
git add javaTest/src/main/java/com/ft546/wcs/demo/traffic javaTest/src/test/java/com/ft546/wcs/demo/traffic/RouteCandidatePlannerTest.java
git commit -m "feat(javaTest): generate bounded route candidates"
Task 2: Traffic Snapshot and Lexicographic Route Quality
Files:
-
Create:
javaTest/src/test/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluatorTest.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/TrafficRouteSnapshot.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteQuality.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteCandidateEvaluation.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RoutePlanDecision.java -
Create:
javaTest/src/main/java/com/ft546/wcs/demo/traffic/RouteQualityEvaluator.java -
Step 1: Write focused failing tests
Build literal two-route fixtures proving the fixed priority order independently: opposite direction beats every lower metric; occupied nodes beat reserved-edge conflicts; reserved-edge conflicts beat active overlap; overlap beats turns; turns beat distance; distance beats canonical path. Also prove self-owned resources and the current vehicle's first node do not count, reverse reservations are not double-counted as incompatible, active-route overlap is undirected, and repeated evaluation is deterministic.
RoutePlanDecision decision = evaluator.select(
map, candidates, TrafficRouteSnapshot.builder()
.occupyNode("B", "OTHER-AGV")
.reserveEdge("A", "B", "OTHER-TASK")
.activeRoute("OTHER-TASK", Arrays.asList("A", "B", "D"))
.build(),
"TASK-1", "AGV-1");
assertEquals(Arrays.asList("A", "C", "D"), decision.getSelectedPath());
assertEquals(0, decision.getSelectedQuality().getOppositeDirectionConflictCount());
- Step 2: Verify RED
mvn -f javaTest/pom.xml -Dtest=RouteQualityEvaluatorTest test
Expected: compilation fails because the snapshot/evaluation contracts do not exist.
- Step 3: Implement immutable evidence and evaluator
RouteQuality.compareTo compares exactly:
oppositeDirectionConflictCount;
occupiedNodeCount;
incompatibleReservedEdgeCount;
activeRouteOverlapEdgeCount;
turnCount;
physicalDistance;
canonicalPath;
Count future nodes from path index 1. Count each candidate edge once per category. A turn occurs when normalized integer direction vectors for three consecutive same-floor sites differ. Return every evaluated candidate, the selected entry, detourRatio, and a stable reason naming the first metric that distinguishes the winner from the physical shortest candidate.
- Step 4: Verify GREEN
mvn -f javaTest/pom.xml -Dtest=RouteCandidatePlannerTest,RouteQualityEvaluatorTest test
Expected: all tests pass.
- Step 5: Commit
git add javaTest/src/main/java/com/ft546/wcs/demo/traffic javaTest/src/test/java/com/ft546/wcs/demo/traffic
git commit -m "feat(javaTest): rank routes by live traffic quality"
Task 3: Atomic Corridor Reservation Replacement
Files:
-
Modify:
javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/CorridorReservationManagerTest.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/CorridorReservationManager.java -
Step 1: Add failing reservation tests
Add real-manager tests for successful replacement, rejection that leaves every old edge owned, preservation of shared same-direction holders, rank preservation, and snapshot direction/owner evidence.
manager.reserve("T1", Arrays.asList("A", "B", "C"), 1, 10L);
manager.reserve("T2", Arrays.asList("D", "C"), 1, 20L);
ReservationDecision denied = manager.replaceRoute(
"T1", Arrays.asList("A", "D", "C"), 1, 10L);
assertFalse(denied.isGranted());
assertEquals("T1", manager.ownerFor("A", "B"));
assertEquals("T1", manager.ownerFor("B", "C"));
- Step 2: Verify RED
mvn -f javaTest/pom.xml -Dtest=CorridorReservationManagerTest test
Expected: compilation fails because replaceRoute and snapshot are missing.
- Step 3: Implement precheck-then-commit replacement
Add:
public ReservationDecision replaceRoute(String taskId, List<String> newRoute,
int effectivePriority, long arrivalMillis);
public List<CorridorReservationSnapshot> snapshot();
During precheck, ignore the current task's own old holdings but retain other holders. Do not mutate edges, taskEdges, or ranks until all new edges pass. On success, remove only old holdings no longer present, add every new holding, replace the task's edge index and rank, and clean empty reservations. Preserve direction plus all holder IDs in the immutable snapshot.
- Step 4: Verify GREEN
mvn -f javaTest/pom.xml -Dtest=CorridorReservationManagerTest test
Expected: all tests pass.
- Step 5: Commit
git add javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/CorridorReservationManager.java javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/CorridorReservationManagerTest.java
git commit -m "feat(javaTest): replace route reservations atomically"
Task 4: Initial Approach and Service Route Integration
Files:
-
Create:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/RoutePlanningEvidence.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationTaskResult.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulator.java -
Modify:
javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java -
Step 1: Add failing simulator tests
Add a compact grid where shortest physical route has a live opposite reservation and a conflict-free path lies within 110%; assert the simulator still uses existing vehicle selection but chooses the safer approach/service route. Add a case where the clean detour exceeds 110%, and one where every candidate has temporary conflicts but the task remains dispatchable rather than NO_ROUTE. Assert selected distance, shortest distance, candidate count, stage and path version are stored.
- Step 2: Verify RED
mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulatorTest test
Expected: new safer-route/evidence assertions fail against BFS-only dispatch.
- Step 3: Integrate planning without changing vehicle assignment
In assignReadyTasks, generate an approach candidate set for each eligible vehicle only to prove that vehicle can physically reach the source; pass every reachable eligible vehicle unchanged to the existing VehicleAssignmentService, whose same-floor/floor/y/x/vehicle-ID ranking remains authoritative. After selection, build one immutable traffic snapshot, independently select the chosen vehicle's approach and the task's service decisions, splice without duplicating the source, and reserve the full selected route. Set plannedPath to the selected service path for compatibility and append both decisions to RoutePlanningEvidence with pathVersion=1.
Permanent candidate-set emptiness is the only route-planning NO_ROUTE. A non-empty set with conflicts remains eligible and is passed to reservation/traffic HOLD behavior.
- Step 4: Verify GREEN and existing fault behavior
mvn -f javaTest/pom.xml -Dtest=HistoricalDispatchSimulatorTest,HistoricalDispatchFaultMatrixTest test
Expected: all tests pass; vehicle eligibility, PLC retry and fault closure behavior remain green.
- Step 5: Commit
git add javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java
git commit -m "feat(javaTest): plan traffic-aware approach and service routes"
Task 5: Third Traffic HOLD Rerouting
Files:
-
Create:
javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/TrafficHoldTrackerTest.java -
Create:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/TrafficHoldTracker.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulator.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/SimulationTickEvent.java -
Modify:
javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulatorTest.java -
Step 1: Add failing policy and integration tests
Prove cycles 1 and 2 do not trigger, cycle 3 does, blocking-resource/reason/vehicle changes reset to 1, movement clears the streak, and PLC/fault/disconnect/low-battery events never enter the tracker. In simulator tests assert a strictly better remaining route causes REROUTE_TRIGGER then REROUTE; no better route yields REROUTE_REJECTED; failed atomic replacement preserves old route; a successful reroute cannot reroute again until one MOVE occurs.
- Step 2: Verify RED
mvn -f javaTest/pom.xml -Dtest=TrafficHoldTrackerTest,HistoricalDispatchSimulatorTest test
Expected: tracker types and reroute events are missing, and existing generic threshold remains 10.
- Step 3: Implement traffic-only reroute state machine
Use key (taskId, vehicleId, blockingResourceId, holdReason). Extract the blocking resource from the exact next node, canonical next edge, or corridor owner evidence. Only traffic-controller node/edge/opposite-direction decisions and CORRIDOR_DIRECTION_OWNED call the tracker. On the third identical HOLD:
- emit
REROUTE_TRIGGERwith streak/resource/reason; - snapshot traffic once;
- plan current position to source plus source to target before pickup, or current position to target after pickup;
- compare new and current remaining
RouteQualityusing the same evaluator; - require a different, strictly better, bounded candidate;
- call
replaceRoutebefore replacing the mutableActiveTask.routeand route index; - increment path version and reroute count only after replacement succeeds;
- require a subsequent MOVE before another ordinary reroute.
Store old/new remaining paths and both quality tuples in structured event detail rather than compressing them into display text. Keep the existing protocol-retry exhaustion and vehicle-fault redispatch paths separate.
- Step 4: Verify GREEN and safety tests
mvn -f javaTest/pom.xml -Dtest=TrafficHoldTrackerTest,HistoricalDispatchSimulatorTest,CorridorReservationManagerTest,SimulationInvariantSummaryTest test
Expected: all tests pass.
- Step 5: Commit
git add javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation javaTest/src/test/java/com/ft546/wcs/shadow/history/simulation
git commit -m "feat(javaTest): reroute after repeated traffic hold"
Task 6: Fair Historical Comparison and Report/API Evidence
Files:
-
Create:
javaTest/src/test/java/com/ft546/wcs/shadow/history/visualizer/HistoricalRouteQualityMapperTest.java -
Create:
javaTest/src/main/java/com/ft546/wcs/shadow/history/visualizer/HistoricalRouteQualityMapper.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/visualizer/RouteTopologyEvidenceMapper.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/visualizer/SimulationVisualizationMapper.java -
Modify:
javaTest/src/main/java/com/ft546/wcs/shadow/history/simulation/HistoricalDispatchSimulationReportWriter.java -
Modify: mapper and report-writer tests.
-
Step 1: Add failing mapping tests
Test all three input classifications with literal paths: valid matching endpoints is COMPARABLE; valid map path with wrong endpoints is ENDPOINT_MISMATCH; unknown or non-adjacent segment is INVALID_HISTORY_PATH and takes precedence. For comparable paths assert exact categories: EXACT_MATCH, SHORTER_PHYSICAL_DISTANCE, SAME_DISTANCE_BETTER_QUALITY, BOUNDED_DETOUR_FEWER_CONFLICTS, WORSE_QUALITY. Assert non-comparable tasks are excluded from optimization counts.
- Step 2: Verify RED
mvn -f javaTest/pom.xml -Dtest=HistoricalRouteQualityMapperTest,SimulationVisualizationMapperTest,HistoricalDispatchSimulationReportWriterTest test
Expected: new classification and evidence fields are absent.
- Step 3: Extend stored result mapping and text report
Expose per task:
routeComparability, routeQualityComparison,
approachPlanningEvidence, servicePlanningEvidence,
pathVersions, rerouteCount, rerouteEvents
Expose summary counts for all comparability/quality categories, bounded-route violations, candidate-limit hits, reroute triggers/success/rejection reasons. Preserve raw plannedPath and pathChanged, label them explicitly as compatibility evidence, and update plannerVersion to the bounded conflict-aware version. Keep timing and PLC retry under operational evidence, never route score.
- Step 4: Verify GREEN
mvn -f javaTest/pom.xml -Dtest=HistoricalRouteQualityMapperTest,RouteTopologyEvidenceMapperTest,SimulationVisualizationMapperTest,HistoricalDispatchSimulationReportWriterTest test
Expected: all tests pass.
- Step 5: Commit
git add javaTest/src/main/java/com/ft546/wcs/shadow/history javaTest/src/test/java/com/ft546/wcs/shadow/history
git commit -m "feat(javaTest): report auditable route quality evidence"
Task 7: Full-Map Route Decision and Reroute Inspector
Files:
-
Modify:
javaTest/src/main/resources/history-visualizer/index.html -
Modify:
javaTest/src/main/resources/history-visualizer/app.js -
Modify:
javaTest/src/main/resources/history-visualizer/app.css -
Modify:
javaTest/src/test/java/com/ft546/wcs/shadow/history/visualizer/HistoricalSimulationVisualizerServerTest.javaor the existing visualizer HTTP test that owns these resources. -
Step 1: Add failing API/resource interaction assertions
Extend the real visualizer integration fixture so its result JSON includes stage decisions and reroute versions. Assert the HTML has stable inspector containers and the script renders from approachPlanningEvidence, servicePlanningEvidence, and rerouteEvents, not by rerunning path logic in JavaScript.
- Step 2: Verify RED
mvn -f javaTest/pom.xml -Dtest=SimulationVisualizationMapperTest,*Visualizer*Test test
Expected: inspector payload/container assertions fail.
- Step 3: Implement the inspector
Keep the complete floor topology always visible. Add route-layer toggles for historical path, initial selected service route, current path version, actual MOVE trace, and HOLD/REROUTE points. In the task inspector show approach and service evidence in separate compact tables: shortest/selected coordinate distance, detour percent, candidate count/limit, each quality metric, decision reason and path version. Add a reroute timeline that selects a version and draws old/new remaining paths simultaneously with distinct solid/dashed styles. Mark ENDPOINT_MISMATCH and INVALID_HISTORY_PATH visibly so users cannot mistake raw path inequality for optimization.
- Step 4: Run focused tests and browser QA
mvn -f javaTest/pom.xml -Dtest=SimulationVisualizationMapperTest,*Visualizer*Test test
Then start the app on 127.0.0.1:18084, use the real point-to-point and historical result endpoints, and verify at desktop 1440x1000 and mobile 390x844: map nonblank, all route layers toggle, task selection updates evidence, reroute version selection changes overlays, no text overlap, no console error.
- Step 5: Commit
git add javaTest/src/main/resources/history-visualizer javaTest/src/test/java/com/ft546/wcs/shadow/history/visualizer
git commit -m "feat(javaTest): inspect bounded route decisions on full map"
Task 8: Full Regression, 240-Task Replay and Completion Audit
Files:
-
Modify only when a failing acceptance test exposes a real defect; add the reproducing test before the fix.
-
Update:
javaTest/README.mdwith route semantics, launch command and evidence legend. -
Step 1: Stop the visualizer and run clean regression
mvn -f javaTest/pom.xml clean test
Expected: zero failures/errors/skips. Record total test count from Surefire rather than reusing the old 645-test baseline.
- Step 2: Run the real 240-task replay
Run the established historical simulation application/report command and verify directly:
- completed + waiting + failed = 240;
- waiting = 0 and every task is terminal;
- selected approach/service distance is at most 110% plus numeric tolerance;
- every selected route is the lexicographic winner among emitted candidates;
- node double occupancy, edge capacity violation, opposite-direction swap and deadlock are all 0;
- archive count equals completed count with zero duplicate archive attempt;
- WMS business effects equal completed count with zero duplicate effect;
- every failure, HOLD, retry and reroute rejection has a nonblank reason.
Capture completed/waiting/failed, per-vehicle counts, vehicle changes, comparable-route quality counts, HOLD/retry reasons, waiting/completion average/P95/P99, historical-versus-simulation duration, reroute counts and safety/archive/WMS results.
- Step 3: Verify determinism
Execute the same replay twice and compare canonical route-decision output after excluding wall-clock/server metadata. Expected: identical vehicle choices, selected paths, quality tuples, reasons and path versions.
- Step 4: Browser verification and screenshots
Restart 127.0.0.1:18084; inspect at least one exact-match task, one endpoint mismatch, one invalid historical path, one bounded detour if produced, and one rerouted task if produced. Capture desktop and mobile screenshots and check browser console plus canvas/SVG pixel content.
- Step 5: Independent review and defect loop
Request a clean-context read-only code review from the design commit through current HEAD. Fix every Critical/Important finding with a failing regression test, rerun focused and full verification, and request a final finding check.
- Step 6: Update README and commit verification documentation
Document that this module is offline in-memory validation, route distance is coordinate units, timing is operational evidence, temporary conflicts do not imply NO_ROUTE, and production release still requires site/HIL validation.
git add javaTest/README.md
git commit -m "docs(javaTest): explain conflict-aware route audit"
Final Requirement Audit
Before completion, re-read the approved design and point each gate to fresh evidence:
- route bound, deterministic winner, temporary-conflict handling;
- traffic-only third-HOLD trigger and anti-oscillation;
- atomic replacement and segment-by-segment resource safety;
- 240-task terminal/archive/WMS closure;
- fair historical comparability;
- report/API/UI decision evidence;
- full Maven suite, replay, browser interaction, console and visual checks;
- independent review with no unresolved Critical or Important finding.
Do not describe the algorithm as production-proven. The valid conclusion is that the offline Java simulation satisfies its verified gates on the bundled map, task history and deterministic fault plan.