From baf1a7a138976f098ddbbf95a9373e0ed4adebe0 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 24 三月 2026 16:46:13 +0800
Subject: [PATCH] docs: add station reroute refactor plan

---
 docs/superpowers/plans/2026-03-24-station-reroute-refactor.md |  337 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 337 insertions(+), 0 deletions(-)

diff --git a/docs/superpowers/plans/2026-03-24-station-reroute-refactor.md b/docs/superpowers/plans/2026-03-24-station-reroute-refactor.md
new file mode 100644
index 0000000..d69fca0
--- /dev/null
+++ b/docs/superpowers/plans/2026-03-24-station-reroute-refactor.md
@@ -0,0 +1,337 @@
+# Station Reroute Refactor 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:** Refactor `StationOperateProcessUtils` so run-block reroute, idle recover reroute, out-order dispatch, and watch-circle dispatch all execute through one shared reroute pipeline without changing current business behavior.
+
+**Architecture:** Keep the four public scan methods as entry points, but move shared reroute work into one internal pipeline inside `StationOperateProcessUtils`: context loading, decision resolution, command-plan building, execution guards, and post-dispatch effects. Keep `ZyStationV5Thread`, `StationMoveCoordinator`, Redis key usage, and current dispatch semantics unchanged; only reorganize code paths and add focused regression tests around the new seams.
+
+**Tech Stack:** Java 17, Spring Boot 3.5, MyBatis-Plus, RedisUtil, JUnit 5, Mockito
+
+---
+
+## File Map
+
+- Modify: `pom.xml`
+  - Add the minimal test dependency required to run focused JUnit 5 / Mockito tests.
+- Modify: `src/main/java/com/zy/core/utils/StationOperateProcessUtils.java`
+  - Introduce shared reroute context / decision / command-plan structures and move the repeated flow into one pipeline.
+- Create: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+  - Cover the new package-private reroute seams and guard ordering with focused unit tests.
+
+### Task 1: Add Test Harness For The New Reroute Seams
+
+**Files:**
+- Modify: `pom.xml`
+- Create: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+
+- [ ] **Step 1: Write the failing test file for the reroute seam**
+
+```java
+package com.zy.core.utils;
+
+import org.junit.jupiter.api.Test;
+
+class StationOperateProcessUtilsReroutePipelineTest {
+
+    @Test
+    void choosesRunBlockCommandBuilderForRunBlockRerouteScene() {
+        // compile-time failing seam: package-private helper does not exist yet
+        StationOperateProcessUtils.RerouteSceneType scene =
+                StationOperateProcessUtils.RerouteSceneType.RUN_BLOCK_REROUTE;
+    }
+}
+```
+
+- [ ] **Step 2: Run the test to verify it fails**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest test`
+Expected: FAIL because JUnit test dependency and/or the new reroute seam types are missing.
+
+- [ ] **Step 3: Add minimal test dependency and keep scope tight**
+
+```xml
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-test</artifactId>
+    <scope>test</scope>
+</dependency>
+```
+
+- [ ] **Step 4: Re-run the same test to verify it still fails for the right reason**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest test`
+Expected: FAIL because `RerouteSceneType` and the package-private reroute seam types do not exist yet.
+
+- [ ] **Step 5: Commit the harness-only change**
+
+```bash
+git add pom.xml src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java
+git commit -m "test: add station reroute pipeline harness"
+```
+
+### Task 2: Extract Shared Reroute Types And The First Decision Seam
+
+**Files:**
+- Modify: `src/main/java/com/zy/core/utils/StationOperateProcessUtils.java`
+- Modify: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+
+- [ ] **Step 1: Write a failing test for the first shared decision seam**
+
+```java
+@Test
+void resolveExecutionTarget_skipsWhenTargetEqualsCurrentStation() {
+    StationOperateProcessUtils.RerouteDecision decision =
+            StationOperateProcessUtils.RerouteDecision.skip("same-station");
+
+    assert decision.skip();
+    assert "same-station".equals(decision.skipReason());
+}
+```
+
+- [ ] **Step 2: Run the focused test to verify it fails**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#resolveExecutionTarget_skipsWhenTargetEqualsCurrentStation test`
+Expected: FAIL because `RerouteDecision` and its skip contract do not exist yet.
+
+- [ ] **Step 3: Add the minimal shared reroute types in `StationOperateProcessUtils.java`**
+
+```java
+static enum RerouteSceneType {
+    RUN_BLOCK_REROUTE,
+    IDLE_RECOVER,
+    OUT_ORDER,
+    WATCH_CIRCLE
+}
+
+static final class RerouteDecision {
+    private final boolean skip;
+    private final String skipReason;
+    private final Integer targetStationId;
+
+    static RerouteDecision skip(String reason) {
+        return new RerouteDecision(true, reason, null);
+    }
+}
+```
+
+Implementation notes:
+- Keep these types inside `StationOperateProcessUtils.java`.
+- Make them package-private or static nested so tests in the same package can reach them without creating a new runtime component.
+- Do not change public behavior yet.
+
+- [ ] **Step 4: Re-run the focused test to verify it passes**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#resolveExecutionTarget_skipsWhenTargetEqualsCurrentStation test`
+Expected: PASS
+
+- [ ] **Step 5: Commit the shared-type extraction**
+
+```bash
+git add src/main/java/com/zy/core/utils/StationOperateProcessUtils.java src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java
+git commit -m "refactor: add station reroute shared types"
+```
+
+### Task 3: Build The Shared Execution Guards And Command Plan
+
+**Files:**
+- Modify: `src/main/java/com/zy/core/utils/StationOperateProcessUtils.java`
+- Modify: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+
+- [ ] **Step 1: Write failing tests for guard behavior and command-builder selection**
+
+```java
+@Test
+void buildCommandPlan_usesRunBlockCommandBuilderForRunBlockScene() {
+    // arrange mocked StationThread and context
+    // assert getRunBlockRerouteCommand is chosen
+}
+
+@Test
+void executePlan_skipsWhenCurrentTaskStillExistsInBuffer() {
+    // arrange task buffer with current taskNo
+    // assert executePlan returns skipped result and does not dispatch
+}
+```
+
+- [ ] **Step 2: Run the focused tests to verify they fail**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#buildCommandPlan_usesRunBlockCommandBuilderForRunBlockScene,StationOperateProcessUtilsReroutePipelineTest#executePlan_skipsWhenCurrentTaskStillExistsInBuffer test`
+Expected: FAIL because shared plan/guard methods do not exist yet.
+
+- [ ] **Step 3: Add the package-private execution helpers and keep order explicit**
+
+```java
+RerouteCommandPlan buildRerouteCommandPlan(RerouteContext context, RerouteDecision decision) { ... }
+
+RerouteExecutionResult executeReroutePlan(RerouteContext context, RerouteCommandPlan plan) { ... }
+```
+
+Implementation notes:
+- Keep buffer guard, recent-dispatch idle guard, out-order lock, and short-term dedup in one place.
+- Preserve current order:
+  - cancel session when the scene requires it
+  - reset segment commands when the scene requires it
+  - clear idle-issued commands only for idle recover
+  - dispatch command
+  - apply post-dispatch effects only after successful dispatch
+- Do not migrate the four public entry methods yet; only make the shared helpers real.
+
+- [ ] **Step 4: Re-run the focused tests to verify they pass**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#buildCommandPlan_usesRunBlockCommandBuilderForRunBlockScene,StationOperateProcessUtilsReroutePipelineTest#executePlan_skipsWhenCurrentTaskStillExistsInBuffer test`
+Expected: PASS
+
+- [ ] **Step 5: Commit the shared plan/guard layer**
+
+```bash
+git add src/main/java/com/zy/core/utils/StationOperateProcessUtils.java src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java
+git commit -m "refactor: add station reroute execution pipeline"
+```
+
+### Task 4: Migrate `checkStationOutOrder` And `watchCircleStation` To The Shared Pipeline
+
+**Files:**
+- Modify: `src/main/java/com/zy/core/utils/StationOperateProcessUtils.java`
+- Modify: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+
+- [ ] **Step 1: Write failing tests for the shared out-order / watch-circle flow**
+
+```java
+@Test
+void outOrderAndWatchCircle_shareDecisionAndPostDispatchEffects() {
+    // arrange equivalent contexts with different scene types
+    // assert both use shared decision flow and sync watch state correctly
+}
+```
+
+- [ ] **Step 2: Run the focused test to verify it fails**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#outOrderAndWatchCircle_shareDecisionAndPostDispatchEffects test`
+Expected: FAIL because the entry methods still duplicate their own execution logic.
+
+- [ ] **Step 3: Migrate the two entry methods to the shared pipeline**
+
+```java
+public synchronized void checkStationOutOrder() {
+    // scan candidates
+    // build context
+    // executeReroute(context)
+}
+
+public synchronized void watchCircleStation() {
+    // scan candidates
+    // build context
+    // executeReroute(context)
+}
+```
+
+Implementation notes:
+- Keep the candidate scan conditions exactly as they are today.
+- Do not change `resolveOutboundDispatchDecision`.
+- Keep `syncOutOrderWatchState` and `recordDispatch` conditions identical.
+
+- [ ] **Step 4: Re-run the focused test to verify it passes**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#outOrderAndWatchCircle_shareDecisionAndPostDispatchEffects test`
+Expected: PASS
+
+- [ ] **Step 5: Commit the out-order migration**
+
+```bash
+git add src/main/java/com/zy/core/utils/StationOperateProcessUtils.java src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java
+git commit -m "refactor: unify station out-order reroute flow"
+```
+
+### Task 5: Migrate `checkStationRunBlock` And `checkStationIdleRecover` To The Shared Pipeline
+
+**Files:**
+- Modify: `src/main/java/com/zy/core/utils/StationOperateProcessUtils.java`
+- Modify: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+
+- [ ] **Step 1: Write failing tests for run-block and idle-recover specific behavior**
+
+```java
+@Test
+void runBlockReroute_keepsDirectReassignAndNormalRerouteSeparate() {
+    // assert inbound run-block reassign does not use the normal reroute command path
+}
+
+@Test
+void idleRecover_skipsWhenLastDispatchIsTooRecent() {
+    // assert the existing recent-dispatch protection still short-circuits the reroute
+}
+```
+
+- [ ] **Step 2: Run the focused tests to verify they fail**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#runBlockReroute_keepsDirectReassignAndNormalRerouteSeparate,StationOperateProcessUtilsReroutePipelineTest#idleRecover_skipsWhenLastDispatchIsTooRecent test`
+Expected: FAIL because the public methods still own their own scene-specific flow.
+
+- [ ] **Step 3: Migrate the two entry methods without changing semantics**
+
+```java
+public synchronized void checkStationRunBlock() {
+    // keep candidate scan and lock acquisition
+    // delegate each candidate to executeReroute(context)
+}
+
+private void checkStationIdleRecover(...) {
+    // keep candidate scan and idle-track touch
+    // delegate the reroute execution to executeReroute(context)
+}
+```
+
+Implementation notes:
+- Keep inbound run-block reassign flow intact, including WMS call, source/target loc updates, and task update order.
+- Keep idle recover command cleanup count and log message intact.
+- Preserve run-block lock and idle lock behavior.
+
+- [ ] **Step 4: Re-run the focused tests to verify they pass**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest#runBlockReroute_keepsDirectReassignAndNormalRerouteSeparate,StationOperateProcessUtilsReroutePipelineTest#idleRecover_skipsWhenLastDispatchIsTooRecent test`
+Expected: PASS
+
+- [ ] **Step 5: Commit the final migration**
+
+```bash
+git add src/main/java/com/zy/core/utils/StationOperateProcessUtils.java src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java
+git commit -m "refactor: unify station run-block and idle reroute flow"
+```
+
+### Task 6: Run Full Verification And Clean Up The Diff
+
+**Files:**
+- Modify: `src/main/java/com/zy/core/utils/StationOperateProcessUtils.java`
+- Modify: `src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java`
+- Modify: `pom.xml`
+
+- [ ] **Step 1: Run the focused regression test class**
+
+Run: `mvn -q -Dtest=StationOperateProcessUtilsReroutePipelineTest test`
+Expected: PASS
+
+- [ ] **Step 2: Run compile verification**
+
+Run: `mvn -q -DskipTests compile`
+Expected: PASS
+
+- [ ] **Step 3: If test runtime is stable, run the full test command**
+
+Run: `mvn test`
+Expected: PASS, or document the exact blocker if legacy environment/test setup prevents it.
+
+- [ ] **Step 4: Review the final diff against the approved spec**
+
+Checklist:
+- The four public entry methods still exist.
+- `ZyStationV5Thread`, `StationMoveCoordinator`, Redis key names, and WMS interactions are unchanged.
+- Shared reroute flow is centralized.
+- No unrelated business behavior was added.
+
+- [ ] **Step 5: Commit the verified implementation**
+
+```bash
+git add pom.xml src/main/java/com/zy/core/utils/StationOperateProcessUtils.java src/test/java/com/zy/core/utils/StationOperateProcessUtilsReroutePipelineTest.java
+git commit -m "refactor: unify station reroute execution flow"
+```

--
Gitblit v1.9.1