粗排引擎 Functional Spec ⇄ 舊版 ScheduleEngine_wo 比對報告

產出日期:2026-06-08 比對對象 A(基準・預計更新版):functional-spec/rough-cut-scheduler.md(狀態:已簽核;2026-06-04 修正上游 JIT 拉動、廢棄 §RCS-FS-10) 比對對象 B(既有實作):Lean-Scheduling/src/main/java/com/thuai/smb/lean/module/ScheduleEngine_wo.java(2350 行) 輔助佐證:LatestStartCalculator.javaLatestStartResult.javaVSMUtil.javaStdScheduleKanbanSorter.java 性質:一次性比對作業(與 workflow 五階段鏈無關),不修改任何程式碼、不裁定


0. 一句話結論

舊版 ScheduleEngine_wo 是一支 細排粗排合一」的工單級排程引擎(以 scheduleParameter.isRoughSchedule() 切換模式);新 spec 描述的是一支 「純試算、投產單級、只產日期」的獨立粗排引擎。兩者定位不同

  • 方向一(spec 是否涵蓋舊版功能):spec 涵蓋了粗排該有的核心(LSD 反推、LeanPlay 節拍點錨定+有限產能堆疊、上游拉動/下游推動、空批次、交期早於今日),但有 2 處語意刻意改變(LeanPlay 改正推 ASAP 錨定、不再交期反推;引擎不判 overdue)與 1 處 spec 更嚴謹、舊版未實作§RCS-FS-1節拍點 fallback)。
  • 方向二(舊版是否多出未定義功能):舊版多出大量功能。其中一部分 spec 已明確聲明「不做/留下一期」(屬設計性排除,非缺口);另一部分 spec 完全未提及(多為「工單級/細排」機制),需團隊裁定要「捨棄、或標記為未來範圍」。

最該注意的 3 件事(詳見 §4):

  1. ❌ 舊版會判逾期並產生 ScheduleAlarm/拋例外,與 spec §RCS-FS-7「引擎不判 overdue」直接相反
  2. ❌ 舊版§RCS-FS-1 fallbackVSM 找不到節拍點時回傳 null,後續 NPE。
  3. ⚠️ 「投產順序」兩邊定義不同:spec=LeanPlay 完工日全域排序;舊版=可插拔 sorter 依「MTO/MTS→開工日→manualSeq」排。

1. 兩邊根本定位差異(先對齊框架,再逐項比)

面向新 Functional Spec舊版 ScheduleEngine_wo
引擎範圍獨立粗排引擎(細排的 input 之一)細排粗排合一,isRoughSchedule() 切換
處理顆粒投產單{poNo, product, qty, dueDate, prioritySeq}**工單(WorkOrder)**級,支援單投產單對多工單迭代
輸出模型每個 VSM 節點掛 {LSD, LeanPlay 交期, 投產順序}(純日期標記)KanBanProduce 生產看板 + KanBanMaterial 物料看板清單
產能語意純試算、不寫回/不鎖定實際消耗並 commit 產能表;非粗排模式另 saveSnapshot 落地
顆粒度到「天」到時間(時/分,含班制 WorkShift、時區位移)
到料/庫存不考慮(§RCS-FS-5,只保留「需要哪些料」)完整 WIP/庫存供需、未搓合工單搓合

因為定位不同,「舊版多很多功能」是預期內的——關鍵在於分辨哪些是 spec 刻意排除、哪些是 spec 漏掉而需補進範圍說明


2. 方向一:Spec 是否涵蓋舊版(粗排相關)功能?

逐項對照 spec 的 Use Case/邊界條件 vs 舊版實作。狀態:✅ 已涵蓋且一致/⚠️ 涵蓋但語意有差/❌ 未涵蓋或相反。

#Spec 項目舊版對應實作(檔:行)狀態說明
1LSD 反推§RCS-FS-13:自交期反推、純 leadtime、不看產能)LatestStartCalculator.calculateNodeRecursiveLatestStartCalculator.java:91-153),由 calculateLatestStart() 在排程後呼叫(ScheduleEngine_wo.java:2142-2174⚠️核心一致(交期為錨、往前反推、不消耗產能)。兩點差異:(a) 逾期時 LSD clamp 到 nowDtLatestStartCalculator.java:117-118),spec §RCS-FS-3 則是「保留過去值、視為無意義」;(b) leadtime除以開機數LatestStartCalculator.java:161-165),spec toy 假設單一資源、未涵蓋資源數對 LSD 的影響。
2LeanPlay:節拍點為錨§RCS-FS-11 正推定錨求最早可開工日 → 有限產能堆疊 → 節拍點往前 JIT 拉動上游、往後推動下游)schedule() 節拍點起排日計算(ScheduleEngine_wo.java:450-475)、有限產能 arrangeTimeWithProduceCapacity(:534)、pullScheduleProduceKanban(:850)、pushScheduleProduceKanban(:1435)⚠️結構對應(節拍點定錨→拉動/推動)。語意差異:spec 2026-06-04 已廢棄交期反推(§RCS-FS-10)改為自起排日正推 ASAP;舊版粗排模式仍保留「交期 JIT 反推」分支(:456-459STRATEGY_TAKT_STARTDATE_JIT)與「nowDt 正推 standardLeadTime」分支(:461-463)。即舊版的節拍點錨點來源與新 spec 不一致,需以 spec 為準重做。
3有限產能堆疊、不足往後一天§RCS-FS-2 排擠)arrangeTimeWithProduceCapacity 失敗→節拍點 +1 天(ScheduleEngine_wo.java:538-547機制一致。
4上游往前拉動 N-x(JIT、緊鄰、不留閒置)getPullNodeDt(最晚開工反推,:1371-1402)+ pullScheduleProduceKanban(:850)拉動以「緊鄰後站開工」反推,與 JIT 不留閒置一致。
5下游往後推動 N+ygetPushNodeDt(:1328-1369)+ pushScheduleProduceKanban(:1435)機制一致。
6節拍點隨排擠後移、上游整段隨之後移§RCS-FS-15節拍點 +1 天後重排上游(:656-664 整段重排)行為一致(上游隨節拍點重新拉動)。
7節拍點→以最後一站為節拍點§RCS-FS-1VSMUtil.getTaktPoint 找不到回傳 nullVSMUtil.java:43-50);ScheduleEngine_wo.java:398 取得後無 fallback,後續 taktPoint.dataBox/getArrangeKanBan 會 NPE舊版未實作 §RCS-FS-1。spec 此處比舊版嚴謹,屬新增需求。
8投產順序=LeanPlay 完工日全域排序、連續編號 1..NprocessAfterSchedule() 用可插拔 IScheduleKanbanSorterScheduleEngine_wo.java:841-845);預設 StdScheduleKanbanSorter 依「MTO/MTS → 開工日 expectStartTime → manualSeq → 成品階 → processSeq」排(StdScheduleKanbanSorter.java:20-35⚠️定義不同:spec 依「完工日」全域排序;舊版依「開工日 +業務分群(MTO/MTS、manualSeq)」。需釐清採哪個定義。
9空批次 → 回傳空、不報錯§RCS-FS-8schedule() 對空 productionOrderList 自然產生空輸出(:357 for-loop);但 inputCheck() 對缺 VSM/產能等會 inputCheckOK=false 直接不跑(:189-243⚠️「空投產單批次」可達成空輸出;但舊版的 inputCheck 是另一層前置擋門,對「空輸入」的容忍邊界與 spec B8「合法空輸入」略有出入,需確認。
10交期早於今日 → LeanPlay 落未來、LSD 落過去、引擎不判 overdue§RCS-FS-3LeanPlay:nowDt 夾住、不排到過去(:419-421, 469-474)✅;LSD:clamp 到 nowDtLatestStartCalculator.java:117-118)⚠️;overdue:見下列第 11 點 ❌⚠️LeanPlay 不落過去一致;LSD 落過去的處理不同(見第 1 點)。
11引擎只輸出日期、不比對交期、不判 overdue§RCS-FS-7舊版多處判逾期::530-531 log error、:688-690 setOverdue:772-776 拋「逾期」例外並 createScheduleAlarm:786-790 互動模式逾期停止與 spec 相反。舊版主動判逾期、產警報、甚至中斷;spec 明定引擎不判、交由下游。
12純試算、不寫回/鎖定產能(UC A1 預期結果)粗排模式跳過 saveSnapshot:765-767);但 arrangeTimeWithProduceCapacity 仍會消耗並 commitFinalProductivityCalculation(:700, :316-319)改寫記憶體產能表⚠️不落 DB 與「不寫回」精神相符;但引擎內部確實會佔用/commit 產能(為了多單排擠 §RCS-FS-2),是否算「鎖定」需與 spec 語意對齊。

方向一小結粗排核心骨架(節拍點錨定+有限產能堆疊+拉動/推動+LSD 反推)在舊版都找得到對應,spec 沒有「漏掉舊版既有的粗排能力」。但有 3 處需要對齊§RCS-FS-1 fallback(舊版缺)、§RCS-FS-7 不判 overdue(舊版相反)、LeanPlay 錨點來源(舊版仍用交期反推,spec 已改正推 ASAP),以及「投產順序」定義差異。


3. 方向二:舊版多出哪些 Spec 未定義的功能?

分三類。A 類=spec 明確排除(非缺口)B 類=spec 完全未提及(潛在缺口,需裁定)C 類=spec 有但舊版無(補記,與 §2 呼應)。

A 類:Spec 已明確聲明「不做/留下一期」——屬設計性排除

舊版功能證據(檔:行)Spec 對應排除依據
產銷協調互動入口/互動式模式(逾期單停止)isTurnOnInteractionMode:772-790概述「產銷協調互動入口明確不做、留下一期」;需求一覆蓋對照=「明確不做」
逾期判定/排程警報(ScheduleAlarm)AlarmMgr.createScheduleAlarmALARM_CODE_PO_SCHEDULE_OVERDUE:772-790§RCS-FS-7(引擎不判 overdue)
寫回/鎖定產能(Snapshot 落地)SnapshotDelegate.saveSnapshot:32-36, 765-767UC A1 預期結果「純試算、不寫回/鎖定」(§Q4 待裁定是否落地)
到料/WIP/庫存供需協調checkSupplyDemand(:2021)、updateOrderRequestQty(:1954)、getWIPSupply/getInventorySupply(:975-984)§RCS-FS-5(不考慮到料,只保留「需要哪些料」)
集批控制getArrangeKanBan 已被移除、恆回傳空(:2072-2074);getTaktTolerance 拆批(:548-571)§RCS-FS-14(集批不支援;LSD 給單一日期)

A 類重點:這些舊版有、spec 沒有,是故意的。報告只是把它們點名,確認「捨棄/延後」是有意識的決定。其中「集批」在舊版其實也已被拔成空殼(getArrangeKanBan 恆空),與 spec B14 方向一致。

B 類:Spec 完全未提及——潛在缺口,需團隊裁定(捨棄 or 標記未來範圍)

#舊版功能證據(檔:行)為何值得裁定
B1工單(WorkOrder)級處理:單投產單對多工單迭代、isCheckSupplyPlanFixedFinishDatetime 固定完工日:491-508, 590-606, 718-740, 937-947spec 只到「投產單+qty」。粗排是否需感知工單/固定完工日?
B2計畫性訂單/共用件合併:未搓合工單搓合、WorkOrderSupplySOURCE_PLANpartUnfinishedWoMap(:90-91, 949-1007)、:716-754, 1819-1900投產單共用件邏輯,spec 未涵蓋。
B3採購件直接出貨isDirectSalecreateShipMaterialKanbanForBuy(:386-393)採購件不走製程樹,spec 未提。
B4物料看板生成(pull/store/ship/buy material kanban)KanbanEngine_new 系列(:578, 1028, 1100-1101, 1607-1684)spec §RCS-FS-5 只要求保留「需要哪些料」,未要求產生各類物料看板。輸出模型差異核心。
B5移轉批量/拆批transferQmaxsplitProduceKanbansplitMaterialKanbanDateTolerance/TaktTolerance 容許天數getPushNodeDt(:1334-1357)、getPullNodeDt(:1379-1395)、:548-571, 1068-1073, 1242-1247比 spec 顆粒更細的批量控制,spec 未定義。
B6Lot 拆分assignLotsToKanbansisEnableLotSplitlotId、TRYMOLD 跳過:797-824, 2198-2348批次級拆分,spec 未涵蓋(spec 到「天」、到「節點」)。
B7瓶頸統計分析建議BottleneckStatEngine(:123, 179-181, 484-536)排單統計/瓶頸建議,spec 未提。
B8產能 Gap 掃描buildPoRecordGap/traverseAndGetGap/ScheduleGap(:1690-1775)不足量回報,spec 未提(spec 只輸出日期)。
B9加班/特殊加班overTimeMapsalesOrderOvertimeMapSalesOrderOvertimeConsume(:73-76, 296-298)spec §RCS-FS-9 只說 Freeze 在引擎外、引擎讀「可用產能」;加班設定屬產能組成細節,spec 未展開。
B10資源數計算策略/模治具限制ResourcePlanCalculatorResourcePlanStrategymaxResourceQtyMapmoldFixtureConstraintMap(:99-110, 2151-2159)開機數會影響 leadtime(連帶影響 LSD);spec toy 假設單一資源、未定義資源數規劃。
B11齊料拉動(forerunner / kit pull)expectCompleteKitDtLongoidForerunnerFinishDtisForerunner(:367-384, 442-448, 712-714)跨單齊料同步,spec 未涵蓋。
B12中斷機制/進度回報interrupt(:246-248, 360-363)、getProgress(:250-255)執行控制,spec 未提(屬非功能性)。
B13時區位移zoneOffsetHoursprocessAfterSchedule :826-834)spec 到「天」、未談時區;若粗排也需跨時區,需補。

B 類重點:B1~B6、B11 多屬**細排/工單級機制,落在粗排投產單級、純試算」定位之外——可能本就該排除,但 spec 目前沒有白紙黑字說明**,建議在 spec 的「範圍說明/待裁定」補一句,避免日後誤判為「漏做」。B9/B10 與 spec 的「可用產能leadtime間接相關,最需要釐清是否納入。

C 類:Spec 有、舊版無(與 §2 呼應,反向補記)

項目說明
§RCS-FS-1節拍點 fallback(以最後一站為節拍點舊版 getTaktPoint 回 null、無 fallback(會 NPE)。spec 較嚴謹。
§RCS-FS-7 明確「引擎不判 overdue」舊版相反(會判逾期+產警報)。spec 為刻意收斂。
LeanPlay 自起排日正推 ASAP 錨定(§RCS-FS-11,廢棄交期反推 §RCS-FS-10)舊版粗排仍用「交期 JIT 反推」或「nowDt 正推 standardLeadTime」分支,與 spec 新定義不一致。

4. 給人裁定的重點清單(依優先序)

  1. §RCS-FS-7 vs 舊版逾期判定(衝突):spec 要引擎「只給日期、不判 overdue」,舊版會判逾期、產 ScheduleAlarm、互動模式還會中斷。實作新粗排時須移除逾期判定與警報,逾期比對交下游。
  2. §RCS-FS-1 fallback(舊版缺):新引擎須補「無節拍點→以最後一站為節拍點」,避免舊版的 null/NPE 路徑。
  3. LeanPlay 錨點來源(語意已改):採 spec §RCS-FS-11 正推 ASAP 定錨,不可沿用舊版的交期反推(STRATEGY_TAKT_STARTDATE_JIT)。
  4. 「投產順序」定義(不一致):確認採 spec 的「LeanPlay 完工日全域排序」,而非舊版 sorter 的「開工日+MTO/MTS+manualSeq」。
  5. LSD 細節對齊:(a) 逾期時 LSD 要「保留過去值」(spec §RCS-FS-3) 還是「clamp 到 nowDt」(舊版)?(b) LSDleadtime 是否要納入「開機數除 CT/CO」(舊版有、spec toy 無)?
  6. B 類功能範圍宣告:對 B1~B13 各項,明確標記「本期捨棄」或「未來範圍」,補進 spec 的範圍/待裁定段,使「不做」是有意識的決定而非遺漏。其中 B9(加班)、B10(資源數/模治具) 與「可用產能leadtime」直接相關,最需先決定是否納入。

附錄:關鍵證據索引

  • LSD最晚開工日)計算:LatestStartCalculator.java:74-202;逾期 clamp :117-118;資源數除 CT/CO :161-165;填回看板 :207-218
  • LeanPlay 節拍點起排日策略:ScheduleEngine_wo.java:450-475(rough+JIT 交期反推 :456-459;nowDt 正推 :461-463
  • 有限產能堆疊/排擠 +1 天:ScheduleEngine_wo.java:534-547
  • 上游拉動:pullScheduleProduceKanban :850-1326getPullNodeDt :1371-1402
  • 下游推動:pushScheduleProduceKanban :1435-1688getPushNodeDt :1328-1369
  • 逾期判定/警報::530-531, 688-690, 769-790
  • Snapshot 寫回(粗排跳過)::32-36, 765-767
  • WIP/庫存供需:checkSupplyDemand :2021-2040updateOrderRequestQty :1954-2009
  • 集批已拔成空殼:getArrangeKanBan :2072-2074
  • Lot 拆分:assignLotsToKanbans :2198-2348
  • 投產順序 sorter:ScheduleEngine_wo.java:841-845StdScheduleKanbanSorter.java:20-35
  • 節拍點查找(無 fallback):VSMUtil.java:43-50;呼叫點 ScheduleEngine_wo.java:398