bulltrackers-module 1.0.331 → 1.0.333

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * FILENAME: computation-system/WorkflowOrchestrator.js
3
- * UPDATED: Implements Early-Skip Optimization for Data-Drift Detection.
3
+ * UPDATED: Implements Chain Repair logic for missing historical dependencies.
4
4
  */
5
5
 
6
6
  const { normalizeName, DEFINITIVE_EARLIEST_DATES } = require('./utils/utils');
@@ -44,7 +44,9 @@ function isDependencyReady(depName, isHistoricalSelf, currentStatusMap, prevStat
44
44
  }
45
45
 
46
46
  /**
47
- * UPDATED: Logic moved to top of loop for early skip on stable data.
47
+ * UPDATED: Added "Chain Repair" logic.
48
+ * If a historical dependency (yesterday's self) is missing, we treat it as a fresh start
49
+ * rather than blocking indefinitely.
48
50
  */
49
51
  function analyzeDateExecution(dateStr, calcsInPass, rootDataStatus, dailyStatus, manifestMap, prevDailyStatus = null) {
50
52
  const report = { runnable: [], blocked: [], impossible: [], failedDependency: [], reRuns: [], skipped: [] };
@@ -86,7 +88,12 @@ function analyzeDateExecution(dateStr, calcsInPass, rootDataStatus, dailyStatus,
86
88
  yesterday.setUTCDate(yesterday.getUTCDate() - 1);
87
89
  if (yesterday >= DEFINITIVE_EARLIEST_DATES.absoluteEarliest) {
88
90
  const check = isDependencyReady(calc.name, true, null, prevDailyStatus, manifestMap, stored);
89
- if (!check.ready) isBlocked = true;
91
+ if (!check.ready) {
92
+ // FIX: If yesterday is missing, we interpret it as drift (Chain Repair)
93
+ // instead of blocking, provided we are running this optimization check.
94
+ if (check.reason === 'Missing') hasDataDrift = true;
95
+ else isBlocked = true;
96
+ }
90
97
  else if (check.dataChanged) hasDataDrift = true;
91
98
  }
92
99
  }
@@ -115,13 +122,22 @@ function analyzeDateExecution(dateStr, calcsInPass, rootDataStatus, dailyStatus,
115
122
  yesterday.setUTCDate(yesterday.getUTCDate() - 1);
116
123
  if (yesterday >= DEFINITIVE_EARLIEST_DATES.absoluteEarliest) {
117
124
  const check = isDependencyReady(calc.name, true, null, prevDailyStatus, manifestMap, stored);
118
- if (!check.ready) isBlocked = true;
125
+ if (!check.ready) {
126
+ // [FIXED LOGIC START]
127
+ // If yesterday is missing (gap or first run), allow it to run as "Fresh Start"
128
+ // to repair the computation chain.
129
+ if (check.reason === 'Missing') {
130
+ hasDataDrift = true;
131
+ } else {
132
+ isBlocked = true;
133
+ }
134
+ // [FIXED LOGIC END]
135
+ }
119
136
  else if (check.dataChanged) hasDataDrift = true;
120
137
  }
121
138
  }
122
139
 
123
140
  if (missingDeps.length > 0) {
124
- // Cast to string to solve some weird null bug
125
141
  const isImpossible = missingDeps.some(d => String(simulationStatus[normalizeName(d)]?.hash).startsWith(STATUS_IMPOSSIBLE_PREFIX));
126
142
  if (isImpossible) {
127
143
  report.impossible.push({ name: cName, reason: 'Upstream Impossible' });
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * @fileoverview Executor for "Standard" (per-user) calculations.
3
3
  * UPDATED: Tracks IO Operations (Reads/Writes) for Cost Analysis.
4
+ * UPDATED: Supports System Context Injection (requiresEarliestDataDate).
4
5
  */
5
- const { normalizeName } = require('../utils/utils');
6
+ const { normalizeName, getEarliestDataDates } = require('../utils/utils');
6
7
  const { streamPortfolioData, streamHistoryData, getPortfolioPartRefs } = require('../utils/data_loader');
7
8
  const { CachedDataLoader } = require('../data/CachedDataLoader');
8
9
  const { ContextFactory } = require('../context/ContextFactory');
@@ -78,6 +79,13 @@ class StandardExecutor {
78
79
  const prevDate = new Date(dateStr + 'T00:00:00Z'); prevDate.setUTCDate(prevDate.getUTCDate() - 1);
79
80
  const prevDateStr = prevDate.toISOString().slice(0, 10);
80
81
 
82
+ // [NEW] Check if any calculation requires System Context Injection (e.g. Earliest Date)
83
+ let earliestDates = null;
84
+ if (streamingCalcs.some(c => c.manifest.requiresEarliestDataDate)) {
85
+ // Fetch once per batch, not per user
86
+ earliestDates = await getEarliestDataDates(config, deps);
87
+ }
88
+
81
89
  const tP_iter = streamPortfolioData(config, deps, dateStr, portfolioRefs);
82
90
  const needsYesterdayPortfolio = streamingCalcs.some(c => c.manifest.isHistorical);
83
91
  const yP_iter = (needsYesterdayPortfolio && rootData.yesterdayPortfolioRefs) ? streamPortfolioData(config, deps, prevDateStr, rootData.yesterdayPortfolioRefs) : null;
@@ -102,7 +110,8 @@ class StandardExecutor {
102
110
  StandardExecutor.executePerUser(
103
111
  calc, calc.manifest, dateStr, tP_chunk, yP_chunk, tH_chunk,
104
112
  fetchedDeps, previousFetchedDeps, config, deps, cachedLoader,
105
- executionStats[normalizeName(calc.manifest.name)]
113
+ executionStats[normalizeName(calc.manifest.name)],
114
+ earliestDates // [NEW] Pass system context data
106
115
  )
107
116
  ));
108
117
 
@@ -208,7 +217,7 @@ class StandardExecutor {
208
217
  if (newResult.failureReport) failureAcc.push(...newResult.failureReport);
209
218
  }
210
219
 
211
- static async executePerUser(calcInstance, metadata, dateStr, portfolioData, yesterdayPortfolioData, historyData, computedDeps, prevDeps, config, deps, loader, stats) {
220
+ static async executePerUser(calcInstance, metadata, dateStr, portfolioData, yesterdayPortfolioData, historyData, computedDeps, prevDeps, config, deps, loader, stats, earliestDates) {
212
221
  const { logger } = deps;
213
222
  const targetUserType = metadata.userType;
214
223
  const mappings = await loader.loadMappings();
@@ -237,6 +246,12 @@ class StandardExecutor {
237
246
  computedDependencies: computedDeps, previousComputedDependencies: prevDeps,
238
247
  config, deps
239
248
  });
249
+
250
+ // [NEW] Inject System Context if requested by Metadata
251
+ if (metadata.requiresEarliestDataDate && earliestDates) {
252
+ if (!context.system) context.system = {};
253
+ context.system.earliestHistoryDate = earliestDates.history;
254
+ }
240
255
 
241
256
  try {
242
257
  await calcInstance.process(context);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.331",
3
+ "version": "1.0.333",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [