bulltrackers-module 1.0.171 → 1.0.173

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,8 +1,6 @@
1
1
  /**
2
2
  * FIXED: computation_pass_runner.js
3
- * Now calculates earliest date PER CALCULATION, not per pass
4
- * --- MODIFIED: Passes 'existingResults' to 'runStandardComputationPass'
5
- * to replicate the test harness's 7-argument signature. ---
3
+ * V3: Fetches Previous Day's Results to enable State Persistence.
6
4
  */
7
5
 
8
6
  const { groupByPass, checkRootDataAvailability, fetchExistingResults, runStandardComputationPass, runMetaComputationPass } = require('./orchestration_helpers.js');
@@ -11,63 +9,98 @@ const PARALLEL_BATCH_SIZE = 7;
11
9
 
12
10
  async function runComputationPass(config, dependencies, computationManifest) {
13
11
  const { logger } = dependencies;
14
- const passToRun = String(config.COMPUTATION_PASS_TO_RUN);
15
- if (!passToRun) return logger.log('ERROR', '[PassRunner] No pass defined. Aborting.');
12
+ const passToRun = String(config.COMPUTATION_PASS_TO_RUN);
13
+ if (!passToRun)
14
+ return logger.log('ERROR', '[PassRunner] No pass defined. Aborting.');
15
+
16
16
  logger.log('INFO', `🚀 Starting PASS ${passToRun}...`);
17
17
 
18
- const earliestDates = { portfolio: new Date('2025-09-25T00:00:00Z'), history: new Date('2025-11-05T00:00:00Z'), social: new Date('2025-10-30T00:00:00Z'), insights: new Date('2025-08-26T00:00:00Z') };
18
+ const earliestDates = { portfolio: new Date('2025-09-25T00:00:00Z'), history: new Date('2025-11-05T00:00:00Z'), social: new Date('2025-10-30T00:00:00Z'), insights: new Date('2025-08-26T00:00:00Z') };
19
19
  earliestDates.absoluteEarliest = Object.values(earliestDates).reduce((a,b) => a < b ? a : b);
20
- logger.log('INFO', `Hardcoded earliest dates: ${Object.entries(earliestDates).map(([k,v]) => `${k}=${v.toISOString().slice(0,10)}`).join(', ')}`);
21
20
 
22
- const passes = groupByPass(computationManifest);
21
+ const passes = groupByPass(computationManifest);
23
22
  const calcsInThisPass = passes[passToRun] || [];
24
- if (!calcsInThisPass.length) return logger.log('WARN', `[PassRunner] No calcs for Pass ${passToRun}. Exiting.`);
23
+
24
+ if (!calcsInThisPass.length)
25
+ return logger.log('WARN', `[PassRunner] No calcs for Pass ${passToRun}. Exiting.`);
26
+
25
27
  const calcEarliestDates = new Map();
26
- for (const calc of calcsInThisPass) { const deps = calc.rootDataDependencies || []; if (!deps.length) { calcEarliestDates.set(calc.name, earliestDates.absoluteEarliest); continue; }
27
- const latestDep = new Date(Math.max(...deps.map(d => earliestDates[d]?.getTime() || 0)));
28
- const calcDate = calc.isHistorical ? new Date(latestDep.getTime() + 86400000) : latestDep; // +1 day if historical
29
- calcEarliestDates.set(calc.name, calcDate);
30
- logger.log('TRACE', `[PassRunner] ${calc.name}: earliest=${calcDate.toISOString().slice(0,10)}`); }
28
+
29
+ for (const calc of calcsInThisPass) {
30
+ const deps = calc.rootDataDependencies || [];
31
+
32
+ if (!deps.length)
33
+ { calcEarliestDates.set(calc.name, earliestDates.absoluteEarliest); continue; }
34
+
35
+ const latestDep = new Date(Math.max(...deps.map(d => earliestDates[d]?.getTime() || 0)));
36
+ const calcDate = calc.isHistorical
37
+ ? new Date(latestDep.getTime() + 86400000)
38
+ : latestDep;
39
+
40
+ calcEarliestDates.set(calc.name, calcDate);
41
+ }
31
42
 
32
43
  const passEarliestDate = new Date(Math.min(...Array.from(calcEarliestDates.values()).map(d => d.getTime())));
33
- logger.log('INFO', `[PassRunner] Pass ${passToRun} analysis: Total calcs=${calcsInThisPass.length}, can start from ${passEarliestDate.toISOString().slice(0,10)}`);
34
- const endDateUTC = new Date(Date.UTC(new Date().getUTCFullYear(), new Date().getUTCMonth(), new Date().getUTCDate() - 1));
44
+ const endDateUTC = new Date(Date.UTC(new Date().getUTCFullYear(), new Date().getUTCMonth(), new Date().getUTCDate() - 1));
35
45
  const allExpectedDates = getExpectedDateStrings(passEarliestDate, endDateUTC);
36
- const standardCalcs = calcsInThisPass.filter(c => c.type === 'standard');
37
- const metaCalcs = calcsInThisPass.filter(c => c.type === 'meta');
38
- const checkDeps = (calc, rootData, existingResults, dateToProcess) => { if (existingResults[calc.name]) return false;
39
- const earliest = calcEarliestDates.get(calc.name);
40
- if (earliest && dateToProcess < earliest) return false;
46
+ const standardCalcs = calcsInThisPass.filter(c => c.type === 'standard');
47
+ const metaCalcs = calcsInThisPass.filter(c => c.type === 'meta');
48
+
49
+ const checkDeps = (calc, rootData, existingResults, dateToProcess) => {
50
+ if (existingResults[calc.name])
51
+ return false;
41
52
 
42
- const missingRoot = (calc.rootDataDependencies || []).filter(dep => !rootData.status[`has${dep[0].toUpperCase() + dep.slice(1)}`]);
43
- if (missingRoot.length) return false;
53
+ const earliest = calcEarliestDates.get(calc.name);
44
54
 
45
- if (calc.type === 'meta') { const missingComputed = (calc.dependencies || []).filter(d => !existingResults[d]); if (missingComputed.length) return false; } return true; };
55
+ if (earliest && dateToProcess < earliest)
56
+ return false;
57
+
58
+ const missingRoot = (calc.rootDataDependencies || []).filter(dep => !rootData.status[`has${dep[0].toUpperCase() + dep.slice(1)}`]);
59
+
60
+ if (missingRoot.length)
61
+ return false;
62
+
63
+ if (calc.type === 'meta')
64
+ { const missingComputed = (calc.dependencies || []).filter(d => !existingResults[d]);
65
+ if (missingComputed.length)
66
+ return false; }
67
+ return true;
68
+ };
46
69
 
47
70
  const processDate = async (dateStr) => {
48
71
  const dateToProcess = new Date(dateStr + 'T00:00:00Z');
49
72
  try {
50
73
  const rootData = await checkRootDataAvailability(dateStr, config, dependencies, earliestDates);
51
74
  if (!rootData) return logger.log('WARN', `[PassRunner] Skipping ${dateStr}: No root data.`);
52
- const existingResults = await fetchExistingResults(dateStr, calcsInThisPass, computationManifest, config, dependencies);
75
+
76
+ // 1. Fetch TODAY'S results (Check what is already done)
77
+ const existingResults = await fetchExistingResults(dateStr, calcsInThisPass, computationManifest, config, dependencies, false);
78
+
79
+ // 2. Fetch YESTERDAY'S results (For State Persistence) We calculate T-1 date string
80
+ const prevDate = new Date(dateToProcess); prevDate.setUTCDate(prevDate.getUTCDate() - 1);
81
+ const prevDateStr = prevDate.toISOString().slice(0, 10);
82
+
83
+ // We pass 'true' to includeSelf, because we need the calc's OWN history (e.g. mimetic-latency needs previous mimetic-latency)
84
+ const previousResults = await fetchExistingResults(prevDateStr, calcsInThisPass, computationManifest, config, dependencies, true);
85
+
53
86
  const standardToRun = standardCalcs.filter(c => checkDeps(c, rootData, existingResults, dateToProcess));
54
87
  const metaToRun = metaCalcs.filter(c => checkDeps(c, rootData, existingResults, dateToProcess));
88
+
55
89
  if (!standardToRun.length && !metaToRun.length) return logger.log('INFO', `[PassRunner] All calcs complete for ${dateStr}. Skipping.`);
90
+
56
91
  logger.log('INFO', `[PassRunner] Running ${dateStr}: ${standardToRun.length} standard, ${metaToRun.length} meta`);
57
92
 
58
- // --- THIS IS THE CHANGE ---
59
- // 'existingResults' (which is the test harness's 'precomputedDependencies')
60
- // is now passed to 'runStandardComputationPass'.
61
- if (standardToRun.length) await runStandardComputationPass(dateToProcess, standardToRun, `Pass ${passToRun} (Standard)`, config, dependencies, rootData, existingResults);
62
- // --- END CHANGE ---
63
-
64
- if (metaToRun.length) await runMetaComputationPass(dateToProcess, metaToRun, `Pass ${passToRun} (Meta)`, config, dependencies, existingResults, rootData);
93
+ // Pass 'previousResults' to the runners
94
+ if (standardToRun.length) await runStandardComputationPass(dateToProcess, standardToRun, `Pass ${passToRun} (Standard)`, config, dependencies, rootData, existingResults, previousResults);
95
+ if (metaToRun.length) await runMetaComputationPass(dateToProcess, metaToRun, `Pass ${passToRun} (Meta)`, config, dependencies, existingResults, previousResults, rootData);
96
+
65
97
  } catch (err) { logger.log('ERROR', `[PassRunner] FAILED Pass ${passToRun} for ${dateStr}`, { errorMessage: err.message, stack: err.stack }); }
66
98
  };
67
99
 
68
- for (let i = 0; i < allExpectedDates.length; i += PARALLEL_BATCH_SIZE) { const batch = allExpectedDates.slice(i, i + PARALLEL_BATCH_SIZE);
69
- logger.log('INFO', `[PassRunner] Processing batch ${Math.floor(i / PARALLEL_BATCH_SIZE) + 1}/${Math.ceil(allExpectedDates.length / PARALLEL_BATCH_SIZE)} (Dates: ${batch[0]}...${batch[batch.length-1]})`);
70
- await Promise.all(batch.map(processDate)); }
100
+ for (let i = 0; i < allExpectedDates.length; i += PARALLEL_BATCH_SIZE) {
101
+ const batch = allExpectedDates.slice(i, i + PARALLEL_BATCH_SIZE);
102
+ await Promise.all(batch.map(processDate));
103
+ }
71
104
  logger.log('INFO', `[PassRunner] Pass ${passToRun} orchestration finished.`);
72
105
  }
73
106