bulltrackers-module 1.0.240 → 1.0.241
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,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Main Orchestrator. Coordinates the topological execution.
|
|
3
3
|
* UPDATED: Exports analyzeDateExecution for Build Reporting tools.
|
|
4
|
+
* UPDATED: Uses centralized DEFINITIVE_EARLIEST_DATES.
|
|
4
5
|
*/
|
|
5
|
-
const { normalizeName }
|
|
6
|
+
const { normalizeName, DEFINITIVE_EARLIEST_DATES } = require('./utils/utils');
|
|
6
7
|
const { checkRootDataAvailability } = require('./data/AvailabilityChecker');
|
|
7
8
|
const { fetchExistingResults } = require('./data/DependencyFetcher');
|
|
8
9
|
const { fetchComputationStatus, updateComputationStatus } = require('./persistence/StatusRepository');
|
|
@@ -123,6 +124,7 @@ function analyzeDateExecution(dateStr, calcsInPass, rootDataStatus, dailyStatus,
|
|
|
123
124
|
report.runnable.push(calc);
|
|
124
125
|
} else if (storedHash !== currentHash) {
|
|
125
126
|
// Hash Mismatch (Code Changed).
|
|
127
|
+
// Pass migration info here too, in case category ALSO changed.
|
|
126
128
|
report.reRuns.push({
|
|
127
129
|
name: cName,
|
|
128
130
|
oldHash: storedHash,
|
|
@@ -155,15 +157,8 @@ async function runDateComputation(dateStr, passToRun, calcsInThisPass, config, d
|
|
|
155
157
|
const dailyStatus = await fetchComputationStatus(dateStr, config, dependencies);
|
|
156
158
|
|
|
157
159
|
// 2. Check Data Availability
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
history: new Date('2025-11-05T00:00:00Z'),
|
|
161
|
-
social: new Date('2025-10-30T00:00:00Z'),
|
|
162
|
-
insights: new Date('2025-08-26T00:00:00Z'),
|
|
163
|
-
price: new Date('2025-08-01T00:00:00Z')
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const rootData = await checkRootDataAvailability(dateStr, config, dependencies, earliestDates);
|
|
160
|
+
// [UPDATE] Using centralized dates to ensure consistency with BuildReporter
|
|
161
|
+
const rootData = await checkRootDataAvailability(dateStr, config, dependencies, DEFINITIVE_EARLIEST_DATES);
|
|
167
162
|
const rootStatus = rootData ? rootData.status : { hasPortfolio: false, hasPrices: false, hasInsights: false, hasSocial: false, hasHistory: false };
|
|
168
163
|
|
|
169
164
|
// 3. ANALYZE EXECUTION
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FILENAME: bulltrackers-module/functions/computation-system/helpers/computation_dispatcher.js
|
|
3
3
|
* PURPOSE: Dispatches granular computation tasks (1 task = 1 calculation/date).
|
|
4
|
-
* UPDATED: Implements "Atomic Task Dispatch"
|
|
4
|
+
* UPDATED: Implements "Atomic Task Dispatch" and uses DEFINITIVE dates to prevent waste.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const { getExpectedDateStrings, normalizeName } = require('../utils/utils.js');
|
|
7
|
+
const { getExpectedDateStrings, normalizeName, DEFINITIVE_EARLIEST_DATES } = require('../utils/utils.js');
|
|
8
8
|
const { groupByPass } = require('../WorkflowOrchestrator.js');
|
|
9
9
|
const { PubSubUtils } = require('../../core/utils/pubsub_utils');
|
|
10
10
|
|
|
@@ -32,16 +32,9 @@ async function dispatchComputationPass(config, dependencies, computationManifest
|
|
|
32
32
|
logger.log('INFO', `[Dispatcher] Target Calculations: [${calcNames.join(', ')}]`);
|
|
33
33
|
|
|
34
34
|
// 2. Determine Date Range
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
history: new Date('2025-11-05T00:00:00Z'),
|
|
39
|
-
social: new Date('2025-10-30T00:00:00Z'),
|
|
40
|
-
insights: new Date('2025-08-26T00:00:00Z'),
|
|
41
|
-
price: new Date('2025-08-01T00:00:00Z')
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const passEarliestDate = Object.values(earliestDates).reduce((a, b) => a < b ? a : b);
|
|
35
|
+
// [UPDATE] Using DEFINITIVE_EARLIEST_DATES ensures we don't dispatch tasks
|
|
36
|
+
// for years before data existed (e.g. 2023), saving massive Pub/Sub costs.
|
|
37
|
+
const passEarliestDate = Object.values(DEFINITIVE_EARLIEST_DATES).reduce((a, b) => a < b ? a : b);
|
|
45
38
|
const endDateUTC = new Date(Date.UTC(new Date().getUTCFullYear(), new Date().getUTCMonth(), new Date().getUTCDate() - 1));
|
|
46
39
|
const allExpectedDates = getExpectedDateStrings(passEarliestDate, endDateUTC);
|
|
47
40
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Build Reporter & Auto-Runner.
|
|
3
3
|
* Generates a "Pre-Flight" report of what the computation system WILL do.
|
|
4
|
-
* Simulates execution logic (Hash Mismatches)
|
|
4
|
+
* Simulates execution logic (Hash Mismatches) respecting DEFINITIVE start dates.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { analyzeDateExecution } = require('../WorkflowOrchestrator');
|
|
8
8
|
const { fetchComputationStatus } = require('../persistence/StatusRepository');
|
|
9
|
-
const { normalizeName, getExpectedDateStrings } = require('../utils/utils');
|
|
9
|
+
const { normalizeName, getExpectedDateStrings, DEFINITIVE_EARLIEST_DATES } = require('../utils/utils');
|
|
10
10
|
const { FieldValue } = require('@google-cloud/firestore');
|
|
11
11
|
|
|
12
12
|
// Attempt to load package.json to get version. Path depends on where this is invoked.
|
|
13
|
-
let packageVersion = '1.0.
|
|
13
|
+
let packageVersion = '1.0.300';
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -33,6 +33,7 @@ async function ensureBuildReport(config, dependencies, manifest) {
|
|
|
33
33
|
logger.log('INFO', `[BuildReporter] 🚀 New Version Detected (${buildId}). Auto-running Pre-flight Report...`);
|
|
34
34
|
// We do NOT await this in the main thread if called during init,
|
|
35
35
|
// but here we are in an async function so we proceed.
|
|
36
|
+
// Defaulting to 90 days for the auto-run to capture full historical impact
|
|
36
37
|
await generateBuildReport(config, dependencies, manifest, 90, buildId);
|
|
37
38
|
|
|
38
39
|
} catch (e) {
|
|
@@ -45,7 +46,7 @@ async function ensureBuildReport(config, dependencies, manifest) {
|
|
|
45
46
|
* @param {object} config
|
|
46
47
|
* @param {object} dependencies
|
|
47
48
|
* @param {Array} manifest
|
|
48
|
-
* @param {number} daysBack - Days to simulate (
|
|
49
|
+
* @param {number} daysBack - Days to simulate (Default 90)
|
|
49
50
|
* @param {string} customBuildId - Optional ID override
|
|
50
51
|
*/
|
|
51
52
|
async function generateBuildReport(config, dependencies, manifest, daysBack = 90, customBuildId = null) {
|
|
@@ -80,15 +81,18 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
80
81
|
// A. Fetch REAL status from DB (What ran previously?)
|
|
81
82
|
const dailyStatus = await fetchComputationStatus(dateStr, config, dependencies);
|
|
82
83
|
|
|
83
|
-
// B. MOCK Root Data
|
|
84
|
-
// We
|
|
85
|
-
//
|
|
84
|
+
// B. SMART MOCK Root Data
|
|
85
|
+
// We only mock "True" if the date is logically valid for that data type.
|
|
86
|
+
// This prevents impossible calculations (e.g. 2025-09-11 requiring History which starts 2025-11-05)
|
|
87
|
+
// from showing as "WillRun".
|
|
88
|
+
const dateObj = new Date(dateStr + 'T00:00:00Z');
|
|
89
|
+
|
|
86
90
|
const mockRootDataStatus = {
|
|
87
|
-
hasPortfolio:
|
|
88
|
-
|
|
89
|
-
hasSocial:
|
|
90
|
-
|
|
91
|
-
hasPrices:
|
|
91
|
+
hasPortfolio: dateObj >= DEFINITIVE_EARLIEST_DATES.portfolio,
|
|
92
|
+
hasHistory: dateObj >= DEFINITIVE_EARLIEST_DATES.history,
|
|
93
|
+
hasSocial: dateObj >= DEFINITIVE_EARLIEST_DATES.social,
|
|
94
|
+
hasInsights: dateObj >= DEFINITIVE_EARLIEST_DATES.insights,
|
|
95
|
+
hasPrices: dateObj >= DEFINITIVE_EARLIEST_DATES.price
|
|
92
96
|
};
|
|
93
97
|
|
|
94
98
|
// C. Run Logic Analysis
|
|
@@ -99,8 +103,8 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
99
103
|
const dateSummary = {
|
|
100
104
|
willRun: [],
|
|
101
105
|
willReRun: [],
|
|
102
|
-
blocked: []
|
|
103
|
-
|
|
106
|
+
blocked: [],
|
|
107
|
+
impossible: [] // New explicit category
|
|
104
108
|
};
|
|
105
109
|
|
|
106
110
|
// -- Runnable (New) --
|
|
@@ -121,16 +125,24 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
|
|
|
121
125
|
dateSummary.willReRun.push({ name: item.name, reason, details });
|
|
122
126
|
});
|
|
123
127
|
|
|
124
|
-
// --
|
|
128
|
+
// -- Impossible (Permanent) --
|
|
129
|
+
// Mapped from analysis.impossible (Missing Root Data or Explicit Impossible)
|
|
125
130
|
analysis.impossible.forEach(item => {
|
|
126
|
-
dateSummary.
|
|
131
|
+
dateSummary.impossible.push({ name: item.name, reason: item.reason }); // e.g. "Permanently Impossible"
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// -- Blocked (Retriable) --
|
|
135
|
+
// Mapped from analysis.blocked (Waiting for data) AND failedDependency
|
|
136
|
+
analysis.blocked.forEach(item => {
|
|
137
|
+
dateSummary.blocked.push({ name: item.name, reason: item.reason });
|
|
127
138
|
});
|
|
128
139
|
analysis.failedDependency.forEach(item => {
|
|
140
|
+
// If a dependency failed, it's blocked, not necessarily impossible (unless dependency is impossible)
|
|
129
141
|
dateSummary.blocked.push({ name: item.name, reason: `Dependency Missing: ${item.missing.join(', ')}` });
|
|
130
142
|
});
|
|
131
143
|
|
|
132
144
|
// Only add date to report if something interesting is happening
|
|
133
|
-
if (dateSummary.willRun.length || dateSummary.willReRun.length || dateSummary.blocked.length) {
|
|
145
|
+
if (dateSummary.willRun.length || dateSummary.willReRun.length || dateSummary.blocked.length || dateSummary.impossible.length) {
|
|
134
146
|
reportData.dates[dateStr] = dateSummary;
|
|
135
147
|
totalNew += dateSummary.willRun.length;
|
|
136
148
|
totalReRuns += dateSummary.willReRun.length;
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
const { FieldValue, FieldPath } = require('@google-cloud/firestore');
|
|
6
6
|
const crypto = require('crypto');
|
|
7
7
|
|
|
8
|
+
// [NEW] Single Source of Truth for Data Availability
|
|
9
|
+
const DEFINITIVE_EARLIEST_DATES = {
|
|
10
|
+
portfolio: new Date('2025-09-25T00:00:00Z'),
|
|
11
|
+
history: new Date('2025-11-05T00:00:00Z'),
|
|
12
|
+
social: new Date('2025-10-30T00:00:00Z'),
|
|
13
|
+
insights: new Date('2025-08-26T00:00:00Z'),
|
|
14
|
+
price: new Date('2025-08-01T00:00:00Z')
|
|
15
|
+
};
|
|
16
|
+
|
|
8
17
|
/** Stage 1: Normalize a calculation name to kebab-case */
|
|
9
18
|
function normalizeName(name) { return name.replace(/_/g, '-'); }
|
|
10
19
|
|
|
@@ -211,5 +220,6 @@ module.exports = {
|
|
|
211
220
|
getExpectedDateStrings,
|
|
212
221
|
getEarliestDataDates,
|
|
213
222
|
generateCodeHash,
|
|
214
|
-
withRetry
|
|
223
|
+
withRetry,
|
|
224
|
+
DEFINITIVE_EARLIEST_DATES // [NEW EXPORT]
|
|
215
225
|
};
|