From d691b55e4c5c34a8d12a7839037d76a553177331 Mon Sep 17 00:00:00 2001 From: zgw <13623675548@163.com> Date: Thu, 30 Jul 2026 13:37:16 +0800 Subject: [PATCH] docs: plan p0-b1 shadow demo expansion --- .../plans/2026-07-30-wcs-p0-b1-shadow-demo.md | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 docs/superpowers/plans/2026-07-30-wcs-p0-b1-shadow-demo.md diff --git a/docs/superpowers/plans/2026-07-30-wcs-p0-b1-shadow-demo.md b/docs/superpowers/plans/2026-07-30-wcs-p0-b1-shadow-demo.md new file mode 100644 index 0000000..597c155 --- /dev/null +++ b/docs/superpowers/plans/2026-07-30-wcs-p0-b1-shadow-demo.md @@ -0,0 +1,285 @@ +# WCS P0-B1 Offline SHADOW 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:** Extend `javaTest` with a deterministic, fail-closed, in-memory P0-B1 SHADOW traffic-control kernel without changing the existing LEGACY demo or production modules. + +**Architecture:** New code lives under `com.ft546.wcs.shadow` and reads immutable snapshots to produce `GRANT/HOLD/YIELD` decisions and replayable events. The SHADOW application layer receives read-only resource state and write-forbidden ports, while state-machine and feedback tests exercise simulated HARD/UNKNOWN_HARD contracts independently of authoritative LEGACY state. + +**Tech Stack:** Java 8, Maven, JUnit Jupiter 5.10.2, Jackson Databind 2.17.2, Surefire 3.2.5. + +## Global Constraints + +- Keep Java source and target compatibility at Java 8. +- Keep all existing LEGACY behavior and tests passing. +- Do not modify any `ruoyi-*` production code. +- Do not connect SQL Server, PLC, WMS, Spring, or network services. +- SHADOW must not write PLC commands, LEGACY business state, or authoritative reservations. +- Traffic zones are coordination/version boundaries, not implicit capacity-one resources. +- `HARD` and `UNKNOWN_HARD` are released only by matching feedback, never by ETA expiry. +- Unknown cargo, lift signals, restart, disconnect, and feedback mismatch fail closed. +- The result is offline SHADOW simulation evidence, not field SHADOW, HIL, ACTIVE, or production evidence. + +--- + +### Task 1: Versioned Map and Resource Ledger + +**Files:** +- Modify: `javaTest/pom.xml` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/map/EffectiveTrafficMap.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/map/TrafficMapCompiler.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/resource/ResourceKey.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/resource/ResourceLedger.java` +- Test: `javaTest/src/test/java/com/ft546/wcs/shadow/MapAndResourceLedgerTest.java` + +**Interfaces:** +- Produces: `TrafficMapCompiler.compile(MapDefinition): EffectiveTrafficMap` +- Produces: `ResourceKey.node(String)`, `edge(String,String)`, `conflict(String)` +- Produces: `ResourceLedger.evaluate(String, Collection): ProtectionResult` + +- [ ] **Step 1: Write failing map and ledger tests** + +Cover checksum mismatch, unconfirmed zone, canonical undirected edge key, zone non-exclusivity, same-node conflict, opposite-edge conflict, capacity, and non-conflicting parallel candidates. + +```java +assertEquals("EDGE:A:B", ResourceKey.edge("B", "A").value()); +assertTrue(ledger.evaluate("V1", Arrays.asList(ResourceKey.node("N1"))).isGranted()); +assertFalse(ledger.evaluate("V2", Arrays.asList(ResourceKey.node("N1"))).isGranted()); +``` + +- [ ] **Step 2: Run the focused test and verify RED** + +Run: `mvn -f javaTest/pom.xml -Dtest=MapAndResourceLedgerTest test` + +Expected: compilation failure because the SHADOW types do not exist. + +- [ ] **Step 3: Implement immutable map compilation and ledger evaluation** + +`EffectiveTrafficMap` exposes immutable nodes, edges, capacities, safe wait/yield sites, `mapCode`, `versionId`, and checksum. `ResourceLedger` copies authoritative protection input and mutates only its private simulation state. + +- [ ] **Step 4: Run focused and existing tests** + +Run: `mvn -f javaTest/pom.xml -Dtest=MapAndResourceLedgerTest test` + +Run: `mvn -f javaTest/pom.xml test` + +- [ ] **Step 5: Commit** + +```bash +git add javaTest/pom.xml javaTest/src/main/java/com/ft546/wcs/shadow/map javaTest/src/main/java/com/ft546/wcs/shadow/resource javaTest/src/test/java/com/ft546/wcs/shadow/MapAndResourceLedgerTest.java +git commit -m "feat: model shadow traffic resources" +``` + +### Task 2: Segment State and Immutable Snapshot + +**Files:** +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/segment/ReservationState.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/segment/SegmentState.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/segment/TrafficSegment.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/snapshot/TrafficVehicleSnapshot.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/snapshot/TrafficSnapshot.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/snapshot/SnapshotFreshnessPolicy.java` +- Test: `javaTest/src/test/java/com/ft546/wcs/shadow/SegmentAndSnapshotTest.java` + +**Interfaces:** +- Produces: `TrafficSegment.transition(SegmentEvent): TrafficSegment` +- Produces: `SnapshotFreshnessPolicy.validate(previous,current,decisionTime): SnapshotHealth` + +- [ ] **Step 1: Write failing state and snapshot tests** + +Assert PREPARED cannot jump to EXECUTING, COMMIT uncertainty creates UNKNOWN_HARD, snapshot collections are frozen, stale snapshots are rejected, sequence rollback is rejected, and boot ID change quarantines the vehicle. + +- [ ] **Step 2: Run focused test and verify RED** + +Run: `mvn -f javaTest/pom.xml -Dtest=SegmentAndSnapshotTest test` + +- [ ] **Step 3: Implement state transitions and snapshot validation** + +Only allow: + +```text +SOFT_PLANNED -> PREPARING -> PREPARED -> COMMITTING -> COMMITTED -> EXECUTING -> COMPLETED +COMMITTING -> COMMIT_UNCERTAIN +COMMITTED/EXECUTING -> FAULT_LOCKED +``` + +All snapshot lists and maps are defensive unmodifiable copies. + +- [ ] **Step 4: Run focused and full tests** + +Run: `mvn -f javaTest/pom.xml -Dtest=SegmentAndSnapshotTest test` + +Run: `mvn -f javaTest/pom.xml test` + +- [ ] **Step 5: Commit** + +```bash +git add javaTest/src/main/java/com/ft546/wcs/shadow/segment javaTest/src/main/java/com/ft546/wcs/shadow/snapshot javaTest/src/test/java/com/ft546/wcs/shadow/SegmentAndSnapshotTest.java +git commit -m "feat: validate shadow segment snapshots" +``` + +### Task 3: Wait Graph and Rolling Decisions + +**Files:** +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/decision/DecisionType.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/decision/ShadowCandidate.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/decision/ShadowDecision.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/decision/WaitForGraph.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/decision/RollingDispatchPolicy.java` +- Test: `javaTest/src/test/java/com/ft546/wcs/shadow/RollingDispatchPolicyTest.java` + +**Interfaces:** +- Produces: `WaitForGraph.wouldCreateCycle(waiter,holders): boolean` +- Produces: `RollingDispatchPolicy.decide(List, ResourceLedger, EffectiveTrafficMap): List` + +- [ ] **Step 1: Write failing deterministic decision tests** + +Cover stable priority/aging/task/vehicle ordering, same-node and opposite-edge HOLD, non-conflicting parallel GRANT, committed segment non-revocation, cycle rejection, safe YIELD, and no-safe-yield HOLD. + +```java +assertEquals(Arrays.asList("V1", "V2"), decisions.stream() + .map(ShadowDecision::getVehicleId).collect(Collectors.toList())); +assertEquals(DecisionType.HOLD, cycleDecision.getType()); +assertEquals("WAIT_CYCLE", cycleDecision.getReasonCode()); +``` + +- [ ] **Step 2: Run focused test and verify RED** + +Run: `mvn -f javaTest/pom.xml -Dtest=RollingDispatchPolicyTest test` + +- [ ] **Step 3: Implement deterministic rolling policy** + +Sort by committed continuation, emergency, business priority descending, wait age descending, clearance cost ascending, task ID, and vehicle ID. Every non-GRANT decision includes reason code, conflicting resources, and blocking vehicles. + +- [ ] **Step 4: Run focused and full tests** + +Run: `mvn -f javaTest/pom.xml -Dtest=RollingDispatchPolicyTest test` + +Run: `mvn -f javaTest/pom.xml test` + +- [ ] **Step 5: Commit** + +```bash +git add javaTest/src/main/java/com/ft546/wcs/shadow/decision javaTest/src/test/java/com/ft546/wcs/shadow/RollingDispatchPolicyTest.java +git commit -m "feat: decide shadow traffic safely" +``` + +### Task 4: Feedback Reconciliation and Fail-Closed Recovery + +**Files:** +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/feedback/ExecutionFeedback.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/feedback/FeedbackResult.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/feedback/FeedbackReconciler.java` +- Test: `javaTest/src/test/java/com/ft546/wcs/shadow/FeedbackReconcilerTest.java` + +**Interfaces:** +- Produces: `FeedbackReconciler.reconcile(TrafficSegment, ExecutionFeedback): FeedbackResult` + +- [ ] **Step 1: Write failing feedback tests** + +Cover A-to-B release, destination retention, duplicate snapshot idempotency, ETA expiry retention, version mismatch, skip, rollback, disconnect, ACK loss, and PLC restart. + +- [ ] **Step 2: Run focused test and verify RED** + +Run: `mvn -f javaTest/pom.xml -Dtest=FeedbackReconcilerTest test` + +- [ ] **Step 3: Implement matching and release rules** + +Only matching boot ID, epoch, plan version, segment sequence, increasing snapshot sequence, and legal path suffix can release resources. Every mismatch returns quarantined `UNKNOWN_HARD` with zero released resources. + +- [ ] **Step 4: Run focused and full tests** + +Run: `mvn -f javaTest/pom.xml -Dtest=FeedbackReconcilerTest test` + +Run: `mvn -f javaTest/pom.xml test` + +- [ ] **Step 5: Commit** + +```bash +git add javaTest/src/main/java/com/ft546/wcs/shadow/feedback javaTest/src/test/java/com/ft546/wcs/shadow/FeedbackReconcilerTest.java +git commit -m "feat: reconcile feedback fail closed" +``` + +### Task 5: SHADOW Guard, Events, JSON Replay, and Demo + +**Files:** +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/application/ShadowWriteForbiddenException.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/application/ShadowWritePort.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/application/ShadowTrafficCoordinator.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/replay/DecisionEvent.java` +- Create: `javaTest/src/main/java/com/ft546/wcs/shadow/replay/DecisionReplayService.java` +- Create: `javaTest/src/test/resources/shadow/golden/basic-conflict.json` +- Create: `javaTest/src/test/java/com/ft546/wcs/shadow/ShadowCoordinatorReplayTest.java` +- Modify: `javaTest/src/main/java/com/ft546/wcs/demo/DemoApplication.java` +- Modify: `javaTest/src/test/java/com/ft546/wcs/demo/DemoScenarioTest.java` + +**Interfaces:** +- Produces: `ShadowTrafficCoordinator.run(TrafficSnapshot,List): DecisionEvent` +- Produces: `DecisionReplayService.read(InputStream): DecisionEvent` +- Produces: `DecisionReplayService.replay(DecisionEvent): List` + +- [ ] **Step 1: Write failing guard and replay tests** + +Assert PLC/business/reservation writes all throw, coordinator leaves LEGACY state unchanged, JSON replay reproduces type/reason/resources, and Demo output contains an explicit offline SHADOW summary. + +- [ ] **Step 2: Run focused tests and verify RED** + +Run: `mvn -f javaTest/pom.xml -Dtest=ShadowCoordinatorReplayTest,DemoScenarioTest test` + +- [ ] **Step 3: Implement coordinator, guard, event hash, and replay** + +Use Jackson only at the replay boundary. Hash canonical event input with SHA-256. The coordinator records intended decisions but never invokes a mutable external port. + +- [ ] **Step 4: Run focused tests and executable demo** + +Run: `mvn -f javaTest/pom.xml -Dtest=ShadowCoordinatorReplayTest,DemoScenarioTest test` + +Run: `mvn -f javaTest/pom.xml exec:java` + +- [ ] **Step 5: Commit** + +```bash +git add javaTest/pom.xml javaTest/src/main/java/com/ft546/wcs/shadow/application javaTest/src/main/java/com/ft546/wcs/shadow/replay javaTest/src/test/resources/shadow javaTest/src/main/java/com/ft546/wcs/demo/DemoApplication.java javaTest/src/test +git commit -m "feat: replay guarded shadow decisions" +``` + +### Task 6: Fixed-Seed Invariants and Documentation + +**Files:** +- Create: `javaTest/src/test/java/com/ft546/wcs/shadow/ShadowInvariantPropertyTest.java` +- Modify: `javaTest/README.md` + +**Interfaces:** +- Consumes: `RollingDispatchPolicy`, `ResourceLedger`, `FeedbackReconciler` +- Produces: repeatable invariant regression output including seed, map version, and input summary. + +- [ ] **Step 1: Write fixed-seed invariant tests** + +For seeds `546001` through `546010`, generate bounded 2-to-8 vehicle candidate sets and assert capacity never exceeds limits, committed wait graph remains acyclic, the same input gives the same decisions, and fault/unknown feedback never frees resources. + +- [ ] **Step 2: Run property test** + +Run: `mvn -f javaTest/pom.xml -Dtest=ShadowInvariantPropertyTest test` + +- [ ] **Step 3: Update README** + +Document package boundaries, `mvn clean test`, `mvn exec:java`, covered P0-B1 scenarios, and the explicit exclusions for SQL, PLC, HIL, real SHADOW, ACTIVE, and production. + +- [ ] **Step 4: Run final verification** + +Run: + +```bash +mvn -f javaTest/pom.xml clean test +mvn -f javaTest/pom.xml exec:java +``` + +Inspect Surefire XML and require `tests > 0`, `failures = 0`, `errors = 0`, and `skipped = 0`. Run `git diff --check` and confirm no changed path under `ruoyi-*`. + +- [ ] **Step 5: Commit** + +```bash +git add javaTest/src/test/java/com/ft546/wcs/shadow/ShadowInvariantPropertyTest.java javaTest/README.md +git commit -m "test: verify shadow traffic invariants" +``` +