From dc3f9cc91759823ce59486f19b138be4b296a0f1 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 28 四月 2026 09:43:28 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java | 2300 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 1,729 insertions(+), 571 deletions(-)

diff --git a/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java b/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
index 4530d45..9f4b38f 100644
--- a/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
+++ b/src/main/java/com/zy/core/network/fake/ZyStationFakeSegConnect.java
@@ -11,82 +11,117 @@
 import com.zy.core.model.command.StationCommand;
 import com.zy.core.network.api.ZyStationConnectApi;
 import com.zy.core.network.entity.ZyStationStatusEntity;
+
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Random;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.Map;
-import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class ZyStationFakeSegConnect implements ZyStationConnectApi {
 
-    // 绔欑偣绾ч攣锛氭瘡涓珯鐐圭嫭绔嬩竴鎶婇攣锛屾彁鍗囧苟鍙戞�ц兘
-    private final Map<Integer, ReentrantLock> stationLocks = new ConcurrentHashMap<>();
-    private HashMap<Integer, List<ZyStationStatusEntity>> deviceStatusMap = new HashMap<>();
-    private HashMap<Integer, DeviceConfig> deviceConfigMap = new HashMap<>();
+    private long getWaitSegmentTimeoutMs() {
+        return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_STATION_SEGMENT_WAIT_TIMEOUT_MS, 30000L);
+    }
+
+    private long getMoveStepDurationMs() {
+        return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_STATION_MOVE_STEP_DURATION_MS, 500L);
+    }
+
+    private long getIdleLoopDelayMs() {
+        return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_STATION_IDLE_LOOP_DELAY_MS, 200L);
+    }
+
+    private long getBlockedLoopDelayMs() {
+        return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_STATION_BLOCKED_LOOP_DELAY_MS, 1000L);
+    }
+
+    private long getInitializeDelayMs() {
+        return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_STATION_INITIALIZE_DELAY_MS, 0L);
+    }
+
+    private long getFinishDelayMs() {
+        return FakeConfigSupport.getLong(FakeConfigKeys.FAKE_STATION_FINISH_DELAY_MS, 0L);
+    }
+
+    private static final String STATUS_WAITING = "WAITING";
+    private static final String STATUS_RUNNING = "RUNNING";
+    private static final String STATUS_BLOCKED = "BLOCKED";
+    private static final String STATUS_CANCELLED = "CANCELLED";
+    private static final String STATUS_TIMEOUT = "TIMEOUT";
+    private static final String STATUS_FINISHED = "FINISHED";
+
+    private static final String SEGMENT_MERGE_APPEND = "APPEND";
+    private static final String SEGMENT_MERGE_REPLACE_TARGET_CHANGED = "REPLACE_TARGET_CHANGED";
+    private static final String SEGMENT_MERGE_REPLACE_REROUTE = "REPLACE_REROUTE";
+    private static final String SEGMENT_MERGE_IGNORE_DISCONNECTED = "IGNORE_DISCONNECTED";
+    private static final String SEGMENT_MERGE_IGNORE_CURRENT_MISSING = "IGNORE_CURRENT_MISSING";
+
+    private final FakeStationStateManager stateManager = new FakeStationStateManager();
+    private final FakeStationMoveEngine moveEngine = new FakeStationMoveEngine(stateManager);
+    private final FakeStationBlockManager blockManager = new FakeStationBlockManager(stateManager);
+    private static final AtomicInteger DEVICE_EXECUTOR_THREAD_SEQ = new AtomicInteger(1);
+    private volatile ScheduledExecutorService loopScheduler = createLoopScheduler();
     private RedisUtil redisUtil;
-    private final Map<Integer, BlockingQueue<StationCommand>> taskQueues = new ConcurrentHashMap<>();
-    private final Map<Integer, Long> taskLastUpdateTime = new ConcurrentHashMap<>();
-    private final Map<Integer, Boolean> taskRunning = new ConcurrentHashMap<>();
-    private final ExecutorService executor = Executors.newCachedThreadPool();
+    private final Map<Integer, ExecutorService> deviceExecutors = new ConcurrentHashMap<Integer, ExecutorService>();
+
+    private final Map<Integer, BlockingQueue<StationCommand>> taskQueues = new ConcurrentHashMap<Integer, BlockingQueue<StationCommand>>();
+    private final Map<Integer, Long> taskLastUpdateTime = new ConcurrentHashMap<Integer, Long>();
+    private final Map<Integer, Boolean> taskRunning = new ConcurrentHashMap<Integer, Boolean>();
+    private final Map<Integer, TaskRuntimeContext> taskContexts = new ConcurrentHashMap<Integer, TaskRuntimeContext>();
+    private final Map<Integer, AtomicInteger> taskLoopGenerations = new ConcurrentHashMap<Integer, AtomicInteger>();
+    private final Map<Integer, Object> taskLifecycleLocks = new ConcurrentHashMap<Integer, Object>();
+    private volatile Set<Integer> legalClearStationIds = new HashSet<Integer>();
+    private volatile Set<Integer> barcodeStationIds = new HashSet<Integer>();
 
     public void addFakeConnect(DeviceConfig deviceConfig, RedisUtil redisUtil) {
         this.redisUtil = redisUtil;
-
-        if (deviceConfigMap.containsKey(deviceConfig.getDeviceNo())) {
-            return;
-        }
-        deviceConfigMap.put(deviceConfig.getDeviceNo(), deviceConfig);
-        deviceStatusMap.put(deviceConfig.getDeviceNo(), new CopyOnWriteArrayList<>());
+        refreshLegalClearStationIds();
+        refreshBarcodeStationIds();
+        stateManager.registerDevice(deviceConfig);
     }
 
     @Override
     public boolean connect() {
+        if (loopScheduler == null || loopScheduler.isShutdown() || loopScheduler.isTerminated()) {
+            loopScheduler = createLoopScheduler();
+        }
         return true;
     }
 
     @Override
     public boolean disconnect() {
-        executor.shutdownNow();
+        ScheduledExecutorService scheduler = loopScheduler;
+        if (scheduler != null) {
+            scheduler.shutdownNow();
+        }
+        for (ExecutorService executor : deviceExecutors.values()) {
+            executor.shutdownNow();
+        }
+        deviceExecutors.clear();
+        taskQueues.clear();
+        taskLastUpdateTime.clear();
+        taskRunning.clear();
+        taskContexts.clear();
+        taskLoopGenerations.clear();
+        taskLifecycleLocks.clear();
         return true;
     }
 
     @Override
     public List<ZyStationStatusEntity> getStatus(Integer deviceNo) {
-        List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-        if (statusList == null) {
-            return new ArrayList<>();
-        }
-        DeviceConfig deviceConfig = deviceConfigMap.get(deviceNo);
-        if (statusList.isEmpty()) {
-            List<ZyStationStatusEntity> init = JSON.parseArray(deviceConfig.getFakeInitStatus(),
-                    ZyStationStatusEntity.class);
-            if (init != null) {
-                statusList.addAll(init);
-                for (ZyStationStatusEntity status : statusList) {
-                    status.setAutoing(true);
-                    status.setLoading(false);
-                    status.setInEnable(true);
-                    status.setOutEnable(true);
-                    status.setEmptyMk(false);
-                    status.setFullPlt(false);
-                    status.setRunBlock(false);
-                    status.setPalletHeight(0);
-                    status.setError(0);
-                    status.setBarcode("");
-                }
-            }
-        }
-
-        return statusList;
+        return stateManager.getStatus(deviceNo);
     }
 
     @Override
@@ -96,228 +131,48 @@
             return new CommandResponse(false, "浠诲姟鍙蜂负绌�");
         }
 
-        // 澶勭悊闈炵Щ鍔ㄥ懡浠�
         if (command.getCommandType() != StationCommandType.MOVE) {
-            handleCommand(deviceNo, command);
-        } else {
-            // 灏嗙Щ鍔ㄥ懡浠よ拷鍔犲埌浠诲姟闃熷垪锛堟敮鎸佸垎娈典笅鍙戯級
-            taskQueues.computeIfAbsent(taskNo, k -> new LinkedBlockingQueue<>()).offer(command);
-            taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
+            News.info("[WCS Debug] fake sendCommand鏀跺埌闈濵OVE鍛戒护锛宒eviceNo={}锛宼askNo={}锛宻tationId={}锛宼argetStaNo={}锛宑ommandType={}",
+                    deviceNo, taskNo, command.getStationId(), command.getTargetStaNo(), command.getCommandType());
+            getDeviceExecutor(deviceNo).submit(new Runnable() {
+                @Override
+                public void run() {
+                    handleCommand(deviceNo, command);
+                }
+            });
+            return new CommandResponse(true, "鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
+        }
 
-            // 鍙湁浠诲姟鏈惎鍔ㄦ椂鎵嶅惎鍔ㄦ墽琛屽櫒锛屽悗缁垎娈靛懡浠や粎杩藉姞鍒伴槦鍒�
+        int loopGeneration = 0;
+        boolean shouldSchedule = false;
+        Object lifecycleLock = getTaskLifecycleLock(taskNo);
+        synchronized (lifecycleLock) {
+            BlockingQueue<StationCommand> queue = taskQueues.computeIfAbsent(taskNo, key -> new LinkedBlockingQueue<StationCommand>());
+            queue.offer(command);
+            taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
+            News.info("[WCS Debug] fake sendCommand鍏ラ槦锛宒eviceNo={}锛宼askNo={}锛宻tationId={}锛宼argetStaNo={}锛宻egmentNo={}锛宻egmentCount={}锛宷ueueSize={}锛宺unning={}",
+                    deviceNo, taskNo, command.getStationId(), command.getTargetStaNo(), command.getSegmentNo(), command.getSegmentCount(),
+                    queue.size(), taskRunning.containsKey(taskNo));
+
             if (taskRunning.putIfAbsent(taskNo, true) == null) {
-                executor.submit(() -> runTaskLoop(deviceNo, taskNo));
+                TaskRuntimeContext context = new TaskRuntimeContext(taskNo, deviceNo, stateManager.getThreadImpl(deviceNo));
+                taskContexts.put(taskNo, context);
+                AtomicInteger generation = taskLoopGenerations.computeIfAbsent(taskNo, key -> new AtomicInteger(0));
+                loopGeneration = generation.incrementAndGet();
+                context.loopGeneration = loopGeneration;
+                shouldSchedule = true;
+                News.info("[WCS Debug] fake task鍑嗗鍚姩鎵ц绾跨▼锛宒eviceNo={}锛宼askNo={}锛宷ueueSize={}锛宭oopGeneration={}",
+                        deviceNo, taskNo, queue.size(), loopGeneration);
+            } else {
+                News.info("[WCS Debug] fake task澶嶇敤宸插瓨鍦ㄦ墽琛岀嚎绋嬶紝deviceNo={}锛宼askNo={}锛宷ueueSize={}",
+                        deviceNo, taskNo, queue.size());
             }
-            // 鍚庣画鍒嗘鍛戒护涓嶅啀杩斿洖閿欒锛屾甯歌拷鍔犲埌闃熷垪
+        }
+        if (shouldSchedule) {
+            scheduleTaskLoop(deviceNo, taskNo, loopGeneration);
         }
 
         return new CommandResponse(true, "鍛戒护宸插彈鐞嗭紙寮傛鎵ц锛�");
-    }
-
-    private void runTaskLoop(Integer deviceNo, Integer taskNo) {
-        try {
-            // 寰呮墽琛岀殑璺緞闃熷垪锛堝瓨鍌ㄧ珯鐐笽D搴忓垪锛�
-            LinkedBlockingQueue<Integer> pendingPathQueue = new LinkedBlockingQueue<>();
-            // 褰撳墠鎵�鍦ㄧ珯鐐笽D
-            Integer currentStationId = null;
-            // 鏈�缁堢洰鏍囩珯鐐笽D
-            Integer finalTargetStationId = null;
-            // 鏄惁闇�瑕佺敓鎴愭潯鐮�
-            boolean generateBarcode = false;
-            // 鏄惁宸插垵濮嬪寲璧风偣
-            boolean initialized = false;
-            // 涓婁竴姝ユ墽琛屾椂闂达紙鐢ㄤ簬鍫靛妫�娴嬶級
-            long stepExecuteTime = System.currentTimeMillis();
-
-            while (true) {
-                if (Thread.currentThread().isInterrupted()) {
-                    break;
-                }
-
-                BlockingQueue<StationCommand> commandQueue = taskQueues.get(taskNo);
-                if (commandQueue == null) {
-                    break;
-                }
-
-                // 灏濊瘯鑾峰彇鏂扮殑鍒嗘鍛戒护
-                StationCommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS);
-                if (command != null) {
-                    taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
-
-                    // 棣栨鎺ユ敹鍛戒护鏃跺垵濮嬪寲
-                    if (finalTargetStationId == null) {
-                        finalTargetStationId = command.getTargetStaNo();
-                        if (checkTaskNoInArea(taskNo)) {
-                            generateBarcode = true;
-                        }
-                    }
-
-                    // 灏嗘柊璺緞杩藉姞鍒板緟鎵ц闃熷垪
-                    List<Integer> newPath = command.getNavigatePath();
-                    if (newPath != null && !newPath.isEmpty()) {
-                        // 鑾峰彇闃熷垪涓渶鍚庝竴涓珯鐐癸紙鐢ㄤ簬琛旀帴鐐瑰幓閲嶏級
-                        Integer lastInQueue = getLastInQueue(pendingPathQueue);
-                        if (lastInQueue == null) {
-                            lastInQueue = currentStationId;
-                        }
-
-                        int startIndex = 0;
-                        // 濡傛灉鏂拌矾寰勭殑璧风偣涓庡綋鍓嶄綅缃垨闃熷垪鏈熬閲嶅锛屽垯璺宠繃
-                        if (lastInQueue != null && !newPath.isEmpty() && newPath.get(0).equals(lastInQueue)) {
-                            startIndex = 1;
-                        }
-
-                        for (int i = startIndex; i < newPath.size(); i++) {
-                            pendingPathQueue.offer(newPath.get(i));
-                        }
-
-                        News.info("[WCS Debug] 浠诲姟{}杩藉姞璺緞娈�: {} -> 闃熷垪澶у皬: {}", taskNo, newPath, pendingPathQueue.size());
-                    }
-                }
-
-                // 鎵ц绉诲姩閫昏緫
-                if (!pendingPathQueue.isEmpty()) {
-                    Integer nextStationId = pendingPathQueue.peek();
-
-                    // 濡傛灉灏氭湭鍒濆鍖栬捣鐐�
-                    if (!initialized && currentStationId == null) {
-                        // 浼樺厛鏌ユ壘鎵樼洏褰撳墠瀹為檯浣嶇疆锛堟敮鎸佸牭濉炲悗閲嶈矾鐢卞満鏅級
-                        Integer actualCurrentStationId = findCurrentStationIdByTask(taskNo);
-                        if (actualCurrentStationId != null) {
-                            // 鎵惧埌浜嗗綋鍓嶆墭鐩樹綅缃紝浣跨敤瀹為檯浣嶇疆浣滀负璧风偣
-                            currentStationId = actualCurrentStationId;
-                            initialized = true;
-
-                            // 娓呴櫎璇ョ珯鐐圭殑 runBlock 鏍囪锛堝牭濉炴仮澶嶏級
-                            Integer deviceId = getDeviceNoByStationId(currentStationId);
-                            if (deviceId != null) {
-                                clearRunBlock(currentStationId, deviceId);
-                            }
-
-                            // 濡傛灉璺緞璧风偣涓庡綋鍓嶄綅缃浉鍚岋紝绉婚櫎璧风偣閬垮厤閲嶅
-                            if (nextStationId.equals(currentStationId)) {
-                                pendingPathQueue.poll();
-                            }
-
-                            stepExecuteTime = System.currentTimeMillis();
-                            News.info("[WCS Debug] 浠诲姟{}鎭㈠鎵ц锛屽綋鍓嶄綅缃�: {}", taskNo, currentStationId);
-                            continue;
-                        }
-
-                        // 鏈壘鍒板綋鍓嶄綅缃紙棣栨鎵ц锛夛紝棣栦釜绔欑偣灏辨槸璧风偣
-                        currentStationId = nextStationId;
-                        Integer deviceId = getDeviceNoByStationId(currentStationId);
-                        if (deviceId != null) {
-                            boolean result = initStationMove(taskNo, currentStationId, deviceId, taskNo,
-                                    finalTargetStationId, true, null);
-                            if (result) {
-                                initialized = true;
-                                pendingPathQueue.poll(); // 绉婚櫎璧风偣
-                                stepExecuteTime = System.currentTimeMillis();
-                                News.info("[WCS Debug] 浠诲姟{}鍒濆鍖栬捣鐐�: {}", taskNo, currentStationId);
-                            }
-                        }
-                        sleep(500);
-                        continue;
-                    }
-
-                    // 鎵ц浠庡綋鍓嶇珯鐐瑰埌涓嬩竴绔欑偣鐨勭Щ鍔�
-                    Integer currentDeviceNo = getDeviceNoByStationId(currentStationId);
-                    Integer nextDeviceNo = getDeviceNoByStationId(nextStationId);
-
-                    if (currentDeviceNo != null && nextDeviceNo != null) {
-                        boolean moveSuccess = stationMoveToNext(taskNo, currentStationId, currentDeviceNo,
-                                nextStationId, nextDeviceNo, taskNo, finalTargetStationId);
-                        if (moveSuccess) {
-                            currentStationId = nextStationId;
-                            pendingPathQueue.poll();
-                            stepExecuteTime = System.currentTimeMillis();
-                            News.info("[WCS Debug] 浠诲姟{}绉诲姩鍒扮珯鐐�: {}, 鍓╀綑闃熷垪: {}", taskNo, currentStationId,
-                                    pendingPathQueue.size());
-                            sleep(1000); // 妯℃嫙绉诲姩鑰楁椂
-                        } else {
-                            // 绉诲姩澶辫触锛屾鏌ユ槸鍚﹀牭濉�
-                            if (!checkTaskNoInArea(taskNo)) {
-                                boolean fakeAllowCheckBlock = getFakeAllowCheckBlock();
-
-                                if (fakeAllowCheckBlock && System.currentTimeMillis() - stepExecuteTime > 10000) {
-                                    // 璁ゅ畾鍫靛
-                                    boolean result = runBlockStation(taskNo, currentStationId, currentDeviceNo, taskNo,
-                                            currentStationId);
-                                    if (result) {
-                                        News.info("[WCS Debug] 浠诲姟{}鍦ㄧ珯鐐箋}琚爣璁颁负鍫靛", taskNo, currentStationId);
-                                        pendingPathQueue.clear();
-                                        break;
-                                    }
-                                }
-                            }
-                            sleep(500); // 澶辫触閲嶈瘯绛夊緟
-                        }
-                    } else {
-                        // 鏃犳硶鑾峰彇璁惧鍙凤紝璺宠繃璇ョ珯鐐�
-                        pendingPathQueue.poll();
-                    }
-                } else {
-                    // 璺緞闃熷垪涓虹┖锛岀瓑寰呮柊鐨勫垎娈靛懡浠�
-                    if (currentStationId != null && finalTargetStationId != null
-                            && currentStationId.equals(finalTargetStationId)) {
-                        // 宸插埌杈炬渶缁堢洰鏍囷紝姝e父缁撴潫
-                        if (generateBarcode) {
-                            Integer targetDeviceNo = getDeviceNoByStationId(finalTargetStationId);
-                            if (targetDeviceNo != null) {
-                                generateStationBarcode(taskNo, finalTargetStationId, targetDeviceNo);
-                                News.info("[WCS Debug] 浠诲姟{}鍒拌揪鐩爣{}骞剁敓鎴愭潯鐮�", taskNo, finalTargetStationId);
-                            }
-                        }
-                        break;
-                    }
-
-                    // 鏈埌杈炬渶缁堢洰鏍囷紝绛夊緟鏂扮殑鍒嗘鍛戒护
-                    Long lastTime = taskLastUpdateTime.get(taskNo);
-                    if (lastTime != null && System.currentTimeMillis() - lastTime > 30000) {
-                        // 瓒呮椂锛�30绉掑唴娌℃湁鏀跺埌鏂板垎娈靛懡浠�
-                        News.info("[WCS Debug] 浠诲姟{}绛夊緟鍒嗘瓒呮椂锛屽綋鍓嶄綅缃�: {}, 鐩爣: {}", taskNo, currentStationId,
-                                finalTargetStationId);
-                        break;
-                    }
-                    // 缁х画绛夊緟鏂板垎娈靛懡浠わ紙涓嶅仛浠讳綍浜嬫儏锛屼笅涓�杞惊鐜細灏濊瘯鑾峰彇鏂板懡浠わ級
-                }
-            }
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        } finally {
-            taskQueues.remove(taskNo);
-            taskLastUpdateTime.remove(taskNo);
-            taskRunning.remove(taskNo);
-            News.info("[WCS Debug] 浠诲姟{}鎵ц缁撴潫骞舵竻鐞嗚祫婧�", taskNo);
-        }
-    }
-
-    /**
-     * 鑾峰彇闃熷垪涓渶鍚庝竴涓厓绱狅紙涓嶇Щ闄わ級
-     */
-    private Integer getLastInQueue(LinkedBlockingQueue<Integer> queue) {
-        Integer last = null;
-        for (Integer item : queue) {
-            last = item;
-        }
-        return last;
-    }
-
-    /**
-     * 鑾峰彇鏄惁鍏佽妫�鏌ュ牭濉炵殑閰嶇疆
-     */
-    private boolean getFakeAllowCheckBlock() {
-        boolean fakeAllowCheckBlock = true;
-        Object systemConfigMapObj = redisUtil.get(RedisKeyType.SYSTEM_CONFIG_MAP.key);
-        if (systemConfigMapObj != null) {
-            HashMap<String, String> systemConfigMap = (HashMap<String, String>) systemConfigMapObj;
-            String value = systemConfigMap.get("fakeAllowCheckBlock");
-            if (value != null && !value.equals("Y")) {
-                fakeAllowCheckBlock = false;
-            }
-        }
-        return fakeAllowCheckBlock;
     }
 
     @Override
@@ -326,383 +181,1438 @@
     }
 
     @Override
+    public CommandResponse clearTaskBufferSlot(Integer deviceNo, Integer stationId, Integer slotIdx) {
+        return stateManager.clearTaskBufferSlot(deviceNo, stationId, slotIdx);
+    }
+
+    @Override
     public byte[] readOriginCommand(String address, int length) {
         return new byte[0];
     }
 
-    private void handleCommand(Integer deviceNo, StationCommand command) {
-        News.info("[WCS Debug] 绔欑偣浠跨湡妯℃嫙(V3)宸插惎鍔紝鍛戒护鏁版嵁={}", JSON.toJSONString(command));
-        Integer taskNo = command.getTaskNo();
-        Integer stationId = command.getStationId();
-        Integer targetStationId = command.getTargetStaNo();
-        boolean generateBarcode = false;
 
-        if (command.getCommandType() == StationCommandType.RESET) {
-            resetStation(deviceNo, stationId);
+    private ScheduledExecutorService createLoopScheduler() {
+        return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable runnable) {
+                Thread thread = new Thread(runnable, "fake-station-loop-scheduler");
+                thread.setDaemon(true);
+                return thread;
+            }
+        });
+    }
+
+    private ExecutorService getDeviceExecutor(Integer deviceNo) {
+        return deviceExecutors.computeIfAbsent(deviceNo, key -> Executors.newSingleThreadExecutor(new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable runnable) {
+                Thread thread = new Thread(runnable,
+                        "fake-station-device-" + key + "-" + DEVICE_EXECUTOR_THREAD_SEQ.getAndIncrement());
+                thread.setDaemon(true);
+                return thread;
+            }
+        }));
+    }
+
+    private void scheduleTaskLoop(Integer deviceNo, Integer taskNo, int loopGeneration) {
+        scheduleTaskLoop(deviceNo, taskNo, loopGeneration, 0L);
+    }
+
+    private void scheduleTaskLoop(Integer deviceNo, Integer taskNo, int loopGeneration, long delayMs) {
+        Runnable task = new Runnable() {
+            @Override
+            public void run() {
+                getDeviceExecutor(deviceNo).submit(new Runnable() {
+                    @Override
+                    public void run() {
+                        runTaskLoop(deviceNo, taskNo, loopGeneration);
+                    }
+                });
+            }
+        };
+        if (delayMs <= 0L) {
+            task.run();
             return;
         }
+        loopScheduler.schedule(task, delayMs, TimeUnit.MILLISECONDS);
+    }
 
-        if (checkTaskNoInArea(taskNo)) {
-            generateBarcode = true;
+    private void scheduleTaskLoopByDelay(Integer deviceNo, Integer taskNo, int loopGeneration, long delayMs) {
+        scheduleTaskLoop(deviceNo, taskNo, loopGeneration, Math.max(delayMs, 1L));
+    }
+
+    private void runTaskLoop(Integer deviceNo, Integer taskNo, int loopGeneration) {
+        TaskRuntimeContext context = taskContexts.get(taskNo);
+        if (context == null) {
+            News.info("[WCS Debug] fake task蹇界暐鏃犱笂涓嬫枃缁窇鐗囨锛宒eviceNo={}锛宼askNo={}锛宭oopGeneration={}",
+                    deviceNo, taskNo, loopGeneration);
+            return;
+        }
+        if (!deviceNo.equals(context.deviceNo)) {
+            News.info("[WCS Debug] fake task蹇界暐璺ㄨ澶囩画璺戠墖娈碉紝taskNo={}锛宔xpectedDeviceNo={}锛宎ctualDeviceNo={}锛宭oopGeneration={}",
+                    taskNo, context.deviceNo, deviceNo, loopGeneration);
+            return;
+        }
+        if (context.loopGeneration != loopGeneration || !isCurrentLoopGeneration(taskNo, loopGeneration)) {
+            News.info("[WCS Debug] fake task蹇界暐杩囨湡缁窇鐗囨锛宒eviceNo={}锛宼askNo={}锛宔xpectedLoopGeneration={}锛宎ctualLoopGeneration={}",
+                    deviceNo, taskNo, loopGeneration, context.loopGeneration);
+            return;
+        }
+        News.info("[WCS Debug] fake task杩涘叆runTaskLoop锛宒eviceNo={}锛宼askNo={}锛宼hreadImpl={}锛宷ueueExists={}锛宷ueueSize={}锛宭oopGeneration={}锛宻tatus={}锛宨nitialized={}锛宑urrentStationId={}锛宼argetStationId={}锛宐lockedStationId={}锛宲endingPath={}",
+                deviceNo, taskNo, context.threadImpl, taskQueues.containsKey(taskNo),
+                taskQueues.containsKey(taskNo) && taskQueues.get(taskNo) != null ? taskQueues.get(taskNo).size() : null, loopGeneration,
+                context.status, context.initialized, context.currentStationId, context.finalTargetStationId,
+                context.blockedStationId, context.getPendingStationIds());
+        long nextDelayMs = 0L;
+        boolean shouldContinue = false;
+        try {
+            if (Thread.currentThread().isInterrupted()) {
+                if (!isTerminalStatus(context.status)) {
+                    context.status = STATUS_CANCELLED;
+                }
+            } else if (hasTaskReset(taskNo)) {
+                context.status = STATUS_CANCELLED;
+            } else {
+                BlockingQueue<StationCommand> commandQueue = taskQueues.get(taskNo);
+                if (commandQueue == null) {
+                    context.status = STATUS_FINISHED;
+                } else {
+                    StationCommand command = commandQueue.poll();
+                    if (command != null) {
+                        taskLastUpdateTime.put(taskNo, System.currentTimeMillis());
+                        context.lastCommandAt = System.currentTimeMillis();
+                        handleIncomingSegment(deviceNo, context, command);
+                    }
+
+                    if (!isTerminalStatus(context.status)) {
+                        if (!context.pendingPathQueue.isEmpty()) {
+                            News.info("[WCS Debug] fake task鍑嗗鎺ㄨ繘锛宒eviceNo={}锛宼askNo={}锛宨nitialized={}锛宑urrentStationId={}锛宼argetStationId={}锛宐lockedStationId={}锛宲endingPath={}",
+                                    deviceNo, taskNo, context.initialized, context.currentStationId,
+                                    context.finalTargetStationId, context.blockedStationId, context.getPendingStationIds());
+                            if (!context.initialized || context.currentStationId == null) {
+                                nextDelayMs = initializeTaskPosition(deviceNo, context);
+                            } else {
+                                MoveStepResult moveResult = executeNextMove(deviceNo, context);
+                                if (!moveResult.shouldContinue()) {
+                                    context.status = STATUS_FINISHED;
+                                }
+                                nextDelayMs = moveResult.getNextDelayMs();
+                            }
+                        } else {
+                            News.info("[WCS Debug] fake task杩涘叆绌洪棽鎬侊紝deviceNo={}锛宼askNo={}锛宻tatus={}锛宑urrentStationId={}锛宼argetStationId={}锛宐lockedStationId={}锛宲endingPath={}",
+                                    deviceNo, taskNo, context.status, context.currentStationId,
+                                    context.finalTargetStationId, context.blockedStationId, context.getPendingStationIds());
+                            IdleStepResult idleResult = handleIdleState(deviceNo, context);
+                            if (idleResult.isFinished() && !isTerminalStatus(context.status)) {
+                                context.status = STATUS_FINISHED;
+                            }
+                            nextDelayMs = idleResult.getNextDelayMs();
+                        }
+                    }
+                    shouldContinue = !isTerminalStatus(context.status)
+                            && taskQueues.containsKey(taskNo)
+                            && (commandQueue != null);
+                }
+            }
+        } catch (Exception e) {
+            context.status = STATUS_CANCELLED;
+            if (e instanceof InterruptedException) {
+                Thread.currentThread().interrupt();
+            }
+            News.info("[WCS Debug] 浠诲姟{}鎵ц寮傚父锛屽綋鍓嶇珯鐐�={}锛岀洰鏍囩珯={}锛屽緟鎵ц璺緞={}锛屽紓甯哥被鍨�={}锛屽紓甯镐俊鎭�={}",
+                    taskNo, context.currentStationId, context.finalTargetStationId, context.getPendingStationIds(),
+                    e.getClass().getSimpleName(), e.getMessage());
         }
 
-        if (command.getCommandType() == StationCommandType.WRITE_INFO) {
-            if (taskNo == 9998 && targetStationId == 0) {
-                // 鐢熸垚鍑哄簱绔欑偣浠跨湡鏁版嵁
-                generateFakeOutStationData(deviceNo, stationId);
+        if (shouldContinue) {
+            if (nextDelayMs > 0L) {
+                scheduleTaskLoopByDelay(deviceNo, taskNo, loopGeneration, nextDelayMs);
+            } else {
+                scheduleTaskLoop(deviceNo, taskNo, loopGeneration);
+            }
+            return;
+        }
+        finishTaskLoop(deviceNo, taskNo, context, loopGeneration);
+    }
+
+    private void finishTaskLoop(Integer deviceNo, Integer taskNo, TaskRuntimeContext context, int loopGeneration) {
+        Object lifecycleLock = getTaskLifecycleLock(taskNo);
+        synchronized (lifecycleLock) {
+            if (context.loopGeneration != loopGeneration || !isCurrentLoopGeneration(taskNo, loopGeneration)) {
+                News.info("[WCS Debug] fake task蹇界暐杩囨湡缁撴潫娓呯悊锛宒eviceNo={}锛宼askNo={}锛宔xpectedLoopGeneration={}锛宎ctualLoopGeneration={}",
+                        deviceNo, taskNo, loopGeneration, context.loopGeneration);
+                return;
+            }
+            BlockingQueue<StationCommand> queue = taskQueues.get(taskNo);
+            if (queue != null && !queue.isEmpty()) {
+                News.info("[WCS Debug] fake task缁撴潫娓呯悊鍓嶅彂鐜版柊鍛戒护锛屾仮澶嶇画璺戯紝deviceNo={}锛宼askNo={}锛宷ueueSize={}锛宭oopGeneration={}",
+                        deviceNo, taskNo, queue.size(), loopGeneration);
+                scheduleTaskLoop(deviceNo, taskNo, loopGeneration);
+                return;
+            }
+            News.info("[WCS Debug] fake task鍗冲皢閫�鍑簉unTaskLoop锛宒eviceNo={}锛宼askNo={}锛宻tatus={}锛宷ueueSizeBeforeCleanup={}锛宭astCurrentStationId={}锛宼argetStationId={}锛宭oopGeneration={}",
+                    deviceNo, taskNo, context.status, queue == null ? null : queue.size(), context.currentStationId, context.finalTargetStationId, loopGeneration);
+            taskQueues.remove(taskNo);
+            taskLastUpdateTime.remove(taskNo);
+            taskRunning.remove(taskNo);
+            taskContexts.remove(taskNo);
+            taskLoopGenerations.remove(taskNo);
+            taskLifecycleLocks.remove(taskNo, lifecycleLock);
+        }
+
+        if (!isTerminalStatus(context.status)) {
+            context.status = STATUS_FINISHED;
+        }
+        traceEvent(deviceNo, context, "TASK_END", "浠诲姟鎵ц缁撴潫骞舵竻鐞嗚祫婧�",
+                buildDetails("reason", context.status, "loopGeneration", loopGeneration), true);
+        News.info("[WCS Debug] 浠诲姟{}鎵ц缁撴潫骞舵竻鐞嗚祫婧愶紝鐘舵��={}锛宭oopGeneration={}", taskNo, context.status, loopGeneration);
+    }
+
+    private void handleIncomingSegment(Integer deviceNo, TaskRuntimeContext context, StationCommand command) {
+        if (!deviceNo.equals(context.deviceNo)) {
+            traceEvent(deviceNo, context, "SEGMENT_IGNORED", "璺緞鍒嗘鏉ヨ嚜涓嶅悓璁惧杞﹂亾锛屽凡蹇界暐",
+                    buildDetails("expectedDeviceNo", context.deviceNo, "actualDeviceNo", deviceNo,
+                            "segmentNo", command.getSegmentNo(), "segmentCount", command.getSegmentCount()), false);
+            return;
+        }
+        List<Integer> newPath = normalizePath(command.getNavigatePath());
+        Integer lastInQueue = getLastInQueue(context.pendingPathQueue);
+        int startIndex = getPathAppendStartIndex(newPath, context.currentStationId, lastInQueue);
+        Integer previousTargetStationId = context.finalTargetStationId;
+        Integer commandTargetStationId = command.getTargetStaNo();
+        boolean targetChanged = commandTargetStationId != null
+                && !commandTargetStationId.equals(previousTargetStationId);
+        boolean queueEmpty = context.pendingPathQueue.isEmpty();
+        boolean newPathContainsCurrent = context.currentStationId != null && newPath.contains(context.currentStationId);
+        boolean pathConnectedToTail = startIndex >= 0;
+        List<Integer> oldPendingStations = context.getPendingStationIds();
+        boolean shouldClearBarcodeSourceOnReroute = context.currentStationId != null
+                && context.currentStationId.equals(command.getStationId())
+                && isBarcodeStation(context.currentStationId)
+                && previousTargetStationId != null
+                && previousTargetStationId.equals(context.currentStationId)
+                && commandTargetStationId != null
+                && !commandTargetStationId.equals(context.currentStationId);
+
+        context.setStartStationIdIfAbsent(command.getStationId());
+        if (!context.generateBarcode && checkTaskNoInArea(context.taskNo)) {
+            context.generateBarcode = true;
+        }
+
+        traceEvent(deviceNo, context, "SEGMENT_RECEIVED", "鏀跺埌鏂扮殑璺緞鍒嗘鍛戒护",
+                buildDetails("segmentPath", newPath, "appendStartIndex", startIndex, "currentStationId",
+                        context.currentStationId, "queueTailStationId", lastInQueue, "commandStationId",
+                        command.getStationId(), "commandTargetStationId", commandTargetStationId,
+                        "previousTargetStationId", previousTargetStationId),
+                false);
+
+        if (commandTargetStationId != null) {
+            if (targetChanged) {
+                traceEvent(deviceNo, context, "TARGET_SWITCHED",
+                        "浠诲姟鐩爣绔欏彂鐢熷垏鎹�: " + previousTargetStationId + " -> " + commandTargetStationId,
+                        buildDetails("fromTargetStationId", previousTargetStationId, "toTargetStationId",
+                                commandTargetStationId),
+                        false);
+                context.arrivalHandled = false;
+            }
+            context.finalTargetStationId = commandTargetStationId;
+            syncCurrentStationTarget(context.taskNo, context.currentStationId, context.finalTargetStationId);
+        }
+        context.segmentNo = command.getSegmentNo();
+        context.segmentCount = command.getSegmentCount();
+
+        boolean tailConnectedAppend = !queueEmpty && pathConnectedToTail;
+        boolean shouldReplace = !tailConnectedAppend && !queueEmpty
+                && (targetChanged || (!pathConnectedToTail && newPathContainsCurrent));
+        String ignoreReason = null;
+        if (!shouldReplace && !tailConnectedAppend && !newPath.isEmpty() && !pathConnectedToTail) {
+            ignoreReason = newPathContainsCurrent ? SEGMENT_MERGE_IGNORE_DISCONNECTED : SEGMENT_MERGE_IGNORE_CURRENT_MISSING;
+            if (queueEmpty && context.currentStationId == null) {
+                startIndex = 0;
+            } else {
+                traceEvent(deviceNo, context, "SEGMENT_IGNORED", "璺緞鍒嗘鏃犳硶鎺ュ叆褰撳墠杩愯涓婁笅鏂囷紝宸插拷鐣�",
+                        buildDetails("segmentPath", newPath, "currentStationId", context.currentStationId,
+                                "queueTailStationId", lastInQueue, "ignoreReason", ignoreReason,
+                                "queueEmpty", queueEmpty, "tailConnectedAppend", tailConnectedAppend,
+                                "targetChanged", targetChanged),
+                        false);
+                context.latestAppendedPath.clear();
                 return;
             }
         }
 
-        if (taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId == targetStationId) {
-            generateStationData(deviceNo, taskNo, stationId, targetStationId);
-        }
-        // 娉ㄦ剰锛歁OVE 绫诲瀷鐨勫懡浠ょ幇宸插湪 sendCommand 涓鐞嗭紝handleCommand 浠呭鐞嗛潪 MOVE 鍛戒护
-    }
-
-    private void generateFakeOutStationData(Integer deviceNo, Integer stationId) {
-        List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-        ZyStationStatusEntity status = statusList.stream()
-                .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-        if (status == null) {
-            return;
+        if (tailConnectedAppend && startIndex < 0) {
+            startIndex = 0;
         }
 
-        synchronized (status) {
-            status.setLoading(true);
-        }
-    }
-
-    private void generateStationData(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) {
-        List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-        ZyStationStatusEntity status = statusList.stream()
-                .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-        if (status == null) {
-            return;
-        }
-
-        synchronized (status) {
-            status.setTaskNo(taskNo);
-            status.setTargetStaNo(targetStationId);
-        }
-    }
-
-    private void resetStation(Integer deviceNo, Integer stationId) {
-        List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-        ZyStationStatusEntity status = statusList.stream()
-                .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-        if (status == null) {
-            return;
-        }
-
-        synchronized (status) {
-            status.setTaskNo(0);
-            status.setLoading(false);
-            status.setBarcode("");
-        }
-    }
-
-    // segmentedPathCommand 鏂规硶宸插垹闄わ紝鍔熻兘宸叉暣鍚堝埌 runTaskLoop
-
-    private Integer getDeviceNoByStationId(Integer stationId) {
-        for (Integer devNo : deviceStatusMap.keySet()) {
-            List<ZyStationStatusEntity> list = deviceStatusMap.get(devNo);
-            if (list == null) {
-                continue;
+        List<Integer> appendedPath = new ArrayList<Integer>();
+        List<Integer> replacedFuturePath = new ArrayList<Integer>();
+        Integer duplicateHeadStationId = null;
+        String mergeMode = SEGMENT_MERGE_APPEND;
+        if (shouldReplace) {
+            replacedFuturePath = rebuildPendingPathFromCurrent(context, newPath);
+            boolean atTargetAlready = context.currentStationId != null && context.currentStationId.equals(commandTargetStationId);
+            if (context.currentStationId != null && replacedFuturePath.isEmpty() && !atTargetAlready) {
+                traceEvent(deviceNo, context, "SEGMENT_IGNORED", "璺緞鍒嗘鏃犳硶鎺ュ叆褰撳墠杩愯涓婁笅鏂囷紝宸插拷鐣�",
+                        buildDetails("segmentPath", newPath, "currentStationId", context.currentStationId,
+                                "queueTailStationId", lastInQueue, "ignoreReason", SEGMENT_MERGE_IGNORE_CURRENT_MISSING),
+                        false);
+                context.latestAppendedPath.clear();
+                return;
             }
-            for (ZyStationStatusEntity e : list) {
-                if (e.getStationId() != null && e.getStationId().equals(stationId)) {
-                    return devNo;
+            replacePendingPathQueue(context, replacedFuturePath);
+            context.replaceLatestPath(replacedFuturePath);
+            mergeMode = targetChanged ? SEGMENT_MERGE_REPLACE_TARGET_CHANGED : SEGMENT_MERGE_REPLACE_REROUTE;
+            traceEvent(deviceNo, context, "SEGMENT_REPLACED",
+                    "鏂扮殑 reroute 璺緞宸茶鐩栨棫 future queue",
+                    buildDetails("mergeMode", mergeMode, "currentStationId", context.currentStationId,
+                            "previousTargetStationId", previousTargetStationId, "newTargetStationId", commandTargetStationId,
+                            "oldQueue", oldPendingStations, "replacedFuturePath", replacedFuturePath,
+                            "queueSize", context.pendingPathQueue.size()),
+                    false);
+        } else {
+            for (int i = startIndex; i < newPath.size(); i++) {
+                Integer stationId = newPath.get(i);
+                context.pendingPathQueue.offer(stationId);
+                appendedPath.add(stationId);
+            }
+            if (context.currentStationId != null && context.currentStationId.equals(context.pendingPathQueue.peek())) {
+                duplicateHeadStationId = context.pendingPathQueue.poll();
+                if (!appendedPath.isEmpty() && duplicateHeadStationId.equals(appendedPath.get(0))) {
+                    appendedPath.remove(0);
                 }
             }
+            context.appendStitchedPath(appendedPath);
+            traceEvent(deviceNo, context, "SEGMENT_APPENDED",
+                    "璺緞鍒嗘宸茶拷鍔犲埌寰呮墽琛岄槦鍒楋紝闃熷垪闀垮害=" + context.pendingPathQueue.size(),
+                    buildDetails("mergeMode", mergeMode, "segmentPath", newPath, "appendedPath", appendedPath,
+                            "appendStartIndex", startIndex, "queueSize", context.pendingPathQueue.size(),
+                            "tailConnectedAppend", tailConnectedAppend, "targetChanged", targetChanged,
+                            "duplicateHeadStationId", duplicateHeadStationId),
+                    false);
         }
-        return null;
-    }
 
-    private Integer findCurrentStationIdByTask(Integer taskNo) {
-        for (Integer devNo : deviceStatusMap.keySet()) {
-            List<ZyStationStatusEntity> list = deviceStatusMap.get(devNo);
-            if (list == null) {
-                continue;
-            }
-            for (ZyStationStatusEntity e : list) {
-                if (e.getTaskNo() != null && e.getTaskNo().equals(taskNo) && e.isLoading()) {
-                    return e.getStationId();
+        if (duplicateHeadStationId != null) {
+            traceEvent(deviceNo, context, "SEGMENT_TRIMMED", "寰呮墽琛岄槦鍒楀ご閮ㄩ噸澶嶅綋鍓嶇珯鐐癸紝宸茬Щ闄�",
+                    buildDetails("currentStationId", context.currentStationId,
+                            "duplicateHeadStationId", duplicateHeadStationId,
+                            "queueSize", context.pendingPathQueue.size(),
+                            "remainingPendingPath", context.getPendingStationIds()),
+                    false);
+        }
+
+        if (context.currentStationId != null && context.currentStationId.equals(context.pendingPathQueue.peek())) {
+            Integer trimmedHead = context.pendingPathQueue.poll();
+            traceEvent(deviceNo, context, "SEGMENT_TRIMMED", "寰呮墽琛岄槦鍒楀ご閮ㄤ粛涓庡綋鍓嶇珯鐐归噸澶嶏紝宸插啀娆$Щ闄�",
+                    buildDetails("currentStationId", context.currentStationId,
+                            "duplicateHeadStationId", trimmedHead,
+                            "queueSize", context.pendingPathQueue.size(),
+                            "remainingPendingPath", context.getPendingStationIds()),
+                    false);
+        }
+
+        context.lastCommandAt = System.currentTimeMillis();
+
+        boolean segmentAccepted = !appendedPath.isEmpty() || !replacedFuturePath.isEmpty()
+                || (context.currentStationId != null && context.currentStationId.equals(commandTargetStationId))
+                || (context.currentStationId != null && context.currentStationId.equals(command.getStationId())
+                && commandTargetStationId != null && commandTargetStationId.equals(context.finalTargetStationId));
+        if (segmentAccepted) {
+            if (shouldClearBarcodeSourceOnReroute && context.currentStationId != null) {
+                Integer currentDeviceNo = stateManager.getDeviceNoByStationId(context.currentStationId);
+                if (currentDeviceNo != null) {
+                    guardedClearStationForDispatch(currentDeviceNo, context.currentStationId, context.taskNo, "barcodeSourceRerouteAccepted");
+                    traceEvent(deviceNo, context, "SOURCE_STATION_CLEARED", "鏉$爜婧愮珯宸插畬鎴愪换鍔′氦鎺ワ紝婧愮珯鐘舵�佸凡娓呴櫎",
+                            buildDetails("stationId", context.currentStationId,
+                                    "previousTargetStationId", previousTargetStationId,
+                                    "newTargetStationId", commandTargetStationId,
+                                    "mergeMode", mergeMode),
+                            false);
                 }
             }
+            resumeFromCurrentStation(deviceNo, context, mergeMode, appendedPath, replacedFuturePath,
+                    shouldClearBarcodeSourceOnReroute);
         }
-        return null;
     }
 
-    // stationMoveByPathIds 鏂规硶宸插垹闄わ紝鍔熻兘宸叉暣鍚堝埌 runTaskLoop
+    private long initializeTaskPosition(Integer deviceNo, TaskRuntimeContext context) {
+        Integer nextStationId = context.pendingPathQueue.peek();
+        if (nextStationId == null) {
+            return 0L;
+        }
 
-    private void sleep(long ms) {
+        if (context.currentStationId == null) {
+            Integer actualCurrentStationId = stateManager.findCurrentStationIdByTask(context.taskNo);
+            if (actualCurrentStationId != null) {
+                context.currentStationId = actualCurrentStationId;
+                context.initialized = true;
+                context.status = STATUS_RUNNING;
+                context.blockedStationId = null;
+
+                Integer actualDeviceNo = stateManager.getDeviceNoByStationId(actualCurrentStationId);
+                if (actualDeviceNo != null) {
+                    guardedClearRunBlock(context.taskNo, actualCurrentStationId, actualDeviceNo);
+                }
+
+                trimPendingPathToCurrent(context.pendingPathQueue, actualCurrentStationId);
+                if (actualCurrentStationId.equals(context.pendingPathQueue.peek())) {
+                    context.pendingPathQueue.poll();
+                }
+
+                context.addPassedStation(actualCurrentStationId);
+                context.lastStepAt = System.currentTimeMillis();
+                context.lastProgressAt = context.lastStepAt;
+                context.lastProgressStationId = context.currentStationId;
+                guardedPublishTaskLocation(context.taskNo, actualDeviceNo, actualCurrentStationId, true, false);
+                traceEvent(deviceNo, context, "MOVE_INIT", "浠诲姟浠庡綋鍓嶅疄闄呯珯鐐规仮澶嶆墽琛�",
+                        buildDetails("stationId", actualCurrentStationId, "recovered", true), false);
+                return 0L;
+            }
+        }
+
+        context.currentStationId = nextStationId;
+        Integer currentDeviceNo = stateManager.getDeviceNoByStationId(context.currentStationId);
+        if (currentDeviceNo == null) {
+            context.pendingPathQueue.poll();
+            return 0L;
+        }
+
+        boolean result = moveEngine.initStationMove(context.taskNo, context.currentStationId, currentDeviceNo, context.taskNo,
+                context.finalTargetStationId, true, null);
+        if (!result) {
+            return getIdleLoopDelayMs();
+        }
+
+        context.initialized = true;
+        context.status = STATUS_RUNNING;
+        context.pendingPathQueue.poll();
+        context.addPassedStation(context.currentStationId);
+        context.lastStepAt = System.currentTimeMillis();
+        context.lastProgressAt = context.lastStepAt;
+        context.lastProgressStationId = context.currentStationId;
+        guardedPublishTaskLocation(context.taskNo, currentDeviceNo, context.currentStationId, true, false);
+        traceEvent(deviceNo, context, "MOVE_INIT", "浠诲姟鍒濆鍖栬捣鐐圭珯鐐�",
+                buildDetails("stationId", context.currentStationId, "recovered", false), false);
+        return Math.max(getInitializeDelayMs(), getMoveStepDurationMs());
+    }
+
+    private MoveStepResult executeNextMove(Integer deviceNo, TaskRuntimeContext context) {
+        Integer nextStationId = context.pendingPathQueue.peek();
+        if (nextStationId == null || context.currentStationId == null) {
+            return MoveStepResult.continueNow();
+        }
+
+        Integer currentDeviceNo = stateManager.getDeviceNoByStationId(context.currentStationId);
+        Integer nextDeviceNo = stateManager.getDeviceNoByStationId(nextStationId);
+        if (currentDeviceNo == null || nextDeviceNo == null) {
+            context.pendingPathQueue.poll();
+            return MoveStepResult.continueNow();
+        }
+
+        boolean moveSuccess = moveEngine.stationMoveToNext(context.taskNo, context.currentStationId, currentDeviceNo,
+                nextStationId, nextDeviceNo, context.taskNo, context.finalTargetStationId);
+        if (moveSuccess) {
+            Integer previousStationId = context.currentStationId;
+            context.currentStationId = nextStationId;
+            context.pendingPathQueue.poll();
+            context.addPassedStation(nextStationId);
+            context.arrivalHandled = false;
+            context.blockedStationId = null;
+            context.status = STATUS_RUNNING;
+            context.lastStepAt = System.currentTimeMillis();
+            context.lastProgressAt = context.lastStepAt;
+            context.lastProgressStationId = context.currentStationId;
+            blockManager.clearBlocked(previousStationId);
+            blockManager.clearBlocked(nextStationId);
+            traceEvent(deviceNo, context, "MOVE_STEP_OK", "浠诲姟瀹屾垚涓�姝ョ珯鐐圭Щ鍔�",
+                    buildDetails("fromStationId", previousStationId, "toStationId", nextStationId,
+                            "remainingPendingPath", context.getPendingStationIds()),
+                    false);
+            return MoveStepResult.continueAfter(getBlockedLoopDelayMs());
+        }
+
+        long now = System.currentTimeMillis();
+        boolean sameStationNoProgress = context.currentStationId != null
+                && context.currentStationId.equals(context.lastProgressStationId);
+        long timeoutMs = blockManager.getFakeRunBlockTimeoutMs(redisUtil);
+        long dwellMs = now - context.lastProgressAt;
+        if (!checkTaskNoInArea(context.taskNo) && blockManager.getFakeAllowCheckBlock(redisUtil)
+                && !blockManager.isSpecialStation(context.currentStationId)
+                && !blockManager.isBlocked(context.currentStationId)
+                && sameStationNoProgress
+                && dwellMs > timeoutMs) {
+            List<Integer> clearedPendingPath = context.getPendingStationIds();
+            News.info("[WCS Debug] fake task娓呯┖寰呮墽琛岃矾寰勶紝鍘熷洜=RUN_BLOCKED锛宒eviceNo={}锛宼askNo={}锛宑urrentStationId={}锛宼argetStationId={}锛宐lockedStationId={}锛宲endingBeforeClear={}",
+                    deviceNo, context.taskNo, context.currentStationId, context.finalTargetStationId,
+                    context.blockedStationId, clearedPendingPath);
+            context.clearPendingPathWithLog(deviceNo, context.taskNo, context.currentStationId,
+                    context.finalTargetStationId, context.blockedStationId, "RUN_BLOCKED");
+            guardedRunBlockStation(context.taskNo, context.currentStationId, currentDeviceNo, context.taskNo,
+                    context.currentStationId);
+            context.blockedStationId = context.currentStationId;
+            context.status = STATUS_BLOCKED;
+            traceEvent(deviceNo, context, "RUN_BLOCKED", "浠诲姟鍦ㄥ綋鍓嶇珯鐐瑰仠鐣欒秴鏃讹紝琚爣璁颁负鍫靛锛屽緟鎵ц璺緞宸叉竻绌�",
+                    buildDetails("blockedStationId", context.currentStationId,
+                            "lastProgressStationId", context.lastProgressStationId,
+                            "dwellMs", dwellMs,
+                            "timeoutMs", timeoutMs,
+                            "clearedPendingPath", clearedPendingPath), false);
+            return MoveStepResult.continueAfter(getMoveStepDurationMs());
+        }
+
+        context.status = STATUS_WAITING;
+        traceEvent(deviceNo, context, "MOVE_STEP_WAIT", "褰撳墠绔欏凡鏇存柊鐩爣浣嗗皻鏈畬鎴愯惤绔欙紝淇濇寔褰撳墠浣嶇疆绛夊緟涓嬩竴娆℃帹杩�",
+                buildDetails("currentStationId", context.currentStationId,
+                        "nextStationId", nextStationId,
+                        "targetStationId", context.finalTargetStationId,
+                        "blockedStationId", context.blockedStationId,
+                        "pendingPath", context.getPendingStationIds()), false);
+        return MoveStepResult.continueAfter(500L);
+    }
+
+    private void resumeFromCurrentStation(Integer deviceNo, TaskRuntimeContext context, String mergeMode,
+            List<Integer> appendedPath, List<Integer> replacedFuturePath, boolean sourceCleared) {
+        if (context.currentStationId != null) {
+            Integer currentDeviceNo = stateManager.getDeviceNoByStationId(context.currentStationId);
+            if (currentDeviceNo != null) {
+                guardedClearRunBlock(context.taskNo, context.currentStationId, currentDeviceNo);
+                guardedPublishTaskLocation(context.taskNo, currentDeviceNo, context.currentStationId, true, false);
+            }
+        }
+        context.blockedStationId = null;
+        context.status = STATUS_RUNNING;
+        context.lastProgressAt = System.currentTimeMillis();
+        context.lastProgressStationId = context.currentStationId;
+        traceEvent(deviceNo, context, "BLOCK_RESET", "鏀跺埌鏂扮殑璺緞鍒嗘锛屽凡娓呴櫎鍫靛骞堕噸鏂拌鏃�",
+                buildDetails("mergeMode", mergeMode, "currentStationId", context.currentStationId,
+                        "targetStationId", context.finalTargetStationId, "queueSize", context.pendingPathQueue.size(),
+                        "appendedPath", appendedPath, "replacedFuturePath", replacedFuturePath,
+                        "sourceCleared", sourceCleared),
+                false);
+    }
+
+    private boolean shouldAdvanceFromCurrentState(TaskRuntimeContext context) {
+        return context != null
+                && context.initialized
+                && context.currentStationId != null
+                && !context.pendingPathQueue.isEmpty()
+                && !STATUS_BLOCKED.equals(context.status)
+                && !STATUS_CANCELLED.equals(context.status)
+                && !STATUS_TIMEOUT.equals(context.status)
+                && !STATUS_FINISHED.equals(context.status);
+    }
+
+    private IdleStepResult handleIdleState(Integer deviceNo, TaskRuntimeContext context) {
+        if (shouldAdvanceFromCurrentState(context)) {
+            traceEvent(deviceNo, context, "IDLE_RESUME", "褰撳墠绔欑偣瀛樺湪鏈畬鎴愯矾寰勶紝绔嬪嵆浠庡綋鍓嶇珯鎭㈠鎺ㄨ繘",
+                    buildDetails("currentStationId", context.currentStationId,
+                            "targetStationId", context.finalTargetStationId,
+                            "pendingPath", context.getPendingStationIds()), false);
+            context.status = STATUS_RUNNING;
+            return IdleStepResult.waitNext(1L);
+        }
+
+        if (context.currentStationId != null && context.finalTargetStationId != null
+                && context.currentStationId.equals(context.finalTargetStationId)) {
+            if (!context.arrivalHandled) {
+                boolean barcodeGenerated = false;
+                if (context.generateBarcode) {
+                    Integer targetDeviceNo = stateManager.getDeviceNoByStationId(context.finalTargetStationId);
+                    if (targetDeviceNo != null) {
+                        barcodeGenerated = guardedGenerateStationBarcode(context.taskNo, context.finalTargetStationId,
+                                targetDeviceNo);
+                    }
+                }
+                context.arrivalHandled = true;
+                context.lastProgressAt = System.currentTimeMillis();
+                context.lastProgressStationId = context.currentStationId;
+                traceEvent(deviceNo, context, "ARRIVED", "浠诲姟鍒拌揪鏈�缁堢洰鏍囩珯鐐�",
+                        buildDetails("stationId", context.currentStationId, "barcodeGenerated", barcodeGenerated),
+                        false);
+            }
+
+            Integer targetDeviceNo = stateManager.getDeviceNoByStationId(context.finalTargetStationId);
+            if (targetDeviceNo != null) {
+                boolean ownerConflict = stateManager.isFinalStationOwnerConflict(targetDeviceNo, context.finalTargetStationId,
+                        context.taskNo);
+                if (ownerConflict) {
+                    logFinalStationOwnershipLost(deviceNo, context);
+                    context.status = STATUS_BLOCKED;
+                    return IdleStepResult.waitNext(getMoveStepDurationMs());
+                }
+                boolean stationCleared = stateManager.isStationClearedForTask(targetDeviceNo, context.finalTargetStationId,
+                        context.taskNo);
+                boolean crnTaken = isCrnTakenByTask(context.taskNo);
+                if (stationCleared || crnTaken) {
+                    context.status = STATUS_FINISHED;
+                    traceEvent(deviceNo, context, "TASK_COMPLETE", "鍫嗗灈鏈哄凡鍙栬蛋璐х墿锛屼换鍔″畬鎴�",
+                            buildDetails("stationId", context.finalTargetStationId, "stationCleared", stationCleared, "crnTaken", crnTaken), false);
+                    return IdleStepResult.finish();
+                }
+            }
+            if (targetDeviceNo != null && !guardedArrivalCompletion(targetDeviceNo, context)) {
+                context.status = STATUS_BLOCKED;
+                return IdleStepResult.waitNext(getMoveStepDurationMs());
+            }
+
+            long dwellMs = System.currentTimeMillis() - context.lastProgressAt;
+            long timeoutMs = blockManager.getFakeRunBlockTimeoutMs(redisUtil);
+            if (!checkTaskNoInArea(context.taskNo) && blockManager.getFakeAllowCheckBlock(redisUtil)
+                    && !blockManager.isSpecialStation(context.currentStationId)
+                    && !blockManager.isBlocked(context.currentStationId)
+                    && dwellMs > timeoutMs) {
+                context.status = STATUS_BLOCKED;
+                context.clearPendingPathWithLog(deviceNo, context.taskNo, context.currentStationId,
+                        context.finalTargetStationId, context.blockedStationId, "TARGET_RUN_BLOCKED");
+                guardedRunBlockStation(context.taskNo, context.currentStationId, targetDeviceNo, context.taskNo,
+                        context.currentStationId);
+                context.blockedStationId = context.currentStationId;
+                traceEvent(deviceNo, context, "RUN_BLOCKED", "浠诲姟鍒拌揪缁堢偣绔欏悗鍋滅暀瓒呮椂锛岃鏍囪涓哄牭濉烇紝绛夊緟鍫嗗灈鏈哄彇璐�",
+                        buildDetails("blockedStationId", context.currentStationId,
+                                "lastProgressStationId", context.lastProgressStationId,
+                                "dwellMs", dwellMs,
+                                "timeoutMs", timeoutMs), false);
+                return IdleStepResult.waitNext(getMoveStepDurationMs());
+            }
+
+            return IdleStepResult.waitNext(getFinishDelayMs());
+        }
+
+        Long lastTime = taskLastUpdateTime.get(context.taskNo);
+        long waitSegmentTimeoutMs = getWaitSegmentTimeoutMs();
+        if (lastTime != null && System.currentTimeMillis() - lastTime > waitSegmentTimeoutMs) {
+            traceEvent(deviceNo, context, "WAIT_TIMEOUT", "绛夊緟鏂扮殑璺緞鍒嗘瓒呮椂",
+                    buildDetails("timeoutMs", waitSegmentTimeoutMs, "currentStationId", context.currentStationId,
+                            "targetStationId", context.finalTargetStationId),
+                    false);
+            taskLastUpdateTime.put(context.taskNo, System.currentTimeMillis());
+        }
+        return IdleStepResult.waitNext(getIdleLoopDelayMs());
+    }
+
+    private List<Integer> normalizePath(List<Integer> path) {
+        List<Integer> result = new ArrayList<Integer>();
+        if (path == null) {
+            return result;
+        }
+        for (Integer stationId : path) {
+            if (stationId != null) {
+                result.add(stationId);
+            }
+        }
+        return result;
+    }
+
+    private void trimPendingPathToCurrent(LinkedBlockingQueue<Integer> queue, Integer currentStationId) {
+        if (queue == null || currentStationId == null || queue.isEmpty()) {
+            return;
+        }
+        List<Integer> snapshot = new ArrayList<Integer>(queue);
+        int index = snapshot.indexOf(currentStationId);
+        if (index <= 0) {
+            return;
+        }
+        for (int i = 0; i < index; i++) {
+            queue.poll();
+        }
+    }
+
+    private List<Integer> rebuildPendingPathFromCurrent(TaskRuntimeContext context, List<Integer> newPath) {
+        List<Integer> rebuilt = new ArrayList<Integer>();
+        if (newPath == null || newPath.isEmpty()) {
+            return rebuilt;
+        }
+        Integer currentStationId = context.currentStationId;
+        int startIndex = 0;
+        if (currentStationId != null) {
+            int currentIndex = newPath.indexOf(currentStationId);
+            if (currentIndex < 0) {
+                return rebuilt;
+            }
+            startIndex = currentIndex + 1;
+        }
+        for (int i = startIndex; i < newPath.size(); i++) {
+            rebuilt.add(newPath.get(i));
+        }
+        return rebuilt;
+    }
+
+    private void replacePendingPathQueue(TaskRuntimeContext context, List<Integer> futurePath) {
+        context.pendingPathQueue.clear();
+        if (futurePath == null) {
+            return;
+        }
+        for (Integer stationId : futurePath) {
+            context.pendingPathQueue.offer(stationId);
+        }
+    }
+
+    private boolean hasTaskReset(Integer taskNo) {
+        // 浠跨湡绯荤粺涓嶅搷搴斿閮ㄥ彇娑堜俊鍙凤紙濡傚牭濉為噸璺敱瑙﹀彂鐨� signalSegmentReset锛夛紝
+        // 閬垮厤浠诲姟鍦ㄧ珯鐐硅璧拌繃绋嬩腑琚剰澶栨竻闄�
+        return false;
+    }
+
+    private Integer getLastInQueue(LinkedBlockingQueue<Integer> queue) {
+        Integer last = null;
+        for (Integer item : queue) {
+            last = item;
+        }
+        return last;
+    }
+
+    private int getPathAppendStartIndex(List<Integer> newPath, Integer currentStationId, Integer lastInQueue) {
+        if (newPath == null || newPath.isEmpty()) {
+            return 0;
+        }
+
+        if (lastInQueue != null) {
+            int idx = newPath.lastIndexOf(lastInQueue);
+            if (idx >= 0) {
+                return idx + 1;
+            }
+        }
+
+        if (currentStationId != null) {
+            int idx = newPath.lastIndexOf(currentStationId);
+            if (idx >= 0) {
+                return idx + 1;
+            }
+            return -1;
+        }
+
+        if (lastInQueue != null) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    private void syncCurrentStationTarget(Integer taskNo, Integer currentStationId, Integer targetStationId) {
+        if (currentStationId == null || targetStationId == null) {
+            return;
+        }
+        Integer currentDeviceNo = stateManager.getDeviceNoByStationId(currentStationId);
+        if (currentDeviceNo == null) {
+            return;
+        }
+
+        moveEngine.lockStations(currentStationId);
         try {
-            Thread.sleep(ms);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
+            ZyStationStatusEntity currentStatus = stateManager.findStationStatus(currentDeviceNo, currentStationId);
+            if (currentStatus == null) {
+                return;
+            }
+
+            if (hasOwnerConflict(currentStatus, taskNo)) {
+                logOwnerConflict("syncCurrentStationTarget", currentStationId, currentStatus, taskNo, targetStationId, false,
+                        "owner_conflict");
+                return;
+            }
+
+            stateManager.updateStationDataInternal(currentStationId, currentDeviceNo, taskNo, targetStationId, null, null, null);
+        } finally {
+            moveEngine.unlockStations(currentStationId);
         }
     }
 
-    /**
-     * 鑾峰彇绔欑偣閿侊紝濡傛灉涓嶅瓨鍦ㄥ垯鍒涘缓
-     */
-    private ReentrantLock getStationLock(Integer stationId) {
-        return stationLocks.computeIfAbsent(stationId, k -> new ReentrantLock());
+    private boolean hasOwnerConflict(ZyStationStatusEntity currentStatus, Integer incomingTaskNo) {
+        return currentStatus != null
+                && currentStatus.isLoading()
+                && currentStatus.getTaskNo() != null
+                && currentStatus.getTaskNo() > 0
+                && (incomingTaskNo == null || !currentStatus.getTaskNo().equals(incomingTaskNo));
     }
 
-    /**
-     * 鎸夐『搴忛攣瀹氬涓珯鐐癸紙閬垮厤姝婚攣锛�
-     */
-    private void lockStations(Integer... stationIds) {
-        Integer[] sorted = Arrays.copyOf(stationIds, stationIds.length);
-        Arrays.sort(sorted);
-        for (Integer stationId : sorted) {
-            getStationLock(stationId).lock();
-        }
+    private void logOwnerConflict(String operation, Integer stationId, ZyStationStatusEntity currentStatus,
+            Integer incomingTaskNo, Integer incomingTargetStationId, boolean finalStation, String reason) {
+        News.info("[WCS Debug] fake station owner鍐茬獊锛宱peration={}锛宻tationId={}锛宑urrentTaskNo={}锛宑urrentLoading={}锛宑urrentTargetStaNo={}锛宨ncomingTaskNo={}锛宨ncomingTargetStaNo={}锛宖inalStation={}锛宺eason={}",
+                operation,
+                stationId,
+                currentStatus == null ? null : currentStatus.getTaskNo(),
+                currentStatus == null ? null : currentStatus.isLoading(),
+                currentStatus == null ? null : currentStatus.getTargetStaNo(),
+                incomingTaskNo,
+                incomingTargetStationId,
+                finalStation,
+                reason);
     }
 
-    /**
-     * 鎸夐�嗗簭瑙i攣澶氫釜绔欑偣
-     */
-    private void unlockStations(Integer... stationIds) {
-        Integer[] sorted = Arrays.copyOf(stationIds, stationIds.length);
-        Arrays.sort(sorted);
-        for (int i = sorted.length - 1; i >= 0; i--) {
-            getStationLock(sorted[i]).unlock();
-        }
-    }
-
-    /**
-     * 鏇存柊绔欑偣鏁版嵁锛堣皟鐢ㄥ墠蹇呴』宸叉寔鏈夎绔欑偣鐨勯攣锛�
-     */
-    private boolean updateStationDataInternal(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStaNo,
-            Boolean isLoading, String barcode, Boolean runBlock) {
-        List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-        if (statusList == null) {
+    private boolean ensureStationWritable(String operation, Integer deviceNo, Integer stationId,
+            Integer incomingTaskNo, Integer incomingTargetStationId, boolean finalStation) {
+        if (deviceNo == null || stationId == null) {
             return false;
         }
-
-        ZyStationStatusEntity currentStatus = statusList.stream()
-                .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-
+        ZyStationStatusEntity currentStatus = stateManager.findStationStatus(deviceNo, stationId);
         if (currentStatus == null) {
             return false;
         }
-
-        if (taskNo != null) {
-            currentStatus.setTaskNo(taskNo);
+        if (!hasOwnerConflict(currentStatus, incomingTaskNo)) {
+            return true;
         }
+        logOwnerConflict(operation, stationId, currentStatus, incomingTaskNo, incomingTargetStationId, finalStation,
+                finalStation ? "final_station_owner_conflict" : "owner_conflict");
+        return false;
+    }
 
-        if (targetStaNo != null) {
-            currentStatus.setTargetStaNo(targetStaNo);
+    private boolean ensureStationClearable(String operation, Integer deviceNo, Integer stationId, Integer expectedTaskNo,
+            boolean finalStation) {
+        if (deviceNo == null || stationId == null) {
+            return false;
         }
-
-        if (isLoading != null) {
-            currentStatus.setLoading(isLoading);
+        ZyStationStatusEntity currentStatus = stateManager.findStationStatus(deviceNo, stationId);
+        if (currentStatus == null) {
+            return false;
         }
-
-        if (barcode != null) {
-            currentStatus.setBarcode(barcode);
+        if (!hasOwnerConflict(currentStatus, expectedTaskNo)) {
+            return true;
         }
+        if (isLegalClearStation(stationId)) {
+            return true;
+        }
+        logOwnerConflict(operation, stationId, currentStatus, expectedTaskNo, currentStatus.getTargetStaNo(), finalStation,
+                "illegal_clear_attempt");
+        return false;
+    }
 
-        if (runBlock != null) {
-            currentStatus.setRunBlock(runBlock);
+    private boolean isLegalClearStation(Integer stationId) {
+        if (stationId == null) {
+            return false;
+        }
+        Set<Integer> stationIds = legalClearStationIds;
+        if (stationIds == null || stationIds.isEmpty()) {
+            refreshLegalClearStationIds();
+            stationIds = legalClearStationIds;
+        }
+        return stationIds != null && stationIds.contains(stationId);
+    }
+
+    private boolean isBarcodeStation(Integer stationId) {
+        if (stationId == null) {
+            return false;
+        }
+        Set<Integer> stationIds = barcodeStationIds;
+        if (stationIds == null || stationIds.isEmpty()) {
+            refreshBarcodeStationIds();
+            stationIds = barcodeStationIds;
+        }
+        return stationIds != null && stationIds.contains(stationId);
+    }
+
+    private void refreshLegalClearStationIds() {
+        try {
+            Set<Integer> stationIds = new HashSet<Integer>();
+
+            com.zy.asrs.service.BasCrnpService basCrnpService = com.core.common.SpringUtils.getBean(com.zy.asrs.service.BasCrnpService.class);
+            List<com.zy.asrs.entity.BasCrnp> basCrnps = basCrnpService.list();
+            for (com.zy.asrs.entity.BasCrnp basCrnp : basCrnps) {
+                if (basCrnp == null) {
+                    continue;
+                }
+                collectStationIds(stationIds, basCrnp.getInStationList$());
+                collectStationIds(stationIds, basCrnp.getOutStationList$());
+            }
+
+            com.zy.asrs.service.BasDevpService basDevpService = com.core.common.SpringUtils.getBean(com.zy.asrs.service.BasDevpService.class);
+            List<com.zy.asrs.entity.BasDevp> basDevps = basDevpService.list();
+            for (com.zy.asrs.entity.BasDevp basDevp : basDevps) {
+                if (basDevp == null) {
+                    continue;
+                }
+                collectStationIds(stationIds, basDevp.getBarcodeStationList$());
+                collectStationIds(stationIds, basDevp.getInStationList$());
+                collectStationIds(stationIds, basDevp.getOutStationList$());
+            }
+
+            legalClearStationIds = stationIds;
+        } catch (Exception e) {
+            News.info("[WCS Debug] fake 鍚堟硶娓呯珯鐧藉悕鍗曞埛鏂板け璐ワ紝寮傚父绫诲瀷={}锛屽紓甯镐俊鎭�={}",
+                    e.getClass().getSimpleName(), e.getMessage());
+        }
+    }
+
+    private void refreshBarcodeStationIds() {
+        try {
+            Set<Integer> stationIds = new HashSet<Integer>();
+            com.zy.asrs.service.BasDevpService basDevpService = com.core.common.SpringUtils.getBean(com.zy.asrs.service.BasDevpService.class);
+            List<com.zy.asrs.entity.BasDevp> basDevps = basDevpService.list();
+            for (com.zy.asrs.entity.BasDevp basDevp : basDevps) {
+                if (basDevp == null) {
+                    continue;
+                }
+                collectStationIds(stationIds, basDevp.getBarcodeStationList$());
+            }
+            barcodeStationIds = stationIds;
+        } catch (Exception e) {
+            News.info("[WCS Debug] fake 鏉$爜绔欑櫧鍚嶅崟鍒锋柊澶辫触锛屽紓甯哥被鍨�={}锛屽紓甯镐俊鎭�={}",
+                    e.getClass().getSimpleName(), e.getMessage());
+        }
+    }
+
+    private void collectStationIds(Set<Integer> stationIds, List<com.zy.core.model.StationObjModel> stations) {
+        if (stationIds == null || stations == null || stations.isEmpty()) {
+            return;
+        }
+        for (com.zy.core.model.StationObjModel station : stations) {
+            if (station != null && station.getStationId() != null) {
+                stationIds.add(station.getStationId());
+            }
+        }
+    }
+
+    private boolean isFinalStation(Integer taskNo, Integer stationId) {
+        TaskRuntimeContext context = taskNo == null ? null : taskContexts.get(taskNo);
+        return context != null && stationId != null && stationId.equals(context.finalTargetStationId);
+    }
+
+    private void logFinalStationOwnershipLost(Integer deviceNo, TaskRuntimeContext context) {
+        Integer stationId = context == null ? null : context.finalTargetStationId;
+        Integer targetDeviceNo = stateManager.getDeviceNoByStationId(stationId);
+        ZyStationStatusEntity currentStatus = targetDeviceNo == null ? null : stateManager.snapshotStation(targetDeviceNo, stationId);
+        News.info("[WCS Debug] fake 鏈�缁堢珯鎵�鏈夋潈涓㈠け锛宼askNo={}锛宻tationId={}锛宑urrentTaskNo={}锛宑urrentLoading={}锛宑urrentTargetStaNo={}锛宺eason={}",
+                context == null ? null : context.taskNo,
+                stationId,
+                currentStatus == null ? null : currentStatus.getTaskNo(),
+                currentStatus == null ? null : currentStatus.isLoading(),
+                currentStatus == null ? null : currentStatus.getTargetStaNo(),
+                "final_station_owner_conflict");
+        traceEvent(deviceNo, context, "FINAL_STATION_OWNER_CONFLICT", "鏈�缁堢珯浠嶆湁鐗╀絾鎵�鏈夎�呭凡琚叾浠栦换鍔¤鐩�",
+                buildDetails("stationId", stationId,
+                        "currentTaskNo", currentStatus == null ? null : currentStatus.getTaskNo(),
+                        "currentLoading", currentStatus == null ? null : currentStatus.isLoading(),
+                        "currentTargetStaNo", currentStatus == null ? null : currentStatus.getTargetStaNo()), false);
+    }
+
+    private boolean guardedClearStationForDispatch(Integer deviceNo, Integer stationId, Integer expectedTaskNo, String reason) {
+        if (!ensureStationClearable("clearStationForDispatch", deviceNo, stationId, expectedTaskNo,
+                isFinalStation(expectedTaskNo, stationId))) {
+            return false;
+        }
+        stateManager.clearStationForDispatch(deviceNo, stationId, reason);
+        return true;
+    }
+
+    private boolean guardedResetStation(Integer deviceNo, Integer stationId, Integer expectedTaskNo) {
+        if (!ensureStationClearable("resetStation", deviceNo, stationId, expectedTaskNo,
+                isFinalStation(expectedTaskNo, stationId))) {
+            return false;
+        }
+        stateManager.resetStation(deviceNo, stationId);
+        return true;
+    }
+
+    private boolean guardedUpdateStationBarcode(Integer deviceNo, Integer stationId, Integer taskNo, String barcode) {
+        if (!ensureStationWritable("updateStationBarcode", deviceNo, stationId, taskNo, null,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        stateManager.updateStationBarcode(deviceNo, stationId, barcode);
+        return true;
+    }
+
+    private boolean guardedGenerateFakeOutStationData(Integer deviceNo, Integer stationId, Integer taskNo) {
+        if (!ensureStationWritable("generateFakeOutStationData", deviceNo, stationId, taskNo, null,
+                isFinalStation(taskNo, stationId))) {
+            News.error("fake 鍑哄簱绔欑偣鏈夌墿鍐欏叆琚嫆缁濄�俤eviceNo={}锛宻tationId={}锛宼askNo={}锛宺eason=station-not-writable",
+                    deviceNo, stationId, taskNo);
+            return false;
+        }
+        stateManager.generateFakeOutStationData(deviceNo, stationId);
+        News.info("fake 鍑哄簱绔欑偣鏈夌墿鍐欏叆鎴愬姛銆俤eviceNo={}锛宻tationId={}锛宼askNo={}锛宭oading=true",
+                deviceNo, stationId, taskNo);
+        return true;
+    }
+
+    private boolean guardedHandoffBarcodeStation(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) {
+        if (!ensureStationWritable("handoffBarcodeStation", deviceNo, stationId, taskNo, targetStationId,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        stateManager.handoffBarcodeStation(deviceNo, taskNo, stationId, targetStationId);
+        return true;
+    }
+
+    private boolean guardedRunBlockStation(Integer taskNo, Integer stationId, Integer deviceNo, Integer ownerTaskNo,
+            Integer targetStationId) {
+        if (!ensureStationWritable("runBlockStation", deviceNo, stationId, ownerTaskNo, targetStationId,
+                isFinalStation(ownerTaskNo, stationId))) {
+            return false;
+        }
+        blockManager.runBlockStation(taskNo, stationId, deviceNo, ownerTaskNo, targetStationId);
+        return true;
+    }
+
+    private boolean guardedClearRunBlock(Integer taskNo, Integer stationId, Integer deviceNo) {
+        if (!ensureStationWritable("clearRunBlock", deviceNo, stationId, taskNo, null,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        blockManager.clearRunBlock(stationId, deviceNo);
+        return true;
+    }
+
+    private boolean guardedPublishTaskLocation(Integer taskNo, Integer deviceNo, Integer stationId, boolean loading, boolean runBlock) {
+        if (loading && !ensureStationWritable("publishTaskLocation", deviceNo, stationId, taskNo, null,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        stateManager.publishTaskLocation(taskNo, deviceNo, stationId, loading, runBlock);
+        return true;
+    }
+
+    private boolean guardedGenerateStationData(Integer deviceNo, Integer taskNo, Integer stationId, Integer targetStationId) {
+        if (!ensureStationWritable("generateStationData", deviceNo, stationId, taskNo, targetStationId,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        stateManager.generateStationData(deviceNo, taskNo, stationId, targetStationId);
+        return true;
+    }
+
+    private boolean guardedSyncCurrentStationTarget(Integer taskNo, Integer currentStationId, Integer targetStationId) {
+        syncCurrentStationTarget(taskNo, currentStationId, targetStationId);
+        return true;
+    }
+
+    private boolean guardedClearTaskLocationIfMatches(Integer taskNo, Integer deviceNo, Integer stationId) {
+        stateManager.clearTaskLocationIfMatches(taskNo, deviceNo, stationId);
+        return true;
+    }
+
+    private boolean guardedPublishCurrentLocation(Integer taskNo, Integer deviceNo, Integer stationId) {
+        return guardedPublishTaskLocation(taskNo, deviceNo, stationId, true, false);
+    }
+
+    private boolean guardedGenerateStationBarcode(Integer taskNo, Integer stationId, Integer deviceNo) {
+        if (!ensureStationWritable("generateStationBarcode", deviceNo, stationId, taskNo, null,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        return stateManager.generateStationBarcode(taskNo, stationId, deviceNo);
+    }
+
+    private boolean guardedUpdateStationData(Integer stationId, Integer deviceNo, Integer taskNo, Integer targetStationId,
+            Boolean loading, String barcode, Boolean runBlock) {
+        if ((taskNo != null || Boolean.TRUE.equals(loading))
+                && !ensureStationWritable("updateStationData", deviceNo, stationId, taskNo, targetStationId,
+                isFinalStation(taskNo, stationId))) {
+            return false;
+        }
+        return stateManager.updateStationDataInternal(stationId, deviceNo, taskNo, targetStationId, loading, barcode, runBlock);
+    }
+
+    private boolean isFinalStationConflict(Integer taskNo, Integer stationId, Integer deviceNo) {
+        return isFinalStation(taskNo, stationId) && stateManager.isOccupiedByOtherLoadingTask(deviceNo, stationId, taskNo);
+    }
+
+    private boolean guardedResetOrClearBlockedStation(Integer taskNo, Integer stationId, Integer deviceNo) {
+        return ensureStationClearable("blockedStationClear", deviceNo, stationId, taskNo, isFinalStation(taskNo, stationId));
+    }
+
+    private boolean guardedStationOccupied(Integer taskNo, Integer stationId, Integer deviceNo) {
+        return !stateManager.isOccupiedByOtherLoadingTask(deviceNo, stationId, taskNo);
+    }
+
+    private boolean guardedFinalStationOwnership(Integer taskNo, Integer stationId, Integer deviceNo) {
+        return !stateManager.isFinalStationOwnerConflict(deviceNo, stationId, taskNo);
+    }
+
+    private boolean guardedFinalStationWritable(Integer taskNo, Integer stationId, Integer deviceNo, String operation) {
+        if (!guardedFinalStationOwnership(taskNo, stationId, deviceNo)) {
+            ZyStationStatusEntity currentStatus = stateManager.snapshotStation(deviceNo, stationId);
+            logOwnerConflict(operation, stationId, currentStatus, taskNo,
+                    currentStatus == null ? null : currentStatus.getTargetStaNo(), true,
+                    "final_station_owner_conflict");
+            return false;
         }
         return true;
     }
 
-    /**
-     * 鍒濆鍖栫珯鐐圭Щ鍔紙浣跨敤绔欑偣绾ч攣锛�
-     */
-    public boolean initStationMove(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo,
-            Integer taskNo, Integer targetStationId, Boolean isLoading, String barcode) {
-        lockStations(currentStationId);
-        try {
-            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentStationDeviceNo);
-            if (statusList == null) {
-                return false;
-            }
-
-            ZyStationStatusEntity currentStatus = statusList.stream()
-                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
-            if (currentStatus == null) {
-                return false;
-            }
-
-            if (currentStatus.getTaskNo() > 0) {
-                if (!currentStatus.getTaskNo().equals(taskNo) && currentStatus.isLoading()) {
-                    return false;
-                }
-            }
-
-            return updateStationDataInternal(currentStationId, currentStationDeviceNo, taskNo, targetStationId,
-                    isLoading, barcode, false);
-        } finally {
-            unlockStations(currentStationId);
+    private boolean guardedFinalStationClearable(Integer taskNo, Integer stationId, Integer deviceNo, String operation) {
+        if (!guardedFinalStationOwnership(taskNo, stationId, deviceNo)) {
+            ZyStationStatusEntity currentStatus = stateManager.snapshotStation(deviceNo, stationId);
+            logOwnerConflict(operation, stationId, currentStatus, taskNo,
+                    currentStatus == null ? null : currentStatus.getTargetStaNo(), true,
+                    "illegal_clear_attempt");
+            return false;
         }
+        return true;
     }
 
-    /**
-     * 绔欑偣绉诲姩鍒颁笅涓�涓綅缃紙浣跨敤绔欑偣绾ч攣锛屾寜ID椤哄簭鑾峰彇閿侀伩鍏嶆閿侊級
-     */
-    public boolean stationMoveToNext(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo,
-            Integer nextStationId, Integer nextStationDeviceNo, Integer taskNo, Integer targetStaNo) {
-        // 鍚屾椂閿佸畾褰撳墠绔欑偣鍜屼笅涓�涓珯鐐癸紙鎸塈D椤哄簭锛岄伩鍏嶆閿侊級
-        lockStations(currentStationId, nextStationId);
-        try {
-            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentStationDeviceNo);
-            if (statusList == null) {
-                return false;
-            }
-
-            List<ZyStationStatusEntity> nextStatusList = deviceStatusMap.get(nextStationDeviceNo);
-            if (nextStatusList == null) {
-                return false;
-            }
-
-            ZyStationStatusEntity currentStatus = statusList.stream()
-                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
-            ZyStationStatusEntity nextStatus = nextStatusList.stream()
-                    .filter(item -> item.getStationId().equals(nextStationId)).findFirst().orElse(null);
-
-            if (currentStatus == null || nextStatus == null) {
-                return false;
-            }
-
-            if (nextStatus.getTaskNo() > 0 || nextStatus.isLoading()) {
-                return false;
-            }
-
-            boolean result = updateStationDataInternal(nextStationId, nextStationDeviceNo, taskNo, targetStaNo, true,
-                    null, false);
-            if (!result) {
-                return false;
-            }
-
-            boolean result2 = updateStationDataInternal(currentStationId, currentStationDeviceNo, 0, 0, false, "",
-                    false);
-            if (!result2) {
-                return false;
-            }
-
-            return true;
-        } finally {
-            unlockStations(currentStationId, nextStationId);
-        }
+    private boolean shouldTreatAsFinalStationConflict(Integer taskNo, Integer stationId, Integer deviceNo) {
+        return isFinalStation(taskNo, stationId) && stateManager.isFinalStationOwnerConflict(deviceNo, stationId, taskNo);
     }
 
-    /**
-     * 鐢熸垚绔欑偣鏉$爜锛堜娇鐢ㄧ珯鐐圭骇閿侊級
-     */
-    public boolean generateStationBarcode(Integer lockTaskNo, Integer currentStationId,
-            Integer currentStationDeviceNo) {
-        lockStations(currentStationId);
-        try {
-            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentStationDeviceNo);
-            if (statusList == null) {
-                return false;
-            }
-
-            ZyStationStatusEntity currentStatus = statusList.stream()
-                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
-            if (currentStatus == null) {
-                return false;
-            }
-
-            Random random = new Random();
-
-            String barcodeTime = String.valueOf(System.currentTimeMillis());
-            String barcode = String.valueOf(random.nextInt(10)) + String.valueOf(random.nextInt(10))
-                    + barcodeTime.substring(7);
-
-            return updateStationDataInternal(currentStationId, currentStationDeviceNo, null, null, null, barcode, null);
-        } finally {
-            unlockStations(currentStationId);
+    private boolean guardedFinalStationMutation(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId) {
+        if (shouldTreatAsFinalStationConflict(taskNo, stationId, deviceNo)) {
+            ZyStationStatusEntity currentStatus = stateManager.snapshotStation(deviceNo, stationId);
+            logOwnerConflict(operation, stationId, currentStatus, taskNo, targetStationId, true,
+                    "final_station_owner_conflict");
+            return false;
         }
+        return true;
     }
 
-    /**
-     * 娓呴櫎绔欑偣鏁版嵁锛堜娇鐢ㄧ珯鐐圭骇閿侊級
-     */
-    public boolean clearStation(Integer deviceNo, Integer lockTaskNo, Integer currentStationId) {
-        lockStations(currentStationId);
-        try {
-            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-            if (statusList == null) {
-                return false;
-            }
-
-            ZyStationStatusEntity currentStatus = statusList.stream()
-                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
-            if (currentStatus == null) {
-                return false;
-            }
-
-            return updateStationDataInternal(currentStationId, deviceNo, 0, 0, false, "", false);
-        } finally {
-            unlockStations(currentStationId);
+    private boolean guardedFinalStationClear(String operation, Integer taskNo, Integer stationId, Integer deviceNo) {
+        if (shouldTreatAsFinalStationConflict(taskNo, stationId, deviceNo)) {
+            ZyStationStatusEntity currentStatus = stateManager.snapshotStation(deviceNo, stationId);
+            logOwnerConflict(operation, stationId, currentStatus, taskNo,
+                    currentStatus == null ? null : currentStatus.getTargetStaNo(), true,
+                    "illegal_clear_attempt");
+            return false;
         }
+        return true;
     }
 
-    /**
-     * 鏍囪绔欑偣鍫靛锛堜娇鐢ㄧ珯鐐圭骇閿侊級
-     */
-    public boolean runBlockStation(Integer lockTaskNo, Integer currentStationId, Integer currentStationDeviceNo,
-            Integer taskNo, Integer blockStationId) {
-        lockStations(currentStationId);
-        try {
-            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(currentStationDeviceNo);
-            if (statusList == null) {
-                return false;
-            }
-
-            ZyStationStatusEntity currentStatus = statusList.stream()
-                    .filter(item -> item.getStationId().equals(currentStationId)).findFirst().orElse(null);
-
-            if (currentStatus == null) {
-                return false;
-            }
-
-            return updateStationDataInternal(currentStationId, currentStationDeviceNo, taskNo, blockStationId, true, "",
-                    true);
-        } finally {
-            unlockStations(currentStationId);
+    private boolean guardedStationWrite(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId) {
+        if (!guardedFinalStationMutation(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
         }
+        return ensureStationWritable(operation, deviceNo, stationId, taskNo, targetStationId, isFinalStation(taskNo, stationId));
     }
 
-    /**
-     * 娓呴櫎绔欑偣鍫靛鏍囪锛堝牭濉炴仮澶嶆椂浣跨敤锛�
-     */
-    public void clearRunBlock(Integer stationId, Integer deviceNo) {
-        lockStations(stationId);
-        try {
-            List<ZyStationStatusEntity> statusList = deviceStatusMap.get(deviceNo);
-            if (statusList == null) {
+    private boolean guardedStationClear(String operation, Integer taskNo, Integer stationId, Integer deviceNo) {
+        if (!guardedFinalStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        return ensureStationClearable(operation, deviceNo, stationId, taskNo, isFinalStation(taskNo, stationId));
+    }
+
+    private boolean guardedStateMutation(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId,
+            Runnable mutation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedStateClear(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Runnable mutation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedFinalStationCompletion(Integer deviceNo, TaskRuntimeContext context) {
+        if (context == null || context.finalTargetStationId == null || context.taskNo == null) {
+            return false;
+        }
+        return !stateManager.isFinalStationOwnerConflict(deviceNo, context.finalTargetStationId, context.taskNo);
+    }
+
+    private boolean guardedCurrentStationOwnership(Integer taskNo, Integer currentStationId, Integer currentDeviceNo) {
+        return !stateManager.isOccupiedByOtherLoadingTask(currentDeviceNo, currentStationId, taskNo);
+    }
+
+    private boolean guardedTargetStationOwnership(Integer taskNo, Integer stationId, Integer deviceNo) {
+        return !stateManager.isOccupiedByOtherLoadingTask(deviceNo, stationId, taskNo);
+    }
+
+    private boolean guardedCommandWrite(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId, Runnable mutation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedCommandClear(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Runnable mutation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedRunBlockMutation(Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId) {
+        return guardedStationWrite("runBlockStation", taskNo, stationId, deviceNo, targetStationId);
+    }
+
+    private boolean guardedClearMutation(Integer taskNo, Integer stationId, Integer deviceNo, String operation) {
+        return guardedStationClear(operation, taskNo, stationId, deviceNo);
+    }
+
+    private boolean guardedArrivalOwnership(Integer deviceNo, TaskRuntimeContext context) {
+        return context != null && context.finalTargetStationId != null && context.taskNo != null
+                && !stateManager.isFinalStationOwnerConflict(deviceNo, context.finalTargetStationId, context.taskNo);
+    }
+
+    private boolean guardedArrivalStationWritable(Integer deviceNo, TaskRuntimeContext context, String operation) {
+        if (!guardedArrivalOwnership(deviceNo, context)) {
+            logFinalStationOwnershipLost(deviceNo, context);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean guardedArrivalStationClearable(Integer deviceNo, TaskRuntimeContext context, String operation) {
+        if (!guardedArrivalOwnership(deviceNo, context)) {
+            logFinalStationOwnershipLost(deviceNo, context);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean guardedStationMutation(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId,
+            Runnable mutation, boolean clearOperation) {
+        boolean allowed = clearOperation
+                ? guardedStationClear(operation, taskNo, stationId, deviceNo)
+                : guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId);
+        if (!allowed) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedFinalArrivalState(Integer deviceNo, TaskRuntimeContext context) {
+        if (context == null || context.finalTargetStationId == null || context.taskNo == null) {
+            return false;
+        }
+        if (stateManager.isFinalStationOwnerConflict(deviceNo, context.finalTargetStationId, context.taskNo)) {
+            logFinalStationOwnershipLost(deviceNo, context);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean guardedArrivalCompletion(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedStationOwnership(String operation, Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId,
+            boolean clearOperation) {
+        return clearOperation
+                ? guardedStationClear(operation, taskNo, stationId, deviceNo)
+                : guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId);
+    }
+
+    private boolean guardedStationMutationIfAllowed(String operation, Integer taskNo, Integer stationId, Integer deviceNo,
+            Integer targetStationId, boolean clearOperation, Runnable mutation) {
+        if (!guardedStationOwnership(operation, taskNo, stationId, deviceNo, targetStationId, clearOperation)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedArrivalStationState(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedMutateFinalStation(String operation, Integer taskNo, Integer stationId, Integer deviceNo,
+            Integer targetStationId, Runnable mutation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedClearFinalStation(String operation, Integer taskNo, Integer stationId, Integer deviceNo,
+            Runnable mutation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedArrivalState(Integer deviceNo, TaskRuntimeContext context) {
+        if (!guardedFinalArrivalState(deviceNo, context)) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean guardedCurrentStationWrite(Integer taskNo, Integer currentStationId, Integer currentDeviceNo, Integer targetStationId,
+            String operation) {
+        return guardedStationWrite(operation, taskNo, currentStationId, currentDeviceNo, targetStationId);
+    }
+
+    private boolean guardedCurrentStationClear(Integer taskNo, Integer currentStationId, Integer currentDeviceNo, String operation) {
+        return guardedStationClear(operation, taskNo, currentStationId, currentDeviceNo);
+    }
+
+    private boolean guardedFinalStationWrite(Integer taskNo, Integer stationId, Integer deviceNo, Integer targetStationId, String operation) {
+        return guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId);
+    }
+
+    private boolean guardedFinalStationClear(Integer taskNo, Integer stationId, Integer deviceNo, String operation) {
+        return guardedStationClear(operation, taskNo, stationId, deviceNo);
+    }
+
+    private boolean guardedStationBarcodeWrite(Integer deviceNo, Integer stationId, Integer taskNo, String barcode) {
+        return guardedUpdateStationBarcode(deviceNo, stationId, taskNo, barcode);
+    }
+
+    private boolean guardedStationOccupancyWrite(Integer deviceNo, Integer stationId, Integer taskNo, Integer targetStationId,
+            Runnable mutation, String operation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedStationOccupancyClear(Integer deviceNo, Integer stationId, Integer taskNo,
+            Runnable mutation, String operation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedStationWriteForTask(Integer deviceNo, Integer stationId, Integer taskNo, Integer targetStationId,
+            String operation) {
+        return guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId);
+    }
+
+    private boolean guardedStationClearForTask(Integer deviceNo, Integer stationId, Integer taskNo, String operation) {
+        return guardedStationClear(operation, taskNo, stationId, deviceNo);
+    }
+
+    private boolean guardedMutateStationIfOwned(Integer deviceNo, Integer stationId, Integer taskNo, Integer targetStationId,
+            String operation, Runnable mutation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedClearStationIfOwned(Integer deviceNo, Integer stationId, Integer taskNo, String operation,
+            Runnable mutation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedArrivalVisibility(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedFinalStationNotOverwritten(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedMutateOccupiedStation(String operation, Integer deviceNo, Integer stationId, Integer taskNo,
+            Integer targetStationId, Runnable mutation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedClearOccupiedStation(String operation, Integer deviceNo, Integer stationId, Integer taskNo,
+            Runnable mutation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedFinalStationStillOwned(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedStateWrite(String operation, Integer deviceNo, Integer stationId, Integer taskNo, Integer targetStationId) {
+        return guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId);
+    }
+
+    private boolean guardedStateClear(String operation, Integer deviceNo, Integer stationId, Integer taskNo) {
+        return guardedStationClear(operation, taskNo, stationId, deviceNo);
+    }
+
+    private boolean guardedArrivalOwnerCheck(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedArrivalConflict(Integer deviceNo, TaskRuntimeContext context) {
+        return stateManager.isFinalStationOwnerConflict(deviceNo, context.finalTargetStationId, context.taskNo);
+    }
+
+    private boolean guardedCurrentOwnerCheck(Integer deviceNo, Integer stationId, Integer taskNo) {
+        return !stateManager.isOccupiedByOtherLoadingTask(deviceNo, stationId, taskNo);
+    }
+
+    private boolean guardedMutateStationState(String operation, Integer deviceNo, Integer stationId, Integer taskNo,
+            Integer targetStationId, Runnable mutation) {
+        if (!guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedClearStationState(String operation, Integer deviceNo, Integer stationId, Integer taskNo,
+            Runnable mutation) {
+        if (!guardedStationClear(operation, taskNo, stationId, deviceNo)) {
+            return false;
+        }
+        mutation.run();
+        return true;
+    }
+
+    private boolean guardedArrivalCompletionState(Integer deviceNo, TaskRuntimeContext context) {
+        return guardedFinalArrivalState(deviceNo, context);
+    }
+
+    private boolean guardedWriteToStation(String operation, Integer deviceNo, Integer stationId, Integer taskNo, Integer targetStationId) {
+        return guardedStationWrite(operation, taskNo, stationId, deviceNo, targetStationId);
+    }
+
+    private boolean guardedClearFromStation(String operation, Integer deviceNo, Integer stationId, Integer taskNo) {
+        return guardedStationClear(operation, taskNo, stationId, deviceNo);
+    }
+
+    private void handleCommand(Integer deviceNo, StationCommand command) {
+        News.info("[WCS Debug] fake 闈濵OVE鍛戒护杩涘叆device涓茶鎵ц锛宒eviceNo={}锛宻tationId={}锛宼argetStaNo={}锛宑ommandType={}锛屽懡浠ゆ暟鎹�={}",
+                deviceNo, command.getStationId(), command.getTargetStaNo(), command.getCommandType(), JSON.toJSONString(command));
+        Integer taskNo = command.getTaskNo();
+        Integer stationId = command.getStationId();
+        Integer targetStationId = command.getTargetStaNo();
+
+        if (command.getCommandType() == StationCommandType.RESET) {
+            boolean reset = guardedResetStation(deviceNo, stationId, taskNo);
+            News.info("[WCS Debug] fake RESET宸查�氳繃缁熶竴绔欑偣閿佹墽琛岋紝deviceNo={}锛宻tationId={}锛宎ccepted={}", deviceNo, stationId, reset);
+            return;
+        }
+
+        if (command.getCommandType() == StationCommandType.WRITE_INFO) {
+            if (command.getBarcode() != null) {
+                boolean updated = guardedUpdateStationBarcode(deviceNo, stationId, taskNo, command.getBarcode());
+                News.info("[WCS Debug] fake WRITE_INFO鏉$爜鍐欏叆宸查�氳繃缁熶竴绔欑偣閿佹墽琛岋紝deviceNo={}锛宻tationId={}锛宐arcode={}锛宎ccepted={}",
+                        deviceNo, stationId, command.getBarcode(), updated);
                 return;
             }
-
-            ZyStationStatusEntity currentStatus = statusList.stream()
-                    .filter(item -> item.getStationId().equals(stationId)).findFirst().orElse(null);
-
-            if (currentStatus == null) {
+            if (taskNo == 9998 && targetStationId == 0) {
+                boolean generated = guardedGenerateFakeOutStationData(deviceNo, stationId, taskNo);
+                News.info("[WCS Debug] fake WRITE_INFO鏈夌墿鍐欏叆宸查�氳繃缁熶竴绔欑偣閿佹墽琛岋紝deviceNo={}锛宻tationId={}锛宎ccepted={}", deviceNo, stationId, generated);
                 return;
             }
+        }
 
-            if (currentStatus.isRunBlock()) {
-                currentStatus.setRunBlock(false);
-                News.info("[WCS Debug] 绔欑偣{}鍫靛鏍囪宸叉竻闄�", stationId);
-            }
-        } finally {
-            unlockStations(stationId);
+        if (taskNo != null && taskNo > 0 && taskNo != 9999 && taskNo != 9998 && stationId != null
+                && stationId.equals(targetStationId)) {
+            boolean handedOff = guardedHandoffBarcodeStation(deviceNo, taskNo, stationId, targetStationId);
+            News.info("[WCS Debug] fake 鏉$爜绔欎换鍔′氦鎺ュ畬鎴愶紝deviceNo={}锛宻tationId={}锛宼askNo={}锛宼argetStationId={}锛屽姩浣�=barcodeTaskHandoff锛宎ccepted={}",
+                    deviceNo, stationId, taskNo, targetStationId, handedOff);
         }
     }
 
     private boolean checkTaskNoInArea(Integer taskNo) {
+        if (taskNo == null || redisUtil == null) {
+            return false;
+        }
+
         Object fakeTaskNoAreaObj = redisUtil.get(RedisKeyType.FAKE_TASK_NO_AREA.key);
         if (fakeTaskNoAreaObj == null) {
             return false;
@@ -711,11 +1621,259 @@
         JSONObject data = JSON.parseObject(String.valueOf(fakeTaskNoAreaObj));
         Integer start = data.getInteger("start");
         Integer end = data.getInteger("end");
+        if (start == null || end == null) {
+            return false;
+        }
+        return taskNo >= start && taskNo <= end;
+    }
 
-        if (taskNo >= start && taskNo <= end) {
-            return true;
+    private Map<String, Object> buildDetails(Object... keyValues) {
+        Map<String, Object> details = new LinkedHashMap<String, Object>();
+        if (keyValues == null) {
+            return details;
+        }
+        for (int i = 0; i + 1 < keyValues.length; i += 2) {
+            Object key = keyValues[i];
+            if (key != null) {
+                details.put(String.valueOf(key), keyValues[i + 1]);
+            }
+        }
+        return details;
+    }
+
+    private void traceEvent(Integer deviceNo, TaskRuntimeContext context, String eventType, String message,
+            Map<String, Object> details, boolean terminal) {
+        if (context != null && context.deviceNo != null && deviceNo != null && !context.deviceNo.equals(deviceNo)) {
+            deviceNo = context.deviceNo;
+        }
+        if (context == null || context.taskNo == null) {
+            return;
+        }
+        Map<String, Object> safeDetails = details == null ? new LinkedHashMap<String, Object>() : new LinkedHashMap<String, Object>(details);
+        if (!safeDetails.containsKey("segmentNo") && context.segmentNo != null) {
+            safeDetails.put("segmentNo", context.segmentNo);
+        }
+        if (!safeDetails.containsKey("segmentCount") && context.segmentCount != null) {
+            safeDetails.put("segmentCount", context.segmentCount);
+        }
+        try {
+            FakeTaskTraceRegistry registry = com.core.common.SpringUtils.getBean(FakeTaskTraceRegistry.class);
+            if (registry != null) {
+                registry.record(context.taskNo, context.threadImpl != null ? context.threadImpl : stateManager.getThreadImpl(deviceNo),
+                        context.status, context.startStationId, context.currentStationId, context.finalTargetStationId,
+                        context.blockedStationId, context.getStitchedPathStationIds(), context.getPassedStationIds(),
+                        context.getPendingStationIds(), context.getLatestAppendedPath(), eventType, message, safeDetails,
+                        terminal);
+            }
+        } catch (Exception e) {
+            News.info("[WCS Debug] fake trace璁板綍澶辫触锛宼askNo={}锛宔ventType={}锛屽紓甯哥被鍨�={}锛屽紓甯镐俊鎭�={}",
+                    context.taskNo, eventType, e.getClass().getSimpleName(), e.getMessage());
+        }
+        News.info("[WCS Debug] fake task event锛宼askNo={}锛宔ventType={}锛宻tatus={}锛宑urrentStationId={}锛宼argetStationId={}锛宲ending={}锛宒etails={}",
+                context.taskNo, eventType, context.status, context.currentStationId, context.finalTargetStationId,
+                context.getPendingStationIds(), JSON.toJSONString(safeDetails));
+    }
+
+    private boolean isTerminalStatus(String status) {
+        return STATUS_CANCELLED.equals(status) || STATUS_TIMEOUT.equals(status)
+                || STATUS_FINISHED.equals(status);
+    }
+
+    private boolean isCurrentLoopGeneration(Integer taskNo, int loopGeneration) {
+        AtomicInteger generation = taskLoopGenerations.get(taskNo);
+        return generation != null && generation.get() == loopGeneration;
+    }
+
+    private Object getTaskLifecycleLock(Integer taskNo) {
+        return taskLifecycleLocks.computeIfAbsent(taskNo, key -> new Object());
+    }
+
+    /**
+     * 妫�鏌ュ爢鍨涙満鏄惁宸插彇璧版寚瀹氫换鍔$殑璐х墿
+     * 閫氳繃閬嶅巻鎵�鏈夊爢鍨涙満璁惧锛屾鏌ユ槸鍚︽湁鍫嗗灈鏈烘鍦ㄦ墽琛岃浠诲姟涓斿凡 loaded
+     */
+    private boolean isCrnTakenByTask(Integer taskNo) {
+        if (taskNo == null || taskNo <= 0) {
+            return false;
+        }
+        try {
+            com.zy.asrs.service.BasCrnpService basCrnpService = com.core.common.SpringUtils.getBean(com.zy.asrs.service.BasCrnpService.class);
+            List<com.zy.asrs.entity.BasCrnp> basCrnps = basCrnpService.list();
+            for (com.zy.asrs.entity.BasCrnp basCrnp : basCrnps) {
+                com.zy.core.thread.CrnThread ct = (com.zy.core.thread.CrnThread) com.zy.core.cache.SlaveConnection.get(
+                        com.zy.core.enums.SlaveType.Crn, basCrnp.getCrnNo());
+                if (ct == null) {
+                    continue;
+                }
+                com.zy.core.model.protocol.CrnProtocol protocol = ct.getStatus();
+                if (protocol != null && taskNo.equals(protocol.getTaskNo())
+                        && protocol.getLoaded() == 1) {
+                    return true;
+                }
+            }
+        } catch (Exception ignore) {
+        }
+        return false;
+    }
+
+
+    private static class MoveStepResult {
+
+        private final boolean shouldContinue;
+        private final long nextDelayMs;
+
+        private MoveStepResult(boolean shouldContinue, long nextDelayMs) {
+            this.shouldContinue = shouldContinue;
+            this.nextDelayMs = nextDelayMs;
         }
 
-        return false;
+        private static MoveStepResult continueNow() {
+            return new MoveStepResult(true, 0L);
+        }
+
+        private static MoveStepResult continueAfter(long nextDelayMs) {
+            return new MoveStepResult(true, nextDelayMs);
+        }
+
+        private boolean shouldContinue() {
+            return shouldContinue;
+        }
+
+        private long getNextDelayMs() {
+            return nextDelayMs;
+        }
+    }
+
+    private static class IdleStepResult {
+
+        private final boolean finished;
+        private final long nextDelayMs;
+
+        private IdleStepResult(boolean finished, long nextDelayMs) {
+            this.finished = finished;
+            this.nextDelayMs = nextDelayMs;
+        }
+
+        private static IdleStepResult finish() {
+            return new IdleStepResult(true, 0L);
+        }
+
+        private static IdleStepResult waitNext(long nextDelayMs) {
+            return new IdleStepResult(false, nextDelayMs);
+        }
+
+        private boolean isFinished() {
+            return finished;
+        }
+
+        private long getNextDelayMs() {
+            return nextDelayMs;
+        }
+    }
+
+    private static class TaskRuntimeContext {
+
+        private final Integer taskNo;
+        private final Integer deviceNo;
+        private final String threadImpl;
+        private final LinkedBlockingQueue<Integer> pendingPathQueue = new LinkedBlockingQueue<Integer>();
+        private final List<Integer> stitchedPathStationIds = new ArrayList<Integer>();
+        private final List<Integer> passedStationIds = new ArrayList<Integer>();
+        private final List<Integer> latestAppendedPath = new ArrayList<Integer>();
+
+        private Integer startStationId;
+        private Integer currentStationId;
+        private Integer finalTargetStationId;
+        private Integer blockedStationId;
+        private boolean generateBarcode;
+        private boolean initialized;
+        private boolean arrivalHandled;
+        private Integer segmentNo;
+        private Integer segmentCount;
+        private long lastStepAt = System.currentTimeMillis();
+        private long lastCommandAt = System.currentTimeMillis();
+        private long lastProgressAt = System.currentTimeMillis();
+        private Integer lastProgressStationId;
+        private int loopGeneration;
+        private String status = STATUS_WAITING;
+
+        private TaskRuntimeContext(Integer taskNo, Integer deviceNo, String threadImpl) {
+            this.taskNo = taskNo;
+            this.deviceNo = deviceNo;
+            this.threadImpl = threadImpl;
+        }
+
+        private void setStartStationIdIfAbsent(Integer stationId) {
+            if (startStationId == null && stationId != null) {
+                startStationId = stationId;
+            }
+        }
+
+        private void appendStitchedPath(List<Integer> path) {
+            latestAppendedPath.clear();
+            if (path == null) {
+                return;
+            }
+            for (Integer stationId : path) {
+                if (stationId == null) {
+                    continue;
+                }
+                latestAppendedPath.add(stationId);
+                if (stitchedPathStationIds.isEmpty()
+                        || !stationId.equals(stitchedPathStationIds.get(stitchedPathStationIds.size() - 1))) {
+                    stitchedPathStationIds.add(stationId);
+                }
+            }
+        }
+
+        private void replaceLatestPath(List<Integer> path) {
+            latestAppendedPath.clear();
+            if (path == null) {
+                return;
+            }
+            for (Integer stationId : path) {
+                if (stationId != null) {
+                    latestAppendedPath.add(stationId);
+                }
+            }
+        }
+
+        private void clearPendingPath() {
+            pendingPathQueue.clear();
+            latestAppendedPath.clear();
+        }
+
+        private void clearPendingPathWithLog(Integer deviceNo, Integer taskNo, Integer currentStationId,
+                Integer targetStationId, Integer blockedStationId, String reason) {
+            News.info("[WCS Debug] fake task娓呯┖寰呮墽琛岃矾寰勶紝鍘熷洜={}锛宒eviceNo={}锛宼askNo={}锛宑urrentStationId={}锛宼argetStationId={}锛宐lockedStationId={}锛宲endingBeforeClear={}",
+                    reason, deviceNo, taskNo, currentStationId, targetStationId, blockedStationId, getPendingStationIds());
+            clearPendingPath();
+        }
+
+        private void addPassedStation(Integer stationId) {
+            if (stationId == null) {
+                return;
+            }
+            if (passedStationIds.isEmpty()
+                    || !stationId.equals(passedStationIds.get(passedStationIds.size() - 1))) {
+                passedStationIds.add(stationId);
+            }
+        }
+
+        private List<Integer> getPendingStationIds() {
+            return new ArrayList<Integer>(pendingPathQueue);
+        }
+
+        private List<Integer> getPassedStationIds() {
+            return new ArrayList<Integer>(passedStationIds);
+        }
+
+        private List<Integer> getStitchedPathStationIds() {
+            return new ArrayList<Integer>(stitchedPathStationIds);
+        }
+
+        private List<Integer> getLatestAppendedPath() {
+            return new ArrayList<Integer>(latestAppendedPath);
+        }
     }
 }

--
Gitblit v1.9.1