docs: complete shadow demo implementation plan

This commit is contained in:
zgw
2026-07-30 14:07:24 +08:00
parent 80a73337d2
commit 086b3c150b

View File

@@ -1,6 +1,6 @@
# WCS P0-B1 Offline SHADOW Demo Implementation Plan # 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. > **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 (`- [x]`) 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. **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.
@@ -37,7 +37,7 @@
- Produces: `ResourceKey.node(String)`, `edge(String,String)`, `conflict(String)` - Produces: `ResourceKey.node(String)`, `edge(String,String)`, `conflict(String)`
- Produces: `ResourceLedger.evaluate(String, Collection<ResourceKey>): ProtectionResult` - Produces: `ResourceLedger.evaluate(String, Collection<ResourceKey>): ProtectionResult`
- [ ] **Step 1: Write failing map and ledger tests** - [x] **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. Cover checksum mismatch, unconfirmed zone, canonical undirected edge key, zone non-exclusivity, same-node conflict, opposite-edge conflict, capacity, and non-conflicting parallel candidates.
@@ -47,23 +47,23 @@ assertTrue(ledger.evaluate("V1", Arrays.asList(ResourceKey.node("N1"))).isGrante
assertFalse(ledger.evaluate("V2", 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** - [x] **Step 2: Run the focused test and verify RED**
Run: `mvn -f javaTest/pom.xml -Dtest=MapAndResourceLedgerTest test` Run: `mvn -f javaTest/pom.xml -Dtest=MapAndResourceLedgerTest test`
Expected: compilation failure because the SHADOW types do not exist. Expected: compilation failure because the SHADOW types do not exist.
- [ ] **Step 3: Implement immutable map compilation and ledger evaluation** - [x] **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. `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** - [x] **Step 4: Run focused and existing tests**
Run: `mvn -f javaTest/pom.xml -Dtest=MapAndResourceLedgerTest test` Run: `mvn -f javaTest/pom.xml -Dtest=MapAndResourceLedgerTest test`
Run: `mvn -f javaTest/pom.xml test` Run: `mvn -f javaTest/pom.xml test`
- [ ] **Step 5: Commit** - [x] **Step 5: Commit**
```bash ```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 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
@@ -85,15 +85,15 @@ git commit -m "feat: model shadow traffic resources"
- Produces: `TrafficSegment.transition(SegmentEvent): TrafficSegment` - Produces: `TrafficSegment.transition(SegmentEvent): TrafficSegment`
- Produces: `SnapshotFreshnessPolicy.validate(previous,current,decisionTime): SnapshotHealth` - Produces: `SnapshotFreshnessPolicy.validate(previous,current,decisionTime): SnapshotHealth`
- [ ] **Step 1: Write failing state and snapshot tests** - [x] **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. 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** - [x] **Step 2: Run focused test and verify RED**
Run: `mvn -f javaTest/pom.xml -Dtest=SegmentAndSnapshotTest test` Run: `mvn -f javaTest/pom.xml -Dtest=SegmentAndSnapshotTest test`
- [ ] **Step 3: Implement state transitions and snapshot validation** - [x] **Step 3: Implement state transitions and snapshot validation**
Only allow: Only allow:
@@ -105,13 +105,13 @@ COMMITTED/EXECUTING -> FAULT_LOCKED
All snapshot lists and maps are defensive unmodifiable copies. All snapshot lists and maps are defensive unmodifiable copies.
- [ ] **Step 4: Run focused and full tests** - [x] **Step 4: Run focused and full tests**
Run: `mvn -f javaTest/pom.xml -Dtest=SegmentAndSnapshotTest test` Run: `mvn -f javaTest/pom.xml -Dtest=SegmentAndSnapshotTest test`
Run: `mvn -f javaTest/pom.xml test` Run: `mvn -f javaTest/pom.xml test`
- [ ] **Step 5: Commit** - [x] **Step 5: Commit**
```bash ```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 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
@@ -132,7 +132,7 @@ git commit -m "feat: validate shadow segment snapshots"
- Produces: `WaitForGraph.wouldCreateCycle(waiter,holders): boolean` - Produces: `WaitForGraph.wouldCreateCycle(waiter,holders): boolean`
- Produces: `RollingDispatchPolicy.decide(List<ShadowCandidate>, ResourceLedger, EffectiveTrafficMap): List<ShadowDecision>` - Produces: `RollingDispatchPolicy.decide(List<ShadowCandidate>, ResourceLedger, EffectiveTrafficMap): List<ShadowDecision>`
- [ ] **Step 1: Write failing deterministic decision tests** - [x] **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. 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.
@@ -143,21 +143,21 @@ assertEquals(DecisionType.HOLD, cycleDecision.getType());
assertEquals("WAIT_CYCLE", cycleDecision.getReasonCode()); assertEquals("WAIT_CYCLE", cycleDecision.getReasonCode());
``` ```
- [ ] **Step 2: Run focused test and verify RED** - [x] **Step 2: Run focused test and verify RED**
Run: `mvn -f javaTest/pom.xml -Dtest=RollingDispatchPolicyTest test` Run: `mvn -f javaTest/pom.xml -Dtest=RollingDispatchPolicyTest test`
- [ ] **Step 3: Implement deterministic rolling policy** - [x] **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. 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** - [x] **Step 4: Run focused and full tests**
Run: `mvn -f javaTest/pom.xml -Dtest=RollingDispatchPolicyTest test` Run: `mvn -f javaTest/pom.xml -Dtest=RollingDispatchPolicyTest test`
Run: `mvn -f javaTest/pom.xml test` Run: `mvn -f javaTest/pom.xml test`
- [ ] **Step 5: Commit** - [x] **Step 5: Commit**
```bash ```bash
git add javaTest/src/main/java/com/ft546/wcs/shadow/decision javaTest/src/test/java/com/ft546/wcs/shadow/RollingDispatchPolicyTest.java git add javaTest/src/main/java/com/ft546/wcs/shadow/decision javaTest/src/test/java/com/ft546/wcs/shadow/RollingDispatchPolicyTest.java
@@ -175,25 +175,25 @@ git commit -m "feat: decide shadow traffic safely"
**Interfaces:** **Interfaces:**
- Produces: `FeedbackReconciler.reconcile(TrafficSegment, ExecutionFeedback): FeedbackResult` - Produces: `FeedbackReconciler.reconcile(TrafficSegment, ExecutionFeedback): FeedbackResult`
- [ ] **Step 1: Write failing feedback tests** - [x] **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. 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** - [x] **Step 2: Run focused test and verify RED**
Run: `mvn -f javaTest/pom.xml -Dtest=FeedbackReconcilerTest test` Run: `mvn -f javaTest/pom.xml -Dtest=FeedbackReconcilerTest test`
- [ ] **Step 3: Implement matching and release rules** - [x] **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. 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** - [x] **Step 4: Run focused and full tests**
Run: `mvn -f javaTest/pom.xml -Dtest=FeedbackReconcilerTest test` Run: `mvn -f javaTest/pom.xml -Dtest=FeedbackReconcilerTest test`
Run: `mvn -f javaTest/pom.xml test` Run: `mvn -f javaTest/pom.xml test`
- [ ] **Step 5: Commit** - [x] **Step 5: Commit**
```bash ```bash
git add javaTest/src/main/java/com/ft546/wcs/shadow/feedback javaTest/src/test/java/com/ft546/wcs/shadow/FeedbackReconcilerTest.java git add javaTest/src/main/java/com/ft546/wcs/shadow/feedback javaTest/src/test/java/com/ft546/wcs/shadow/FeedbackReconcilerTest.java
@@ -218,25 +218,25 @@ git commit -m "feat: reconcile feedback fail closed"
- Produces: `DecisionReplayService.read(InputStream): DecisionEvent` - Produces: `DecisionReplayService.read(InputStream): DecisionEvent`
- Produces: `DecisionReplayService.replay(DecisionEvent): List<ShadowDecision>` - Produces: `DecisionReplayService.replay(DecisionEvent): List<ShadowDecision>`
- [ ] **Step 1: Write failing guard and replay tests** - [x] **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. 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** - [x] **Step 2: Run focused tests and verify RED**
Run: `mvn -f javaTest/pom.xml -Dtest=ShadowCoordinatorReplayTest,DemoScenarioTest test` Run: `mvn -f javaTest/pom.xml -Dtest=ShadowCoordinatorReplayTest,DemoScenarioTest test`
- [ ] **Step 3: Implement coordinator, guard, event hash, and replay** - [x] **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. 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** - [x] **Step 4: Run focused tests and executable demo**
Run: `mvn -f javaTest/pom.xml -Dtest=ShadowCoordinatorReplayTest,DemoScenarioTest test` Run: `mvn -f javaTest/pom.xml -Dtest=ShadowCoordinatorReplayTest,DemoScenarioTest test`
Run: `mvn -f javaTest/pom.xml exec:java` Run: `mvn -f javaTest/pom.xml exec:java`
- [ ] **Step 5: Commit** - [x] **Step 5: Commit**
```bash ```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 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
@@ -253,19 +253,19 @@ git commit -m "feat: replay guarded shadow decisions"
- Consumes: `RollingDispatchPolicy`, `ResourceLedger`, `FeedbackReconciler` - Consumes: `RollingDispatchPolicy`, `ResourceLedger`, `FeedbackReconciler`
- Produces: repeatable invariant regression output including seed, map version, and input summary. - Produces: repeatable invariant regression output including seed, map version, and input summary.
- [ ] **Step 1: Write fixed-seed invariant tests** - [x] **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. 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** - [x] **Step 2: Run property test**
Run: `mvn -f javaTest/pom.xml -Dtest=ShadowInvariantPropertyTest test` Run: `mvn -f javaTest/pom.xml -Dtest=ShadowInvariantPropertyTest test`
- [ ] **Step 3: Update README** - [x] **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. 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** - [x] **Step 4: Run final verification**
Run: Run:
@@ -276,10 +276,11 @@ 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-*`. 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** - [x] **Step 5: Commit**
```bash ```bash
git add javaTest/src/test/java/com/ft546/wcs/shadow/ShadowInvariantPropertyTest.java javaTest/README.md git add javaTest/src/test/java/com/ft546/wcs/shadow/ShadowInvariantPropertyTest.java javaTest/README.md
git commit -m "test: verify shadow traffic invariants" git commit -m "test: verify shadow traffic invariants"
``` ```