poi-plugin-remodel-assistant 1.2.5-beta.2 → 1.2.6-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/assets/main.css CHANGED
@@ -10955,67 +10955,118 @@ body.decision-modal-is-dragging * {
10955
10955
  text-overflow: ellipsis;
10956
10956
  }
10957
10957
 
10958
- /* Current improvement identity stays beside the large equipment artwork. All
10959
- * plan references are a separate scan block with deliberate horizontal air. */
10958
+ /* Current improvement identity stays beside the large equipment artwork.
10959
+ * Header tools own a stable top-right column, while plan references may grow
10960
+ * vertically without pushing the tools onto a later flex line. */
10960
10961
  #item-improvement .decision-detail-header {
10961
- flex-wrap: wrap;
10962
+ display: grid;
10963
+ grid-template-columns: auto minmax(0, 1fr) max-content;
10964
+ grid-template-areas: "artwork heading tools";
10965
+ align-items: start;
10962
10966
  gap: 12px;
10963
10967
  }
10964
10968
 
10969
+ #item-improvement .decision-detail-header.has-related-plans {
10970
+ grid-template-columns: auto minmax(180px, 0.9fr) minmax(180px, 1.1fr) max-content;
10971
+ grid-template-areas: "artwork heading related tools";
10972
+ }
10973
+
10974
+ #item-improvement .decision-detail-artwork {
10975
+ grid-area: artwork;
10976
+ margin-right: 0;
10977
+ }
10978
+
10965
10979
  #item-improvement .decision-detail-heading-copy {
10966
- flex: 0 1 auto;
10980
+ grid-area: heading;
10981
+ min-width: 0;
10982
+ }
10983
+
10984
+
10985
+ #item-improvement .decision-detail-show-parent-plans {
10986
+ display: inline-flex;
10987
+ align-items: center;
10988
+ gap: 5px;
10989
+ margin: 0;
10990
+ font-size: var(--improvement-font-small);
10991
+ font-weight: 600;
10992
+ cursor: pointer;
10993
+ }
10994
+
10995
+ #item-improvement .decision-detail-show-parent-plans input {
10996
+ margin: 0;
10967
10997
  }
10968
10998
 
10969
10999
  #item-improvement .decision-detail-related-plans {
10970
11000
  display: grid;
10971
- flex: 0 1 auto;
10972
- gap: 6px;
10973
- min-width: 140px;
10974
- margin-left: 28px;
11001
+ grid-area: related;
11002
+ gap: 7px;
11003
+ min-width: 180px;
11004
+ margin-left: 16px;
10975
11005
  }
10976
11006
 
10977
- #item-improvement .decision-detail-related-plans-label {
10978
- color: #8fa8b4;
10979
- font-size: var(--improvement-font-small);
11007
+ #item-improvement .decision-detail-related-plan-group {
11008
+ display: grid;
11009
+ gap: 5px;
11010
+ }
11011
+
11012
+ #item-improvement .decision-detail-related-plan-group-label {
11013
+ width: fit-content;
11014
+ padding: 1px 7px;
11015
+ border-radius: 999px;
11016
+ background: rgba(103, 198, 193, 0.09);
11017
+ color: #67c6c1;
11018
+ font-size: var(--improvement-font-caption);
10980
11019
  font-weight: 700;
11020
+ line-height: 1.55;
10981
11021
  }
10982
11022
 
10983
11023
  #item-improvement .decision-detail-related-plan-list {
10984
11024
  display: flex;
10985
11025
  flex-wrap: wrap;
10986
- gap: 6px;
11026
+ align-items: flex-start;
11027
+ gap: 7px 8px;
10987
11028
  }
10988
11029
 
10989
11030
  #item-improvement .decision-detail-related-plan {
10990
11031
  display: inline-flex;
10991
11032
  align-items: baseline;
10992
11033
  gap: 5px;
10993
- padding: 3px 7px;
11034
+ padding: 5px 9px;
10994
11035
  border-radius: 999px;
10995
11036
  background: rgba(127, 127, 127, 0.09);
10996
11037
  white-space: nowrap;
10997
11038
  }
10998
11039
 
10999
- #item-improvement .decision-detail-related-plan em {
11000
- color: #67c6c1;
11001
- font-size: var(--improvement-font-caption);
11002
- font-style: normal;
11040
+ #item-improvement .decision-detail-related-plan strong {
11041
+ font-size: var(--improvement-font-body-large);
11003
11042
  font-weight: 700;
11004
11043
  }
11005
11044
 
11006
- #item-improvement .decision-detail-related-plan-parent {
11007
- color: #a9b7bf;
11008
- font-size: var(--improvement-font-small);
11009
- font-weight: 600;
11045
+ #item-improvement .decision-detail-related-plan.is-consumable {
11046
+ background: rgba(69, 169, 165, 0.1);
11010
11047
  }
11011
11048
 
11012
- #item-improvement .decision-detail-related-plan strong {
11013
- font-size: var(--improvement-font-small);
11014
- font-weight: 700;
11049
+ #item-improvement .decision-detail-consumable-plan-reference {
11050
+ display: grid;
11051
+ align-content: start;
11052
+ gap: 3px;
11053
+ min-width: max-content;
11015
11054
  }
11016
11055
 
11017
- #item-improvement .decision-detail-related-plan.is-consumable {
11018
- background: rgba(69, 169, 165, 0.1);
11056
+ #item-improvement .decision-detail-consumable-plan-reference .decision-detail-related-plan-parent {
11057
+ display: flex;
11058
+ align-items: center;
11059
+ gap: 5px;
11060
+ padding-left: 8px;
11061
+ color: #c8d2d7;
11062
+ font-size: var(--improvement-font-body);
11063
+ font-weight: 650;
11064
+ white-space: nowrap;
11065
+ }
11066
+
11067
+ #item-improvement .decision-detail-related-plan-parent-arrow {
11068
+ color: #67c6c1;
11069
+ font-weight: 700;
11019
11070
  }
11020
11071
 
11021
11072
  @media (max-width: 760px) {
@@ -11462,17 +11513,28 @@ body.decision-modal-is-dragging * {
11462
11513
  /* Page-specific detail-section manager. */
11463
11514
  #item-improvement .decision-detail-panel-tools {
11464
11515
  display: flex;
11465
- flex: 0 0 auto;
11466
- align-self: flex-start;
11516
+ grid-area: tools;
11517
+ align-items: center;
11518
+ align-self: start;
11467
11519
  justify-content: flex-end;
11468
- margin-left: auto;
11520
+ gap: 10px;
11521
+ margin-left: 0;
11522
+ white-space: nowrap;
11469
11523
  }
11470
11524
 
11471
- /* Keep the manager as the last flex item in the detail header. This makes
11472
- * auto margin resolve against the real right edge even when Related Plans
11473
- * wraps differently across Poi/Electron machines. */
11474
- #item-improvement .decision-detail-header > .decision-detail-panel-tools {
11475
- order: 99;
11525
+ /* On narrow detail panes the plan groups may move below the identity, but the
11526
+ * parent-plan switch and detail manager stay pinned to the top-right cell. */
11527
+ @media (max-width: 900px) {
11528
+ #item-improvement .decision-detail-header.has-related-plans {
11529
+ grid-template-columns: auto minmax(0, 1fr) max-content;
11530
+ grid-template-areas:
11531
+ "artwork heading tools"
11532
+ "artwork related related";
11533
+ }
11534
+
11535
+ #item-improvement .decision-detail-related-plans {
11536
+ margin-left: 0;
11537
+ }
11476
11538
  }
11477
11539
 
11478
11540
  #item-improvement .decision-detail-layout-manager-button {
@@ -1,6 +1,14 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "entries": [
4
+ {
5
+ "version": "1.2.6",
6
+ "items": [
7
+ "changelog_1_2_6_1",
8
+ "changelog_1_2_6_2",
9
+ "changelog_1_2_6_3"
10
+ ]
11
+ },
4
12
  {
5
13
  "version": "1.2.5",
6
14
  "items": [
package/i18n/en-US.json CHANGED
@@ -905,8 +905,11 @@
905
905
  "shared.Corresponding plan target": "Corresponding Plan target",
906
906
  "shared.Current plan target": "Plan target",
907
907
  "shared.For plan": "for",
908
+ "shared.Parent plan": "Parent plan",
908
909
  "shared.Related plans": "Related plans",
909
910
  "shared.Consumable plan": "Consumable plan",
911
+ "shared.User plans": "User plans",
912
+ "shared.Consumable plans": "Consumable plans",
910
913
  "workbench.Plan targets": "Plan targets",
911
914
  "workbench.Plan targets available for improvement on selected day": "Today improvable",
912
915
  "workbench.No plan target is available for improvement on selected day": "No unfinished Plan target needs action on the selected day",
@@ -1592,5 +1595,9 @@
1592
1595
  "app.changelog_1_2_5_7": "Fixed several interface and data-handling issues.",
1593
1596
  "data.Backup summary %p plans %r routes %l low priority": "%p plans · %r routes · %l low-priority equipment",
1594
1597
  "equipment.Search equipment name": "Search equipment name",
1595
- "workbench.Search equipment name": "Search equipment name"
1598
+ "workbench.Search equipment name": "Search equipment name",
1599
+ "app.changelog_1_2_6_1": "Optimized plan calculation and startup flow to reduce redundant work on local changes and make the interface available sooner after startup.",
1600
+ "app.changelog_1_2_6_2": "Fixed cases where user Plans and consumable Plans were handled together, improving consistency in Plan counts, equipment allocation, and diagnostics.",
1601
+ "shared.Show parent plans": "Show parent plans",
1602
+ "app.changelog_1_2_6_3": "Improved related-Plan and consumable-Plan details with unified target buttons and clearer parent-Plan relationships for better readability."
1596
1603
  }
package/i18n/ja-JP.json CHANGED
@@ -1344,6 +1344,8 @@
1344
1344
  "shared.Comfortable density": "ゆったり",
1345
1345
  "shared.Compact density": "コンパクト",
1346
1346
  "shared.Consumable plan": "消耗材計画",
1347
+ "shared.User plans": "ユーザー計画",
1348
+ "shared.Consumable plans": "消耗材計画",
1347
1349
  "shared.Corresponding plan target": "対応する計画目標",
1348
1350
  "shared.Current improvement starting point": "現在の改修開始点",
1349
1351
  "shared.Current plan target": "現在の計画目標",
@@ -1353,6 +1355,7 @@
1353
1355
  "shared.Equipment category filter": "装備カテゴリ絞り込み",
1354
1356
  "shared.Expanded": "展開",
1355
1357
  "shared.For plan": "使用先",
1358
+ "shared.Parent plan": "親計画",
1356
1359
  "shared.Improvement starting point": "改修開始点",
1357
1360
  "shared.Interface density": "表示密度",
1358
1361
  "shared.Move down": "下へ",
@@ -1592,5 +1595,9 @@
1592
1595
  "app.changelog_1_2_5_7": "一部の画面表示とデータ処理の問題を修正しました。",
1593
1596
  "data.Backup summary %p plans %r routes %l low priority": "プラン %p · ルート %r · 低優先装備 %l",
1594
1597
  "equipment.Search equipment name": "装備名を検索",
1595
- "workbench.Search equipment name": "装備名を検索"
1598
+ "workbench.Search equipment name": "装備名を検索",
1599
+ "app.changelog_1_2_6_1": "計画計算と起動処理を最適化し、局所的な変更時の重複計算を減らして、起動後に画面をより早く利用できるようにしました。",
1600
+ "app.changelog_1_2_6_2": "一部の状況でユーザー計画と消耗品計画が混在して処理される問題を修正し、計画数・装備割り当て・異常検出の整合性を改善しました。",
1601
+ "shared.Show parent plans": "親計画を表示",
1602
+ "app.changelog_1_2_6_3": "関連計画と消耗品計画の詳細表示を改善し、計画目標ボタンを統一するとともに親計画との関係を明確化して、可読性を高めました。"
1596
1603
  }
package/i18n/zh-CN.json CHANGED
@@ -905,8 +905,11 @@
905
905
  "shared.Corresponding plan target": "对应计划目标",
906
906
  "shared.Current plan target": "当前计划目标",
907
907
  "shared.For plan": "用于",
908
+ "shared.Parent plan": "父计划",
908
909
  "shared.Related plans": "相关计划",
909
910
  "shared.Consumable plan": "耗材计划",
911
+ "shared.User plans": "用户计划",
912
+ "shared.Consumable plans": "耗材计划",
910
913
  "workbench.Plan targets": "计划目标",
911
914
  "workbench.Plan targets available for improvement on selected day": "今日可改",
912
915
  "workbench.No plan target is available for improvement on selected day": "当天没有需要处理的未完成计划目标",
@@ -1592,5 +1595,9 @@
1592
1595
  "app.changelog_1_2_5_7": "修复部分界面与数据处理问题。",
1593
1596
  "data.Backup summary %p plans %r routes %l low priority": "计划 %p · 路线 %r · 低优先装备 %l",
1594
1597
  "equipment.Search equipment name": "搜索装备名称",
1595
- "workbench.Search equipment name": "搜索装备名称"
1598
+ "workbench.Search equipment name": "搜索装备名称",
1599
+ "app.changelog_1_2_6_1": "优化计划计算与启动流程,减少局部变化时的重复计算,并加快启动后的界面可用速度。",
1600
+ "app.changelog_1_2_6_2": "修复用户计划与耗材计划在部分情况下混合处理的问题,改善计划数量、装备分配与异常检测的一致性。",
1601
+ "shared.Show parent plans": "显示父计划",
1602
+ "app.changelog_1_2_6_3": "优化相关计划与耗材计划详情显示,统一计划目标按钮,并补充父计划关系,提升信息可读性。"
1596
1603
  }
package/i18n/zh-TW.json CHANGED
@@ -1344,6 +1344,8 @@
1344
1344
  "shared.Comfortable density": "寬鬆",
1345
1345
  "shared.Compact density": "緊湊",
1346
1346
  "shared.Consumable plan": "耗材計畫",
1347
+ "shared.User plans": "使用者計畫",
1348
+ "shared.Consumable plans": "耗材計畫",
1347
1349
  "shared.Corresponding plan target": "對應計畫目標",
1348
1350
  "shared.Current improvement starting point": "目前改修起點",
1349
1351
  "shared.Current plan target": "目前計畫目標",
@@ -1353,6 +1355,7 @@
1353
1355
  "shared.Equipment category filter": "裝備分類篩選",
1354
1356
  "shared.Expanded": "已展開",
1355
1357
  "shared.For plan": "用於",
1358
+ "shared.Parent plan": "父計畫",
1356
1359
  "shared.Improvement starting point": "改修起點",
1357
1360
  "shared.Interface density": "介面密度",
1358
1361
  "shared.Move down": "下移",
@@ -1592,5 +1595,9 @@
1592
1595
  "app.changelog_1_2_5_7": "修復部分介面與資料處理問題。",
1593
1596
  "data.Backup summary %p plans %r routes %l low priority": "計畫 %p · 路線 %r · 低優先裝備 %l",
1594
1597
  "equipment.Search equipment name": "搜尋裝備名稱",
1595
- "workbench.Search equipment name": "搜尋裝備名稱"
1598
+ "workbench.Search equipment name": "搜尋裝備名稱",
1599
+ "app.changelog_1_2_6_1": "最佳化計畫計算與啟動流程,減少局部變化時的重複計算,並加快啟動後的介面可用速度。",
1600
+ "app.changelog_1_2_6_2": "修復使用者計畫與耗材計畫在部分情況下混合處理的問題,改善計畫數量、裝備分配與異常檢測的一致性。",
1601
+ "shared.Show parent plans": "顯示父計畫",
1602
+ "app.changelog_1_2_6_3": "最佳化相關計畫與耗材計畫詳情顯示,統一計畫目標按鈕,並補充父計畫關係,提升資訊可讀性。"
1596
1603
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poi-plugin-remodel-assistant",
3
- "version": "1.2.5-beta.2",
3
+ "version": "1.2.6-beta.1",
4
4
  "description": "View enhanced KanColle improvement data, manage improvement plans, and receive improvement recommendations.",
5
5
  "main": "index.js",
6
6
  "author": {
@@ -9,7 +9,7 @@ var _equipmentBlacklistDomain = require("../equipment/domain/equipment-blacklist
9
9
 
10
10
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
11
11
 
12
- const SNAPSHOT_INPUT_KEYS = ['dataRevision', 'dataIdentity', 'plans', 'initialDay', 'masterEquips', 'masterUseitems', 'equipTypes', 'staticItems', 'actualEquipLevels', 'actualEquipInventory', 'actualUseitems', 'actualResourceBudget', 'equipmentRealityReady', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'currentInventoryBindings', 'equipmentBlacklist', 'routeAcquisitionIndex'];
12
+ const SNAPSHOT_INPUT_KEYS = ['dataRevision', 'dataIdentity', 'plans', 'initialDay', 'masterEquips', 'masterUseitems', 'equipTypes', 'staticItems', 'actualEquipLevels', 'actualEquipInventory', 'actualUseitems', 'actualResourceBudget', 'equipmentRealityReady', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'currentInventoryBindings', 'currentInventoryBindingOwnerRefs', 'equipmentBlacklist', 'routeAcquisitionIndex'];
13
13
  exports.SNAPSHOT_INPUT_KEYS = SNAPSHOT_INPUT_KEYS;
14
14
  const SNAPSHOT_FEEDBACK_CONTEXT_KEYS = SNAPSHOT_INPUT_KEYS.filter(key => key !== 'currentInventoryBindings');
15
15
  exports.SNAPSHOT_FEEDBACK_CONTEXT_KEYS = SNAPSHOT_FEEDBACK_CONTEXT_KEYS;
@@ -63,7 +63,7 @@ const stableSignature = value => JSON.stringify(stableValue(value || {})); // `m
63
63
  // cheap secondary guard for unexpected replacement under the same data identity.
64
64
 
65
65
 
66
- const CONTENT_IDENTITY_KEYS = new Set(['plans', 'actualEquipLevels', 'actualEquipInventory', 'actualUseitems', 'actualResourceBudget', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'currentInventoryBindings']); // `routeAcquisitionIndex` is a large selector-derived static projection. It
66
+ const CONTENT_IDENTITY_KEYS = new Set(['plans', 'actualEquipLevels', 'actualEquipInventory', 'actualUseitems', 'actualResourceBudget', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'currentInventoryBindings', 'currentInventoryBindingOwnerRefs']); // `routeAcquisitionIndex` is a large selector-derived static projection. It
67
67
  // still needs semantic equality so a reconstructed-but-equivalent generation
68
68
  // can reuse the completed Snapshot, but repeatedly sorting/stringifying the
69
69
  // same nested object on every React update makes Plan edits unnecessarily slow.
@@ -13,6 +13,8 @@ var _consumablePlanDomain = require("../plan/domain/consumable-plan-domain");
13
13
 
14
14
  var _currentStartAssignmentDomain = require("../plan/domain/current-start-assignment-domain");
15
15
 
16
+ var _allocationOwnerDomain = require("../plan/domain/allocation-owner-domain");
17
+
16
18
  var _improvementPlanDomain = require("../plan/domain/improvement-plan-domain");
17
19
 
18
20
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -37,18 +39,35 @@ const prefixedProfile = (profile, prefix) => typeof profile === 'function' ? (ev
37
39
  // - composition:只提供 Derived Consumable 展示元数据。
38
40
 
39
41
 
42
+ const attachUserPlanAuthorityProjection = (items, userItems) => {
43
+ const userById = new Map((userItems || []).map(item => [Number(item && item.id), item]));
44
+ return (items || []).map(item => {
45
+ const userItem = userById.get(Number(item && item.id)) || null;
46
+ if (!userItem) return item;
47
+ return _extends({}, item, {
48
+ userPlanAuthorityProjection: {
49
+ planState: userItem.planState || null,
50
+ planRouteEntries: Array.isArray(userItem.planRouteEntries) ? userItem.planRouteEntries : [],
51
+ routePlanning: userItem.routePlanning || null
52
+ }
53
+ });
54
+ });
55
+ };
56
+
40
57
  const publishDecisionSnapshot = ({
41
58
  userAllocation,
42
59
  consumableAllocation,
43
60
  composition,
61
+ userPlans = {},
62
+ bindingTransferTransitions = [],
44
63
  useitems = {},
45
64
  resourceBudget = {}
46
65
  }) => {
47
66
  const effective = consumableAllocation;
48
- const decoratedItems = (0, _consumablePlanDomain.decorateConsumablePlanEntries)({
67
+ const decoratedItems = attachUserPlanAuthorityProjection((0, _consumablePlanDomain.decorateConsumablePlanEntries)({
49
68
  items: effective.items,
50
69
  metadataByEquipmentId: composition.metadataByEquipmentId
51
- });
70
+ }), userAllocation && userAllocation.items || []);
52
71
  const items = (0, _improvementPlanDomain.materializeEquipmentDetailResolutions)({
53
72
  items: decoratedItems,
54
73
  equipLevels: effective.effectiveEquipLevels,
@@ -59,6 +78,10 @@ const publishDecisionSnapshot = ({
59
78
  items: effective.workbenchItems,
60
79
  metadataByEquipmentId: composition.metadataByEquipmentId
61
80
  });
81
+ const liveAllocationOwners = (0, _allocationOwnerDomain.buildLiveAllocationOwnerSet)({
82
+ userPlans,
83
+ consumableMetadataByEquipmentId: composition.metadataByEquipmentId
84
+ });
62
85
  const snapshot = {
63
86
  effectiveEquipLevels: effective.effectiveEquipLevels,
64
87
  effectiveUseitems: useitems,
@@ -67,9 +90,10 @@ const publishDecisionSnapshot = ({
67
90
  items,
68
91
  workbenchItems,
69
92
  chainItems: effective.chainItems || [],
93
+ liveAllocationOwners,
70
94
  retainedBindingCurrentIds: effective.retainedBindingCurrentIds || [],
71
95
  assignmentPersistenceBindings: effective.assignmentPersistenceBindings || effective.currentInventoryBindings || {},
72
- assignmentBindingTransitions: [...(userAllocation && userAllocation.assignmentBindingTransitions || []), ...(effective.assignmentBindingTransitions || [])],
96
+ assignmentBindingTransitions: [...(userAllocation && userAllocation.assignmentBindingTransitions || []), ...(bindingTransferTransitions || []), ...(effective.assignmentBindingTransitions || [])],
73
97
  // invariant findings 读取最终阶段即可;它不是阶段历史,不做重复累积。
74
98
  assignmentFindings: effective.assignmentFindings || [],
75
99
  assignmentDiagnostics: [...(userAllocation && userAllocation.assignmentDiagnostics || []), ...(effective.assignmentDiagnostics || [])]
@@ -230,10 +254,15 @@ const allocationStageProjection = (result, allocationScope) => ({
230
254
 
231
255
  const buildFullDecisionSnapshotPayload = input => {
232
256
  const job = input || {};
257
+ const userLiveOwners = (0, _allocationOwnerDomain.buildLiveAllocationOwnerSet)({
258
+ userPlans: job.plans || {}
259
+ });
260
+ const baseRouteSelections = (0, _allocationOwnerDomain.filterRouteSelectionsForLiveAllocationOwners)(job.planRouteSelections || {}, userLiveOwners);
233
261
  const baseBindings = (0, _currentStartAssignmentDomain.filterCurrentInventoryBindingsForPlanSpace)(job.plans || {}, job.currentInventoryBindings || {}); // Phase 1: UserAllocation(用户计划主件分配). All eligible User Plan
234
262
  // main-equipment Bindings are established before Consumable demand derivation.
235
263
 
236
264
  const base = (0, _decisionSnapshotDomain.buildFullDecisionSnapshotCore)(_extends({}, job, {
265
+ planRouteSelections: baseRouteSelections,
237
266
  currentInventoryBindings: baseBindings,
238
267
  allocationScope: 'user'
239
268
  }));
@@ -246,24 +275,63 @@ const buildFullDecisionSnapshotPayload = input => {
246
275
  // whole User owner set. Derived Consumable demand is computed only after it.
247
276
  // UserBindingPhaseBoundary(用户绑定阶段边界).
248
277
 
249
- const demands = (0, _consumablePlanDomain.collectConsumablePlanDemands)(base.workbenchItems);
278
+ const requirements = (0, _consumablePlanDomain.collectConsumableRequirements)(base.workbenchItems);
279
+ observeAllocationStage(job, 'ConsumableRequirementDiscovery', {
280
+ mode: 'full',
281
+ requirements,
282
+ requirementCount: requirements.length
283
+ });
284
+ const requirementCoverage = (0, _consumablePlanDomain.computeConsumableRequirementCoverage)(requirements, base.workbenchItems);
285
+ observeAllocationStage(job, 'ConsumableCoverage', {
286
+ mode: 'full',
287
+ requirements,
288
+ requirementCoverage,
289
+ userBindings: base.currentInventoryBindings || {}
290
+ });
291
+ const demands = (0, _consumablePlanDomain.deriveConsumableAcquisitionTasks)(requirements, requirementCoverage);
292
+ observeAllocationStage(job, 'ConsumableAcquisitionDerivation', {
293
+ mode: 'full',
294
+ requirements,
295
+ requirementCoverage,
296
+ demands,
297
+ requirementCount: requirements.length,
298
+ demandCount: demands.length
299
+ });
250
300
  const composition = demands.length > 0 ? (0, _consumablePlanDomain.composeConsumablePlansAfter)(job.plans || {}, demands) : {
251
301
  plans: job.plans || {},
252
302
  demands: [],
253
303
  metadataByEquipmentId: {}
254
304
  };
255
- observeAllocationStage(job, 'ConsumableDerivation', {
305
+ observeAllocationStage(job, 'ConsumableAcquisitionUnitExpansion', {
256
306
  mode: 'full',
257
- allocationScope: 'user',
258
307
  demands: composition.demands || demands,
259
- demandCount: demands.length,
260
- userBindings: base.currentInventoryBindings || {}
308
+ metadataByEquipmentId: composition.metadataByEquipmentId || {}
309
+ });
310
+ const effectiveLiveOwners = (0, _allocationOwnerDomain.buildLiveAllocationOwnerSet)({
311
+ userPlans: job.plans || {},
312
+ consumableMetadataByEquipmentId: composition.metadataByEquipmentId
261
313
  });
262
- const effectiveBindings = (0, _currentStartAssignmentDomain.filterCurrentInventoryBindingsForPlanSpace)(composition.plans, _extends({}, job.currentInventoryBindings || {}, base.currentInventoryBindings || {})); // Phase 2: ConsumableAllocation(耗材计划分配). Existing User Bindings
314
+ observeAllocationStage(job, 'LiveOwnerSpace', {
315
+ mode: 'full',
316
+ liveAllocationOwners: effectiveLiveOwners
317
+ });
318
+ const effectiveRouteSelections = (0, _allocationOwnerDomain.filterRouteSelectionsForLiveAllocationOwners)(job.planRouteSelections || {}, effectiveLiveOwners);
319
+ const bindingTransfer = (0, _currentStartAssignmentDomain.transferBindingsAfterUserAllocation)({
320
+ previousBindings: job.currentInventoryBindings || {},
321
+ userPlanBindingsBeforeAllocation: baseBindings,
322
+ frozenUserBindings: base.currentInventoryBindings || {}
323
+ });
324
+ const remappedTransferredBindings = (0, _allocationOwnerDomain.remapAllocationBindingsForLiveOwners)({
325
+ bindings: bindingTransfer.bindings,
326
+ ownerRefsByTransport: job.currentInventoryBindingOwnerRefs || {},
327
+ owners: effectiveLiveOwners
328
+ });
329
+ const effectiveBindings = (0, _currentStartAssignmentDomain.filterCurrentInventoryBindingsForPlanSpace)(composition.plans, remappedTransferredBindings); // Phase 2: ConsumableAllocation(耗材计划分配). Existing User Bindings
263
330
  // are retained; only Derived Consumable demands may materialize new Bindings.
264
331
 
265
332
  const effective = (0, _decisionSnapshotDomain.buildFullDecisionSnapshotCore)(_extends({}, job, {
266
333
  plans: composition.plans,
334
+ planRouteSelections: effectiveRouteSelections,
267
335
  currentInventoryBindings: effectiveBindings,
268
336
  allocationScope: 'consumable'
269
337
  }));
@@ -274,6 +342,8 @@ const buildFullDecisionSnapshotPayload = input => {
274
342
  userAllocation: base,
275
343
  consumableAllocation: effective,
276
344
  composition,
345
+ userPlans: job.plans || {},
346
+ bindingTransferTransitions: bindingTransfer.released || [],
277
347
  useitems: job.useitems || {},
278
348
  resourceBudget: job.resourceBudget || {}
279
349
  });
@@ -294,6 +364,10 @@ const buildDecisionSnapshotPayload = (input, profile = null) => {
294
364
  return buildFullDecisionSnapshotPayload(job, profile);
295
365
  }
296
366
 
367
+ const userLiveOwners = (0, _allocationOwnerDomain.buildLiveAllocationOwnerSet)({
368
+ userPlans: job.plans || {}
369
+ });
370
+ const baseRouteSelections = (0, _allocationOwnerDomain.filterRouteSelectionsForLiveAllocationOwners)(job.planRouteSelections || {}, userLiveOwners);
297
371
  let phaseStartedAt = profileNow();
298
372
  const baseBindings = (0, _currentStartAssignmentDomain.filterCurrentInventoryBindingsForPlanSpace)(job.plans || {}, job.currentInventoryBindings || {});
299
373
  measureProfile(profile, 'base-bindings', phaseStartedAt, {
@@ -302,6 +376,7 @@ const buildDecisionSnapshotPayload = (input, profile = null) => {
302
376
  phaseStartedAt = profileNow(); // Phase 1: UserAllocation(用户计划主件分配).
303
377
 
304
378
  const baseResult = (0, _planDecisionIndex.buildIncrementalDecisionSnapshot)(_extends({}, job, {
379
+ planRouteSelections: baseRouteSelections,
305
380
  currentInventoryBindings: baseBindings,
306
381
  previous: baseIncrementalProjectionCacheState,
307
382
  allocationScope: 'user',
@@ -320,8 +395,30 @@ const buildDecisionSnapshotPayload = (input, profile = null) => {
320
395
  mode: 'incremental'
321
396
  }, allocationStageProjection(base, 'user')));
322
397
  phaseStartedAt = profileNow();
323
- const demands = (0, _consumablePlanDomain.collectConsumablePlanDemands)(base.workbenchItems);
398
+ const requirements = (0, _consumablePlanDomain.collectConsumableRequirements)(base.workbenchItems);
399
+ observeAllocationStage(job, 'ConsumableRequirementDiscovery', {
400
+ mode: 'incremental',
401
+ requirements,
402
+ requirementCount: requirements.length
403
+ });
404
+ const requirementCoverage = (0, _consumablePlanDomain.computeConsumableRequirementCoverage)(requirements, base.workbenchItems);
405
+ observeAllocationStage(job, 'ConsumableCoverage', {
406
+ mode: 'incremental',
407
+ requirements,
408
+ requirementCoverage,
409
+ userBindings: base.currentInventoryBindings || {}
410
+ });
411
+ const demands = (0, _consumablePlanDomain.deriveConsumableAcquisitionTasks)(requirements, requirementCoverage);
412
+ observeAllocationStage(job, 'ConsumableAcquisitionDerivation', {
413
+ mode: 'incremental',
414
+ requirements,
415
+ requirementCoverage,
416
+ demands,
417
+ requirementCount: requirements.length,
418
+ demandCount: demands.length
419
+ });
324
420
  measureProfile(profile, 'consumable-demands', phaseStartedAt, {
421
+ requirementCount: requirements.length,
325
422
  demandCount: demands.length,
326
423
  workbenchCount: Array.isArray(base.workbenchItems) ? base.workbenchItems.length : 0
327
424
  });
@@ -331,18 +428,35 @@ const buildDecisionSnapshotPayload = (input, profile = null) => {
331
428
  demands: [],
332
429
  metadataByEquipmentId: {}
333
430
  };
334
- observeAllocationStage(job, 'ConsumableDerivation', {
431
+ observeAllocationStage(job, 'ConsumableAcquisitionUnitExpansion', {
335
432
  mode: 'incremental',
336
- allocationScope: 'user',
337
433
  demands: composition.demands || demands,
338
- demandCount: demands.length,
339
- userBindings: base.currentInventoryBindings || {}
434
+ metadataByEquipmentId: composition.metadataByEquipmentId || {}
340
435
  });
341
436
  measureProfile(profile, 'consumable-composition', phaseStartedAt, {
342
437
  effectivePlanGroupCount: Object.keys(composition.plans || {}).length
343
438
  });
344
439
  phaseStartedAt = profileNow();
345
- const effectiveBindings = (0, _currentStartAssignmentDomain.filterCurrentInventoryBindingsForPlanSpace)(composition.plans, _extends({}, job.currentInventoryBindings || {}, base.currentInventoryBindings || {}));
440
+ const effectiveLiveOwners = (0, _allocationOwnerDomain.buildLiveAllocationOwnerSet)({
441
+ userPlans: job.plans || {},
442
+ consumableMetadataByEquipmentId: composition.metadataByEquipmentId
443
+ });
444
+ observeAllocationStage(job, 'LiveOwnerSpace', {
445
+ mode: 'incremental',
446
+ liveAllocationOwners: effectiveLiveOwners
447
+ });
448
+ const effectiveRouteSelections = (0, _allocationOwnerDomain.filterRouteSelectionsForLiveAllocationOwners)(job.planRouteSelections || {}, effectiveLiveOwners);
449
+ const bindingTransfer = (0, _currentStartAssignmentDomain.transferBindingsAfterUserAllocation)({
450
+ previousBindings: job.currentInventoryBindings || {},
451
+ userPlanBindingsBeforeAllocation: baseBindings,
452
+ frozenUserBindings: base.currentInventoryBindings || {}
453
+ });
454
+ const remappedTransferredBindings = (0, _allocationOwnerDomain.remapAllocationBindingsForLiveOwners)({
455
+ bindings: bindingTransfer.bindings,
456
+ ownerRefsByTransport: job.currentInventoryBindingOwnerRefs || {},
457
+ owners: effectiveLiveOwners
458
+ });
459
+ const effectiveBindings = (0, _currentStartAssignmentDomain.filterCurrentInventoryBindingsForPlanSpace)(composition.plans, remappedTransferredBindings);
346
460
  measureProfile(profile, 'effective-bindings', phaseStartedAt, {
347
461
  bindingCount: Object.keys(effectiveBindings || {}).length
348
462
  });
@@ -358,6 +472,7 @@ const buildDecisionSnapshotPayload = (input, profile = null) => {
358
472
  const seededEffectiveFromBase = !effectiveIncrementalProjectionCacheState && Boolean(baseResult.state);
359
473
  const effectiveResult = (0, _planDecisionIndex.buildIncrementalDecisionSnapshot)(_extends({}, job, {
360
474
  plans: composition.plans,
475
+ planRouteSelections: effectiveRouteSelections,
361
476
  currentInventoryBindings: effectiveBindings,
362
477
  previous: effectivePrevious,
363
478
  allocationScope: 'consumable',
@@ -378,6 +493,8 @@ const buildDecisionSnapshotPayload = (input, profile = null) => {
378
493
  userAllocation: base,
379
494
  consumableAllocation: effective,
380
495
  composition,
496
+ userPlans: job.plans || {},
497
+ bindingTransferTransitions: bindingTransfer.released || [],
381
498
  useitems: job.useitems || {},
382
499
  resourceBudget: job.resourceBudget || {}
383
500
  });
@@ -175,6 +175,7 @@ const requestDecisionSnapshot = inputs => {
175
175
  planRouteSelections: inputs.planRouteSelections,
176
176
  routeAcquisitionIndex: inputs.routeAcquisitionIndex || {},
177
177
  currentInventoryBindings: inputs.currentInventoryBindings || {},
178
+ currentInventoryBindingOwnerRefs: inputs.currentInventoryBindingOwnerRefs || {},
178
179
  lowPriorityEquipmentIds: (0, _equipmentBlacklistDomain.getLowPriorityEquipmentIds)(inputs.equipmentBlacklist),
179
180
  startupSnapshotPath: (0, _pluginResourcePaths.getStartupSnapshotPath)()
180
181
  };