poi-plugin-remodel-assistant 1.0.1069-beta → 1.0.1074-beta

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.
Files changed (24) hide show
  1. package/i18n/en-US.json +15 -1
  2. package/i18n/ja-JP.json +15 -1
  3. package/i18n/zh-CN.json +15 -1
  4. package/i18n/zh-TW.json +15 -1
  5. package/package.json +5 -2
  6. package/views/new-interface/app/decision-foundation-jobs.js +11 -0
  7. package/views/new-interface/app/decision-foundation-service.js +10 -2
  8. package/views/new-interface/app/decision-snapshot-cache.js +11 -4
  9. package/views/new-interface/app/decision-snapshot-jobs.js +14 -1
  10. package/views/new-interface/app/decision-snapshot-service.js +1 -0
  11. package/views/new-interface/app/new-interface-area.js +43 -7
  12. package/views/new-interface/decisions/domain/decision-snapshot-domain.js +104 -61
  13. package/views/new-interface/equipment/components/equipment-list.js +5 -1
  14. package/views/new-interface/equipment/domain/acquisition-domain.js +69 -25
  15. package/views/new-interface/incremental/plan-decision-index.js +95 -9
  16. package/views/new-interface/plan/components/current-start-candidate-selector.js +21 -10
  17. package/views/new-interface/plan/components/current-start-planner-modal.js +2 -2
  18. package/views/new-interface/plan/domain/current-inventory-ownership-domain.js +226 -0
  19. package/views/new-interface/plan/domain/current-plan-execution-domain.js +161 -8
  20. package/views/new-interface/plan/domain/current-plan-identity-domain.js +38 -0
  21. package/views/new-interface/plan/domain/current-start-candidate-domain.js +195 -42
  22. package/views/new-interface/plan/domain/current-start-selection-domain.js +42 -7
  23. package/views/new-interface/workbench/components/workbench-detail.js +32 -4
  24. package/views/shared/plugin-meta.js +4 -2
package/i18n/en-US.json CHANGED
@@ -974,6 +974,11 @@
974
974
  "workbench.Development": "Development",
975
975
  "workbench.Improvement source": "Improvement source",
976
976
  "workbench.Periodic quest": "Periodic quest",
977
+ "workbench.Quest": "Quest",
978
+ "workbench.Occupied by another plan": "Occupied by another plan",
979
+ "workbench.This equipment instance is already occupied by another plan": "This equipment instance is already occupied by another plan",
980
+ "workbench.Resolve the earlier Current first; this plan will not manufacture an extra copy automatically.": "Resolve the earlier Current first; this plan will not manufacture an extra copy automatically.",
981
+ "equipment.Occupied by another plan": "Occupied by another plan",
977
982
  "workbench.Ship source": "Ship source",
978
983
  "workbench.Acquire Current start": "Acquire Current start",
979
984
  "workbench.Obtain this Current start before improvement": "Obtain this Current start before improvement",
@@ -1213,5 +1218,14 @@
1213
1218
  "app.Review the current improvement starting point": "Review the current improvement starting point",
1214
1219
  "app.Right shows the Current Start selected from conservative candidates and current inventory.": "Right shows the Current Start selected from conservative candidates and current inventory.",
1215
1220
  "app.Low-priority equipment guide": "Low-priority equipment guide",
1216
- "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "Review low-priority reasons, add recommended or manual entries, and remove multiple items at once."
1221
+ "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.",
1222
+ "plan.Quest": "Quest",
1223
+ "plan.Later branches are deferred until the Current reaches the real decision point.": "Later branches are deferred until the Current reaches the real decision point.",
1224
+ "equipment.Current instance route changed": "Current instance route changed",
1225
+ "workbench.Current instance changed": "Current instance changed",
1226
+ "workbench.The bound equipment is outside the currently reachable route": "The bound equipment is outside the currently reachable route",
1227
+ "workbench.The concrete api_id is kept; the system will not silently switch to another equipment instance.": "The concrete api_id is kept; the system will not silently switch to another equipment instance.",
1228
+ "plan.Current decision target": "Current decision target",
1229
+ "plan.Current start equipment is occupied by another plan": "Current start equipment is occupied by another plan",
1230
+ "plan.A matching concrete equipment instance exists, but it is already bound to another Current. Resolve that conflict before creating another acquisition demand.": "A matching concrete equipment instance exists, but it is already bound to another Current. Resolve that conflict before creating another acquisition demand."
1217
1231
  }
package/i18n/ja-JP.json CHANGED
@@ -974,6 +974,11 @@
974
974
  "workbench.Development": "開発",
975
975
  "workbench.Improvement source": "改修入手元",
976
976
  "workbench.Periodic quest": "定期任務",
977
+ "workbench.Quest": "任務",
978
+ "workbench.Occupied by another plan": "他の計画で使用中",
979
+ "workbench.This equipment instance is already occupied by another plan": "この装備インスタンスは別の計画ですでに使用中です",
980
+ "workbench.Resolve the earlier Current first; this plan will not manufacture an extra copy automatically.": "先行する Current を先に解決してください。この計画は追加の装備を自動製造しません。",
981
+ "equipment.Occupied by another plan": "他の計画で使用中",
977
982
  "workbench.Ship source": "艦娘入手元",
978
983
  "workbench.Acquire Current start": "Current 起点を入手",
979
984
  "workbench.Obtain this Current start before improvement": "改修前にこの Current 起点を入手",
@@ -1213,5 +1218,14 @@
1213
1218
  "app.Review the current improvement starting point": "現在の改修開始地点を確認",
1214
1219
  "app.Right shows the Current Start selected from conservative candidates and current inventory.": "右側には、保守的な候補と現在の在庫から選択した Current Start を表示します。",
1215
1220
  "app.Low-priority equipment guide": "低優先装備ガイド",
1216
- "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "低優先の理由を確認し、推奨または手動の項目を追加し、複数項目をまとめて解除できます。"
1221
+ "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "低優先の理由を確認し、推奨または手動の項目を追加し、複数項目をまとめて解除できます。",
1222
+ "plan.Quest": "任務",
1223
+ "plan.Later branches are deferred until the Current reaches the real decision point.": "後続分岐は Current が実際の判断点に到達するまで保留します。",
1224
+ "equipment.Current instance route changed": "Current 実体のルートが変化",
1225
+ "workbench.Current instance changed": "Current 実体が変化しました",
1226
+ "workbench.The bound equipment is outside the currently reachable route": "バインド済み装備の現在状態は到達可能なルート外です",
1227
+ "workbench.The concrete api_id is kept; the system will not silently switch to another equipment instance.": "具体的な api_id は保持し、別の装備実体へ暗黙に切り替えません。",
1228
+ "plan.Current decision target": "現在の判断先",
1229
+ "plan.Current start equipment is occupied by another plan": "現在の開始装備は別の計画で使用中です",
1230
+ "plan.A matching concrete equipment instance exists, but it is already bound to another Current. Resolve that conflict before creating another acquisition demand.": "条件に合う装備実体は存在しますが、別の Current にバインドされています。新しい入手要求を増やす前に、この競合を解消してください。"
1217
1231
  }
package/i18n/zh-CN.json CHANGED
@@ -974,6 +974,11 @@
974
974
  "workbench.Development": "开发",
975
975
  "workbench.Improvement source": "改修来源",
976
976
  "workbench.Periodic quest": "周期任务",
977
+ "workbench.Quest": "任务",
978
+ "workbench.Occupied by another plan": "已被其他计划占用",
979
+ "workbench.This equipment instance is already occupied by another plan": "这件装备实例已被其他计划占用",
980
+ "workbench.Resolve the earlier Current first; this plan will not manufacture an extra copy automatically.": "请先处理前面的 Current;当前计划不会自动制造额外装备。",
981
+ "equipment.Occupied by another plan": "已被其他计划占用",
977
982
  "workbench.Ship source": "舰娘来源",
978
983
  "workbench.Acquire Current start": "获取当前起点",
979
984
  "workbench.Obtain this Current start before improvement": "改修前先获取这个 Current 起点",
@@ -1213,5 +1218,14 @@
1213
1218
  "app.Review the current improvement starting point": "查看当前改修起点",
1214
1219
  "app.Right shows the Current Start selected from conservative candidates and current inventory.": "右侧展示从保守候选与当前库存中选定的 Current Start。",
1215
1220
  "app.Low-priority equipment guide": "低优先装备指南",
1216
- "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "查看低优先原因,添加推荐或手动条目,并可批量移除。"
1221
+ "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "查看低优先原因,添加推荐或手动条目,并可批量移除。",
1222
+ "plan.Quest": "任务",
1223
+ "plan.Later branches are deferred until the Current reaches the real decision point.": "后续分支延后到 Current 真正走到决策点时再选择。",
1224
+ "equipment.Current instance route changed": "当前实例路线已变化",
1225
+ "workbench.Current instance changed": "当前实例已变化",
1226
+ "workbench.The bound equipment is outside the currently reachable route": "已绑定装备当前状态不在可达路线中",
1227
+ "workbench.The concrete api_id is kept; the system will not silently switch to another equipment instance.": "保留当前具体 api_id;系统不会静默切换到其他装备实例。",
1228
+ "plan.Current decision target": "当前决策目标",
1229
+ "plan.Current start equipment is occupied by another plan": "当前起点装备已被其他计划占用",
1230
+ "plan.A matching concrete equipment instance exists, but it is already bound to another Current. Resolve that conflict before creating another acquisition demand.": "存在符合条件的具体装备实例,但它已绑定给其他 Current。请先处理该冲突,不要自动扩大新的获取需求。"
1217
1231
  }
package/i18n/zh-TW.json CHANGED
@@ -974,6 +974,11 @@
974
974
  "workbench.Development": "開發",
975
975
  "workbench.Improvement source": "改修來源",
976
976
  "workbench.Periodic quest": "週期任務",
977
+ "workbench.Quest": "任務",
978
+ "workbench.Occupied by another plan": "已被其他計畫占用",
979
+ "workbench.This equipment instance is already occupied by another plan": "這件裝備實例已被其他計畫占用",
980
+ "workbench.Resolve the earlier Current first; this plan will not manufacture an extra copy automatically.": "請先處理前面的 Current;目前計畫不會自動製造額外裝備。",
981
+ "equipment.Occupied by another plan": "已被其他計畫占用",
977
982
  "workbench.Ship source": "艦娘來源",
978
983
  "workbench.Acquire Current start": "取得目前起點",
979
984
  "workbench.Obtain this Current start before improvement": "改修前先取得這個 Current 起點",
@@ -1213,5 +1218,14 @@
1213
1218
  "app.Review the current improvement starting point": "查看目前改修起點",
1214
1219
  "app.Right shows the Current Start selected from conservative candidates and current inventory.": "右側顯示從保守候選與目前庫存中選定的 Current Start。",
1215
1220
  "app.Low-priority equipment guide": "低優先裝備指南",
1216
- "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "查看低優先原因,加入建議或手動項目,並可批次移除。"
1221
+ "app.Review low-priority reasons, add recommended or manual entries, and remove multiple items at once.": "查看低優先原因,加入建議或手動項目,並可批次移除。",
1222
+ "plan.Quest": "任務",
1223
+ "plan.Later branches are deferred until the Current reaches the real decision point.": "後續分支延後到 Current 真正走到決策點時再選擇。",
1224
+ "equipment.Current instance route changed": "目前實例路線已變化",
1225
+ "workbench.Current instance changed": "目前實例已變化",
1226
+ "workbench.The bound equipment is outside the currently reachable route": "已綁定裝備目前狀態不在可達路線中",
1227
+ "workbench.The concrete api_id is kept; the system will not silently switch to another equipment instance.": "保留目前具體 api_id;系統不會靜默切換到其他裝備實例。",
1228
+ "plan.Current decision target": "目前決策目標",
1229
+ "plan.Current start equipment is occupied by another plan": "目前起點裝備已被其他計畫占用",
1230
+ "plan.A matching concrete equipment instance exists, but it is already bound to another Current. Resolve that conflict before creating another acquisition demand.": "存在符合條件的具體裝備實例,但它已綁定給其他 Current。請先處理該衝突,不要自動擴大新的取得需求。"
1217
1231
  }
package/package.json CHANGED
@@ -96,8 +96,11 @@
96
96
  "id": "poi-plugin-remodel-assistant",
97
97
  "priority": 50,
98
98
  "releaseChannel": "beta",
99
- "title": "改修助手"
99
+ "title": "改修助手",
100
+ "runtimeFlags": {
101
+ "forceFullDecisionRebuild": true
102
+ }
100
103
  },
101
104
  "private": false,
102
- "version": "1.0.1069-beta"
105
+ "version": "1.0.1074-beta"
103
106
  }
@@ -3,6 +3,8 @@
3
3
  exports.__esModule = true;
4
4
  exports.executeDecisionFoundationJob = exports.resetDecisionFoundationJobState = exports.buildDecisionFoundationPayload = exports.buildFullDecisionFoundationPayload = void 0;
5
5
 
6
+ var _pluginMeta = require("../../shared/plugin-meta");
7
+
6
8
  var _decisionItemIndex = require("../incremental/decision-item-index");
7
9
 
8
10
  var _decisionChainDomain = require("../decisions/domain/decision-chain-domain");
@@ -30,6 +32,15 @@ const buildDecisionFoundationPayload = ({
30
32
  effectiveData = [],
31
33
  masterEquips = {}
32
34
  } = {}) => {
35
+ if (_pluginMeta.FORCE_FULL_DECISION_REBUILD) {
36
+ incrementalFoundationState = null;
37
+ return buildFullDecisionFoundationPayload({
38
+ data,
39
+ effectiveData,
40
+ masterEquips
41
+ });
42
+ }
43
+
33
44
  const result = (0, _decisionItemIndex.buildIncrementalDecisionFoundation)({
34
45
  data,
35
46
  effectiveData,
@@ -5,6 +5,8 @@ exports.clearProcessDecisionFoundation = exports.requestDecisionFoundation = exp
5
5
 
6
6
  var _path = _interopRequireDefault(require("path"));
7
7
 
8
+ var _pluginMeta = require("../../shared/plugin-meta");
9
+
8
10
  var _decisionFoundationJobs = require("./decision-foundation-jobs");
9
11
 
10
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -143,6 +145,7 @@ const execute = job => {
143
145
  };
144
146
 
145
147
  const readProcessDecisionFoundation = inputs => {
148
+ if (_pluginMeta.FORCE_FULL_DECISION_REBUILD) return null;
146
149
  const identity = normalizeInputs(inputs);
147
150
  return sameInputs(foundationCache, identity) ? foundationCache.value : null;
148
151
  };
@@ -151,7 +154,12 @@ exports.readProcessDecisionFoundation = readProcessDecisionFoundation;
151
154
 
152
155
  const requestDecisionFoundation = inputs => {
153
156
  const identity = normalizeInputs(inputs);
154
- if (sameInputs(foundationCache, identity)) return Promise.resolve(foundationCache.value);
157
+
158
+ if (!_pluginMeta.FORCE_FULL_DECISION_REBUILD && sameInputs(foundationCache, identity)) {
159
+ return Promise.resolve(foundationCache.value);
160
+ }
161
+
162
+ if (_pluginMeta.FORCE_FULL_DECISION_REBUILD) foundationCache = null;
155
163
 
156
164
  if (foundationRequest && sameInputs(foundationRequest, identity)) {
157
165
  return foundationRequest.promise;
@@ -172,7 +180,7 @@ const requestDecisionFoundation = inputs => {
172
180
  processingMode
173
181
  });
174
182
 
175
- if (requestId === foundationRequestId) {
183
+ if (requestId === foundationRequestId && !_pluginMeta.FORCE_FULL_DECISION_REBUILD) {
176
184
  foundationCache = _extends({}, identity, {
177
185
  value
178
186
  });
@@ -3,11 +3,13 @@
3
3
  exports.__esModule = true;
4
4
  exports.SNAPSHOT_INPUT_KEYS = exports.FOUNDATION_INPUT_KEYS = exports.createDecisionFoundationCache = exports.readDecisionFoundationCache = exports.clearProcessDecisionSnapshotCache = exports.writeProcessDecisionSnapshotCache = exports.readProcessDecisionSnapshotCache = exports.createDecisionSnapshotCache = exports.readDecisionSnapshotCache = exports.sameDecisionSnapshotInputs = void 0;
5
5
 
6
+ var _pluginMeta = require("../../shared/plugin-meta");
7
+
6
8
  var _equipmentBlacklistDomain = require("../equipment/domain/equipment-blacklist-domain");
7
9
 
8
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); }
9
11
 
10
- const SNAPSHOT_INPUT_KEYS = ['dataRevision', 'plans', 'initialDay', 'masterEquips', 'actualEquipLevels', 'actualEquipInventory', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'equipmentBlacklist', 'acquisitionValueIndex'];
12
+ const SNAPSHOT_INPUT_KEYS = ['dataRevision', 'plans', 'initialDay', 'masterEquips', 'actualEquipLevels', 'actualEquipInventory', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'equipmentBlacklist', 'routeAcquisitionIndex', 'acquisitionValueIndex'];
11
13
  exports.SNAPSHOT_INPUT_KEYS = SNAPSHOT_INPUT_KEYS;
12
14
  const FOUNDATION_INPUT_KEYS = ['dataRevision', 'masterEquips'];
13
15
  exports.FOUNDATION_INPUT_KEYS = FOUNDATION_INPUT_KEYS;
@@ -23,7 +25,7 @@ const stableValue = value => {
23
25
 
24
26
  const stableSignature = value => JSON.stringify(stableValue(value || {}));
25
27
 
26
- const CONTENT_IDENTITY_KEYS = new Set(['plans', 'actualEquipLevels', 'actualEquipInventory', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections']);
28
+ const CONTENT_IDENTITY_KEYS = new Set(['plans', 'actualEquipLevels', 'actualEquipInventory', 'actualOwnedShipMasterIds', 'decisionSelections', 'planRouteSelections', 'routeAcquisitionIndex', 'acquisitionValueIndex']);
27
29
 
28
30
  const inputIdentity = (key, value) => {
29
31
  if (key === 'equipmentBlacklist') return (0, _equipmentBlacklistDomain.equipmentBlacklistSignature)(value);
@@ -53,7 +55,7 @@ const sameDecisionSnapshotInputs = (left, right) => sameInputs(left, right, SNAP
53
55
 
54
56
  exports.sameDecisionSnapshotInputs = sameDecisionSnapshotInputs;
55
57
 
56
- const readDecisionSnapshotCache = (cache, inputs) => readCache(cache, inputs, SNAPSHOT_INPUT_KEYS);
58
+ const readDecisionSnapshotCache = (cache, inputs) => _pluginMeta.FORCE_FULL_DECISION_REBUILD ? null : readCache(cache, inputs, SNAPSHOT_INPUT_KEYS);
57
59
 
58
60
  exports.readDecisionSnapshotCache = readDecisionSnapshotCache;
59
61
 
@@ -66,6 +68,11 @@ const readProcessDecisionSnapshotCache = inputs => readDecisionSnapshotCache(pro
66
68
  exports.readProcessDecisionSnapshotCache = readProcessDecisionSnapshotCache;
67
69
 
68
70
  const writeProcessDecisionSnapshotCache = (inputs, value) => {
71
+ if (_pluginMeta.FORCE_FULL_DECISION_REBUILD) {
72
+ processDecisionSnapshotCache = null;
73
+ return value;
74
+ }
75
+
69
76
  processDecisionSnapshotCache = createDecisionSnapshotCache(inputs, value);
70
77
  return value;
71
78
  };
@@ -78,7 +85,7 @@ const clearProcessDecisionSnapshotCache = () => {
78
85
 
79
86
  exports.clearProcessDecisionSnapshotCache = clearProcessDecisionSnapshotCache;
80
87
 
81
- const readDecisionFoundationCache = (cache, inputs) => readCache(cache, inputs, FOUNDATION_INPUT_KEYS);
88
+ const readDecisionFoundationCache = (cache, inputs) => _pluginMeta.FORCE_FULL_DECISION_REBUILD ? null : readCache(cache, inputs, FOUNDATION_INPUT_KEYS);
82
89
 
83
90
  exports.readDecisionFoundationCache = readDecisionFoundationCache;
84
91
 
@@ -3,6 +3,8 @@
3
3
  exports.__esModule = true;
4
4
  exports.executeDecisionSnapshotJob = exports.resetDecisionSnapshotJobState = exports.buildDecisionSnapshotPayload = exports.buildFullDecisionSnapshotPayload = void 0;
5
5
 
6
+ var _pluginMeta = require("../../shared/plugin-meta");
7
+
6
8
  var _planDecisionIndex = require("../incremental/plan-decision-index");
7
9
 
8
10
  var _decisionSnapshotDomain = require("../decisions/domain/decision-snapshot-domain");
@@ -26,7 +28,8 @@ const buildFullDecisionSnapshotPayload = input => {
26
28
 
27
29
  const composition = (0, _consumablePlanDomain.composeConsumablePlansAfter)(input && input.plans || {}, demands);
28
30
  const effective = (0, _decisionSnapshotDomain.buildFullDecisionSnapshotCore)(_extends({}, input || {}, {
29
- plans: composition.plans
31
+ plans: composition.plans,
32
+ currentInventoryBindings: _extends({}, input && input.currentInventoryBindings || {}, base.currentInventoryBindings || {})
30
33
  }));
31
34
  return _extends({}, base, {
32
35
  workbenchItems: (0, _consumablePlanDomain.decorateConsumablePlanEntries)({
@@ -39,6 +42,7 @@ const buildFullDecisionSnapshotPayload = input => {
39
42
  metadataByEquipmentId: composition.metadataByEquipmentId,
40
43
  parentPlanIdByEquipmentId
41
44
  }),
45
+ currentInventoryBindings: effective.currentInventoryBindings || base.currentInventoryBindings || {},
42
46
  consumablePlanDemands: composition.demands,
43
47
  consumablePlanMetaByEquipmentId: composition.metadataByEquipmentId
44
48
  });
@@ -50,6 +54,13 @@ let effectiveIncrementalSnapshotState = null;
50
54
 
51
55
  const buildDecisionSnapshotPayload = input => {
52
56
  const job = input || {};
57
+
58
+ if (_pluginMeta.FORCE_FULL_DECISION_REBUILD) {
59
+ baseIncrementalSnapshotState = null;
60
+ effectiveIncrementalSnapshotState = null;
61
+ return buildFullDecisionSnapshotPayload(job);
62
+ }
63
+
53
64
  const baseResult = (0, _planDecisionIndex.buildIncrementalDecisionSnapshot)(_extends({}, job, {
54
65
  previous: baseIncrementalSnapshotState
55
66
  }));
@@ -70,6 +81,7 @@ const buildDecisionSnapshotPayload = input => {
70
81
  const composition = (0, _consumablePlanDomain.composeConsumablePlansAfter)(job.plans || {}, demands);
71
82
  const effectiveResult = (0, _planDecisionIndex.buildIncrementalDecisionSnapshot)(_extends({}, job, {
72
83
  plans: composition.plans,
84
+ currentInventoryBindings: _extends({}, job.currentInventoryBindings || {}, base.currentInventoryBindings || {}),
73
85
  previous: effectiveIncrementalSnapshotState
74
86
  }));
75
87
  effectiveIncrementalSnapshotState = effectiveResult.state;
@@ -85,6 +97,7 @@ const buildDecisionSnapshotPayload = input => {
85
97
  metadataByEquipmentId: composition.metadataByEquipmentId,
86
98
  parentPlanIdByEquipmentId
87
99
  }),
100
+ currentInventoryBindings: effective.currentInventoryBindings || base.currentInventoryBindings || {},
88
101
  consumablePlanDemands: composition.demands,
89
102
  consumablePlanMetaByEquipmentId: composition.metadataByEquipmentId,
90
103
  incrementalMetrics: _extends({}, base.incrementalMetrics || {}, {
@@ -125,6 +125,7 @@ const requestDecisionSnapshot = inputs => {
125
125
  planRouteSelections: inputs.planRouteSelections,
126
126
  routeAcquisitionIndex: inputs.routeAcquisitionIndex || {},
127
127
  acquisitionValueIndex: inputs.acquisitionValueIndex || {},
128
+ currentInventoryBindings: inputs.currentInventoryBindings || {},
128
129
  lowPriorityEquipmentIds: (0, _equipmentBlacklistDomain.getLowPriorityEquipmentIds)(inputs.equipmentBlacklist)
129
130
  };
130
131
 
@@ -29,6 +29,8 @@ var _currentStartCandidateDomain = require("../plan/domain/current-start-candida
29
29
 
30
30
  var _currentStartSelectionDomain = require("../plan/domain/current-start-selection-domain");
31
31
 
32
+ var _currentPlanIdentityDomain = require("../plan/domain/current-plan-identity-domain");
33
+
32
34
  var _currentPlanExecutionDomain = require("../plan/domain/current-plan-execution-domain");
33
35
 
34
36
  var _planStorage = require("../../shared/plan-storage");
@@ -186,6 +188,7 @@ class NewInterfaceArea extends _react.Component {
186
188
  const snapshotInputs = decisionSnapshotInputsFor(props, this.state, this.plansOverride, this.plansOverrideBase);
187
189
  this.currentDecisionSnapshot = (0, _decisionSnapshotCache.readProcessDecisionSnapshotCache)(snapshotInputs);
188
190
  this.currentDecisionSnapshotInputs = this.currentDecisionSnapshot ? snapshotInputs : null;
191
+ this.currentInventoryBindings = this.currentDecisionSnapshot && this.currentDecisionSnapshot.currentInventoryBindings || {};
189
192
  if (this.currentDecisionSnapshot) this.state.decisionSnapshotLoading = false;
190
193
  this.exclusionRecommendationSnapshot = {
191
194
  dataRevision: null,
@@ -212,13 +215,16 @@ class NewInterfaceArea extends _react.Component {
212
215
  initialDay
213
216
  } = this.props;
214
217
  const {
215
- equipmentBlacklist
218
+ equipmentBlacklist,
219
+ workbenchDay
216
220
  } = this.state;
217
221
 
218
222
  if (prevProps.initialDay !== initialDay) {
219
- const nextWorkbenchDay = (0, _jstClock.followJSTDaySelection)(this.state.workbenchDay, prevProps.initialDay, initialDay);
223
+ const nextWorkbenchDay = (0, _jstClock.followJSTDaySelection)(workbenchDay, prevProps.initialDay, initialDay);
220
224
 
221
- if (Number(nextWorkbenchDay) !== Number(this.state.workbenchDay)) {
225
+ if (Number(nextWorkbenchDay) !== Number(workbenchDay)) {
226
+ // Prop-driven day rollover is intentionally synchronized after update.
227
+ // eslint-disable-next-line react/no-did-update-set-state
222
228
  this.setState({
223
229
  workbenchDay: nextWorkbenchDay
224
230
  });
@@ -617,6 +623,7 @@ var _initialiseProps = function () {
617
623
  if (cached) {
618
624
  this.currentDecisionSnapshot = cached;
619
625
  this.currentDecisionSnapshotInputs = snapshotInputs;
626
+ this.currentInventoryBindings = cached.currentInventoryBindings || {};
620
627
 
621
628
  const complete = () => {
622
629
  this.ensureSelection(cached);
@@ -655,7 +662,8 @@ var _initialiseProps = function () {
655
662
  equipmentBlacklist: snapshotInputs.equipmentBlacklist
656
663
  };
657
664
  const request = yieldToVisibleShell().then(() => (0, _decisionFoundationService.requestDecisionFoundation)(foundationInputs)).then(foundation => (0, _decisionSnapshotService.requestDecisionSnapshot)(_extends({}, snapshotInputs, {
658
- foundation
665
+ foundation,
666
+ currentInventoryBindings: this.currentInventoryBindings || {}
659
667
  }))).then(snapshot => {
660
668
  if (!this.mounted || taskId !== this.decisionSnapshotTaskId) return null;
661
669
 
@@ -667,6 +675,7 @@ var _initialiseProps = function () {
667
675
  (0, _decisionSnapshotCache.writeProcessDecisionSnapshotCache)(snapshotInputs, snapshot);
668
676
  this.currentDecisionSnapshot = snapshot;
669
677
  this.currentDecisionSnapshotInputs = snapshotInputs;
678
+ this.currentInventoryBindings = snapshot.currentInventoryBindings || {};
670
679
  this.setState(previous => ({
671
680
  decisionSnapshotLoading: false,
672
681
  decisionSnapshotError: null,
@@ -794,9 +803,36 @@ var _initialiseProps = function () {
794
803
  configurable: true,
795
804
  enumerable: true,
796
805
  writable: true,
797
- value: () => {// Route preference is user intent; computed path/inventory assignment is
798
- // derived state. Never feed a projection back into planRouteSelections.
799
- // Doing so would create a second authority that outlives live inventory.
806
+ value: snapshot => {
807
+ // Current selection is user intent, but its lifecycle is exactly one live
808
+ // Current. Do not persist a completed Current's decision into the next
809
+ // generation. Computed route/inventory fields still never flow back here.
810
+ const activeCurrentIds = new Set((snapshot && snapshot.routePlannings || []).map(planning => {
811
+ const analysis = planning && planning.analysis;
812
+ return analysis && analysis.goal ? (0, _currentPlanIdentityDomain.currentPlanInstanceId)(planning.id, analysis.goal.star, analysis) : '';
813
+ }).filter(Boolean));
814
+ const {
815
+ planRouteSelections = {}
816
+ } = this.state;
817
+ let changed = false;
818
+ const next = Object.keys(planRouteSelections).reduce((result, key) => {
819
+ const selection = planRouteSelections[key];
820
+ const currentId = String(selection && selection.currentId || '').trim();
821
+
822
+ if (currentId && !activeCurrentIds.has(currentId)) {
823
+ changed = true;
824
+ return result;
825
+ }
826
+
827
+ return _extends({}, result, {
828
+ [key]: selection
829
+ });
830
+ }, {});
831
+ if (!changed) return;
832
+ const normalized = (0, _currentStartSelectionDomain.setCurrentStartSelections)(config, next);
833
+ this.setState({
834
+ planRouteSelections: normalized
835
+ });
800
836
  }
801
837
  });
802
838
  Object.defineProperty(this, "getFilteredItems", {
@@ -5,8 +5,12 @@ exports.buildFullDecisionSnapshotCore = void 0;
5
5
 
6
6
  var _currentStartCandidateDomain = require("../../plan/domain/current-start-candidate-domain");
7
7
 
8
+ var _currentPlanIdentityDomain = require("../../plan/domain/current-plan-identity-domain");
9
+
8
10
  var _currentStartSelectionDomain = require("../../plan/domain/current-start-selection-domain");
9
11
 
12
+ var _currentInventoryOwnershipDomain = require("../../plan/domain/current-inventory-ownership-domain");
13
+
10
14
  var _currentPlanExecutionDomain = require("../../plan/domain/current-plan-execution-domain");
11
15
 
12
16
  var _planFactsDomain = require("../../plan/domain/plan-facts-domain");
@@ -32,7 +36,8 @@ const buildFullDecisionSnapshotCore = ({
32
36
  decisionSelections = {},
33
37
  planRouteSelections = {},
34
38
  routeAcquisitionIndex = {},
35
- lowPriorityEquipmentIds = []
39
+ lowPriorityEquipmentIds = [],
40
+ currentInventoryBindings = {}
36
41
  } = {}) => {
37
42
  if (!foundation) throw new Error('decision-snapshot-foundation-missing');
38
43
  const {
@@ -50,76 +55,114 @@ const buildFullDecisionSnapshotCore = ({
50
55
  decisionSelections,
51
56
  lowPriorityEquipmentIds
52
57
  });
53
- const routePlannings = (0, _currentStartCandidateDomain.buildCurrentStartPlanningStates)({
54
- data: effectiveData,
55
- plans,
56
- equipLevels,
57
- equipInventory,
58
- routeAcquisitionIndex
59
- });
60
- const routePlanningById = Object.fromEntries(routePlannings.map(planning => [planning.id, planning]));
61
-
62
- const routePlanningFor = item => routePlanningById[item.id] || {
63
- id: Number(item.id),
64
- status: _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.NO_PLAN,
65
- planState: item.planState,
66
- analysis: null
67
- };
68
58
 
69
- const projectionInput = (item, analysis) => {
70
- const routeSelection = analysis ? (0, _currentStartSelectionDomain.getCurrentStartSelection)(planRouteSelections, item.id, analysis.goal.star, 1) : null;
71
- const planning = routePlanningFor(item);
72
- return {
73
- item: _extends({}, item, {
74
- routePlanning: planning
75
- }),
76
- analysis,
77
- selection: routeSelection,
78
- selections: planRouteSelections,
79
- allItems: baseItems,
80
- today: initialDay,
81
- ownedShipMasterIds,
59
+ const projectPass = passBindings => {
60
+ const routePlannings = (0, _currentStartCandidateDomain.buildCurrentStartPlanningStates)({
61
+ data: effectiveData,
62
+ plans,
82
63
  equipLevels,
83
64
  equipInventory,
84
- routeAcquisitionIndex
65
+ routeAcquisitionIndex,
66
+ currentInventoryBindings: passBindings
67
+ });
68
+ const routePlanningById = Object.fromEntries(routePlannings.map(planning => [planning.id, planning]));
69
+
70
+ const routePlanningFor = item => routePlanningById[item.id] || {
71
+ id: Number(item.id),
72
+ status: _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.NO_PLAN,
73
+ planState: item.planState,
74
+ analysis: null
75
+ };
76
+
77
+ const projectionInput = (item, analysis) => {
78
+ const routeSelection = analysis ? (0, _currentStartSelectionDomain.getCurrentStartSelectionForAnalysis)(planRouteSelections, item.id, analysis.goal.star, analysis) : null;
79
+ const planning = routePlanningFor(item);
80
+ const currentId = analysis ? (0, _currentPlanIdentityDomain.currentPlanInstanceId)(item.id, analysis.goal.star, analysis) : '';
81
+ return {
82
+ item: _extends({}, item, {
83
+ routePlanning: planning
84
+ }),
85
+ analysis,
86
+ selection: routeSelection,
87
+ preferredInventoryId: currentId ? passBindings[currentId] : null,
88
+ selections: planRouteSelections,
89
+ allItems: baseItems,
90
+ today: initialDay,
91
+ ownedShipMasterIds,
92
+ equipLevels,
93
+ equipInventory,
94
+ routeAcquisitionIndex
95
+ };
85
96
  };
86
- };
87
97
 
88
- const projectedEntriesById = {};
89
- baseItems.forEach(item => {
90
- const planning = routePlanningFor(item);
91
- let entries = [];
98
+ const projectedEntriesById = {};
99
+ baseItems.forEach(item => {
100
+ const planning = routePlanningFor(item);
101
+ let entries = [];
92
102
 
93
- if (item.planState.status === _planFactsDomain.PLAN_TARGET_STATUS.PENDING) {
94
- if (planning.status === _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.READY) {
95
- entries = (0, _currentPlanExecutionDomain.projectCurrentPlanTodayEntries)(projectionInput(item, planning.analysis));
96
- } else if (planning.status === _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.DIRECT_ONLY) {
97
- entries = (0, _currentPlanExecutionDomain.projectCurrentPlanTodayEntries)(projectionInput(item, null));
103
+ if (item.planState.status === _planFactsDomain.PLAN_TARGET_STATUS.PENDING) {
104
+ if (planning.status === _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.READY || planning.status === _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.OCCUPIED) {
105
+ entries = (0, _currentPlanExecutionDomain.projectCurrentPlanTodayEntries)(projectionInput(item, planning.analysis));
106
+ } else if (planning.status === _currentStartCandidateDomain.CURRENT_START_PLANNING_STATUS.DIRECT_ONLY) {
107
+ entries = (0, _currentPlanExecutionDomain.projectCurrentPlanTodayEntries)(projectionInput(item, null));
108
+ }
98
109
  }
99
- }
100
110
 
101
- projectedEntriesById[item.id] = entries;
102
- });
103
- const items = (0, _decisionDomain.sortDecisionItems)(baseItems.map(item => {
104
- const planning = routePlanningFor(item);
105
- const entries = projectedEntriesById[item.id] || [];
106
- const projected = entries[0] || item;
107
- return _extends({}, projected, {
108
- routePlanning: planning,
109
- planRouteEntries: entries
111
+ projectedEntriesById[item.id] = entries;
110
112
  });
111
- }));
112
- const workbenchItems = (0, _decisionDomain.sortDecisionItems)(baseItems.reduce((result, item) => result.concat(projectedEntriesById[item.id] || []), []));
113
- return {
114
- decisionPoints,
115
- effectiveEquipLevels: equipLevels,
116
- effectiveEquipInventory: equipInventory,
117
- effectiveOwnedShipMasterIds: ownedShipMasterIds,
118
- items,
119
- workbenchItems,
120
- routePlannings,
121
- chainItems
113
+ const projectedWorkbenchItems = (0, _decisionDomain.sortDecisionItems)(baseItems.reduce((result, item) => result.concat(projectedEntriesById[item.id] || []), []));
114
+ const ownership = (0, _currentInventoryOwnershipDomain.reconcileCurrentInventoryOwnership)({
115
+ entries: projectedWorkbenchItems,
116
+ equipInventory,
117
+ equipLevels,
118
+ previousBindings: passBindings
119
+ });
120
+ const reconciledById = ownership.entries.reduce((result, entry) => _extends({}, result, {
121
+ [Number(entry.id)]: entry
122
+ }), {});
123
+ const items = (0, _decisionDomain.sortDecisionItems)(baseItems.map(item => {
124
+ const planning = routePlanningFor(item);
125
+ const rawEntries = projectedEntriesById[item.id] || [];
126
+ const projected = reconciledById[item.id] || rawEntries[0] || item;
127
+ const entries = rawEntries.length > 0 ? [projected] : [];
128
+ return _extends({}, projected, {
129
+ routePlanning: planning,
130
+ planRouteEntries: entries
131
+ });
132
+ }));
133
+ return {
134
+ decisionPoints,
135
+ effectiveEquipLevels: equipLevels,
136
+ effectiveEquipInventory: equipInventory,
137
+ effectiveOwnedShipMasterIds: ownedShipMasterIds,
138
+ items,
139
+ workbenchItems: ownership.entries,
140
+ routePlannings,
141
+ chainItems,
142
+ currentInventoryBindings: ownership.bindings
143
+ };
122
144
  };
145
+
146
+ const sameBindings = (left, right) => {
147
+ const normalize = source => Object.entries(source || {}).map(([currentId, inventoryId]) => [String(currentId), Number(inventoryId)]).filter(([, inventoryId]) => Number.isInteger(inventoryId) && inventoryId > 0).sort(([leftId], [rightId]) => leftId.localeCompare(rightId));
148
+
149
+ return JSON.stringify(normalize(left)) === JSON.stringify(normalize(right));
150
+ }; // Ownership is a live fact used by Current Start search. Re-project until
151
+ // concrete bindings stabilize so a later Current can observe that an exact
152
+ // matching api_id was already claimed earlier in the same snapshot and
153
+ // becomes OCCUPIED instead of fabricating a second acquisition demand.
154
+
155
+
156
+ let passBindings = currentInventoryBindings || {};
157
+ let result = null;
158
+
159
+ for (let pass = 0; pass < 3; pass += 1) {
160
+ result = projectPass(passBindings);
161
+ if (sameBindings(result.currentInventoryBindings, passBindings)) break;
162
+ passBindings = result.currentInventoryBindings;
163
+ }
164
+
165
+ return result;
123
166
  };
124
167
 
125
168
  exports.buildFullDecisionSnapshotCore = buildFullDecisionSnapshotCore;
@@ -180,7 +180,11 @@ class EquipmentList extends _react.Component {
180
180
  className: "decision-equipment-meta decision-workbench-tag-column"
181
181
  }, activePlan.todayStage && activePlan.todayStage.kind === 'missing-source' && activePlan.currentStartAcquisition && activePlan.currentStartAcquisition.available === true && _react.default.createElement("span", {
182
182
  className: "decision-pill decision-pill-warning"
183
- }, __('Acquire first')), materialShortage && activePlan.todayStage && activePlan.todayStage.kind !== 'missing-source' && _react.default.createElement("span", {
183
+ }, __('Acquire first')), activePlan.todayStage && activePlan.todayStage.kind === 'occupied-source' && _react.default.createElement("span", {
184
+ className: "decision-pill decision-pill-warning"
185
+ }, __('Occupied by another plan')), activePlan.todayStage && activePlan.todayStage.kind === 'current-instance-diverged' && _react.default.createElement("span", {
186
+ className: "decision-pill decision-pill-warning"
187
+ }, __('Current instance route changed')), materialShortage && activePlan.todayStage && activePlan.todayStage.kind !== 'missing-source' && _react.default.createElement("span", {
184
188
  className: "decision-pill decision-pill-warning"
185
189
  }, __('Materials insufficient')), activePlan.planKind === 'consumable' && _react.default.createElement("span", {
186
190
  className: "decision-pill decision-pill-primary"