bulltrackers-module 1.0.222 → 1.0.223
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.
|
@@ -68,7 +68,7 @@ async function runDateComputation(dateStr, passToRun, calcsInThisPass, config, d
|
|
|
68
68
|
const { logger } = dependencies;
|
|
69
69
|
const dateToProcess = new Date(dateStr + 'T00:00:00Z');
|
|
70
70
|
|
|
71
|
-
// 1. Version Check
|
|
71
|
+
// 1. Version Check
|
|
72
72
|
const dailyStatus = await fetchComputationStatus(dateStr, config, dependencies);
|
|
73
73
|
const calcsToAttempt = [];
|
|
74
74
|
|
|
@@ -78,16 +78,13 @@ async function runDateComputation(dateStr, passToRun, calcsInThisPass, config, d
|
|
|
78
78
|
const currentHash = calc.hash;
|
|
79
79
|
|
|
80
80
|
if (!storedStatus) {
|
|
81
|
-
// New calculation
|
|
82
81
|
calcsToAttempt.push(calc); continue;
|
|
83
82
|
}
|
|
84
83
|
if (typeof storedStatus === 'string' && currentHash && storedStatus !== currentHash) {
|
|
85
|
-
// Code changed, must re-run
|
|
86
84
|
logger.log('INFO', `[Versioning] ${cName}: Code Changed.`);
|
|
87
85
|
calcsToAttempt.push(calc); continue;
|
|
88
86
|
}
|
|
89
87
|
if (storedStatus === true && currentHash) {
|
|
90
|
-
// Migrating legacy status
|
|
91
88
|
logger.log('INFO', `[Versioning] ${cName}: Upgrading legacy status.`);
|
|
92
89
|
calcsToAttempt.push(calc); continue;
|
|
93
90
|
}
|
|
@@ -108,12 +105,12 @@ async function runDateComputation(dateStr, passToRun, calcsInThisPass, config, d
|
|
|
108
105
|
if (!rootData) { logger.log('INFO', `[DateRunner] Root data missing for ${dateStr}. Skipping.`); return null; }
|
|
109
106
|
|
|
110
107
|
// 3. Viability Check (Smart Execution Map)
|
|
111
|
-
// Filter candidates: Remove any calculation that misses Root Data OR Dependencies
|
|
112
|
-
|
|
108
|
+
// Filter candidates: Remove any calculation that misses Root Data OR Matches Stale Dependencies
|
|
109
|
+
// PASSED: computationManifest (needed for hash lookup)
|
|
110
|
+
const runnableCalcs = getViableCalculations(calcsToAttempt, computationManifest, rootData.status, dailyStatus);
|
|
113
111
|
|
|
114
112
|
if (!runnableCalcs.length) {
|
|
115
|
-
//
|
|
116
|
-
// logger.log('INFO', `[DateRunner] ${dateStr}: Candidates pruned due to missing deps/data.`);
|
|
113
|
+
// logger.log('INFO', `[DateRunner] ${dateStr}: Candidates pruned due to missing deps/data/stale hashes.`);
|
|
117
114
|
return null;
|
|
118
115
|
}
|
|
119
116
|
|
|
@@ -125,7 +122,6 @@ async function runDateComputation(dateStr, passToRun, calcsInThisPass, config, d
|
|
|
125
122
|
|
|
126
123
|
try {
|
|
127
124
|
const calcsRunning = [...standardToRun, ...metaToRun];
|
|
128
|
-
// Fetch dependencies for the *runnable* calculations
|
|
129
125
|
const existingResults = await fetchExistingResults(dateStr, calcsRunning, computationManifest, config, dependencies, false);
|
|
130
126
|
const prevDate = new Date(dateToProcess); prevDate.setUTCDate(prevDate.getUTCDate() - 1);
|
|
131
127
|
const prevDateStr = prevDate.toISOString().slice(0, 10);
|
|
@@ -26,31 +26,46 @@ function checkRootDependencies(calcManifest, rootDataStatus) {
|
|
|
26
26
|
* Filters candidates to only those that are strictly "viable" to run.
|
|
27
27
|
* A calculation is Viable if:
|
|
28
28
|
* 1. All required Root Data is present.
|
|
29
|
-
* 2. All required Dependencies
|
|
29
|
+
* 2. All required Dependencies are present AND their stored hash matches their current code hash.
|
|
30
30
|
* * @param {Array} candidates - Calculations attempting to run in this pass.
|
|
31
|
+
* @param {Array} fullManifest - The complete manifest (to lookup dependency current hashes).
|
|
31
32
|
* @param {Object} rootDataStatus - { hasPortfolio: bool, hasPrices: bool... }
|
|
32
33
|
* @param {Object} dailyStatus - Map of { "calc-name": "hash" } for completed items.
|
|
33
34
|
*/
|
|
34
|
-
function getViableCalculations(candidates, rootDataStatus, dailyStatus) {
|
|
35
|
+
function getViableCalculations(candidates, fullManifest, rootDataStatus, dailyStatus) {
|
|
35
36
|
const viable = [];
|
|
37
|
+
const manifestMap = new Map(fullManifest.map(c => [normalizeName(c.name), c]));
|
|
36
38
|
|
|
37
39
|
for (const calc of candidates) {
|
|
38
40
|
// 1. Check Root Data
|
|
39
41
|
const rootCheck = checkRootDependencies(calc, rootDataStatus);
|
|
40
42
|
if (!rootCheck.canRun) {
|
|
41
|
-
// Root data missing -> Impossible
|
|
42
|
-
continue;
|
|
43
|
+
continue; // Root data missing -> Impossible.
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
// 2. Check Dependencies
|
|
46
|
+
// 2. Check Dependencies (Strict Hash Verification)
|
|
46
47
|
let dependenciesMet = true;
|
|
47
48
|
if (calc.dependencies && calc.dependencies.length > 0) {
|
|
48
49
|
for (const depName of calc.dependencies) {
|
|
49
50
|
const normDep = normalizeName(depName);
|
|
51
|
+
const storedHash = dailyStatus[normDep];
|
|
52
|
+
const depManifest = manifestMap.get(normDep);
|
|
50
53
|
|
|
51
|
-
// If
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
// If dependency is missing from manifest, we can't verify it (shouldn't happen)
|
|
55
|
+
if (!depManifest) {
|
|
56
|
+
dependenciesMet = false;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// CHECK: Does the dependency exist in DB?
|
|
61
|
+
if (!storedHash) {
|
|
62
|
+
dependenciesMet = false;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// CHECK: Does the stored hash match the current code hash?
|
|
67
|
+
// This prevents running on stale data if a dependency failed to update.
|
|
68
|
+
if (storedHash !== depManifest.hash) {
|
|
54
69
|
dependenciesMet = false;
|
|
55
70
|
break;
|
|
56
71
|
}
|
|
@@ -75,7 +90,6 @@ async function checkRootDataAvailability(dateStr, config, dependencies, earliest
|
|
|
75
90
|
|
|
76
91
|
try {
|
|
77
92
|
const tasks = [];
|
|
78
|
-
// Only check data sources if the date is after the earliest known data point
|
|
79
93
|
if (dateToProcess >= earliestDates.portfolio) {
|
|
80
94
|
tasks.push(getPortfolioPartRefs(config, dependencies, dateStr).then(r => { portfolioRefs = r; hasPortfolio = !!r.length; }));
|
|
81
95
|
}
|
|
@@ -94,7 +108,6 @@ async function checkRootDataAvailability(dateStr, config, dependencies, earliest
|
|
|
94
108
|
|
|
95
109
|
await Promise.all(tasks);
|
|
96
110
|
|
|
97
|
-
// If ABSOLUTELY NO data exists, we can return null early
|
|
98
111
|
if (!(hasPortfolio || hasInsights || hasSocial || hasHistory || hasPrices)) return null;
|
|
99
112
|
|
|
100
113
|
return {
|
|
@@ -103,7 +116,7 @@ async function checkRootDataAvailability(dateStr, config, dependencies, earliest
|
|
|
103
116
|
todayInsights: insightsData,
|
|
104
117
|
todaySocialPostInsights: socialData,
|
|
105
118
|
status: { hasPortfolio, hasInsights, hasSocial, hasHistory, hasPrices },
|
|
106
|
-
yesterdayPortfolioRefs: null
|
|
119
|
+
yesterdayPortfolioRefs: null
|
|
107
120
|
};
|
|
108
121
|
} catch (err) {
|
|
109
122
|
logger.log('ERROR', `Error checking data: ${err.message}`);
|
|
@@ -111,10 +124,6 @@ async function checkRootDataAvailability(dateStr, config, dependencies, earliest
|
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
126
|
|
|
114
|
-
/**
|
|
115
|
-
* Checks if any price data exists in the collection.
|
|
116
|
-
* Note: Uses a lightweight limit(1) query.
|
|
117
|
-
*/
|
|
118
127
|
async function checkPriceAvailability(config, db) {
|
|
119
128
|
try {
|
|
120
129
|
const collection = config.priceCollection || 'asset_prices';
|