bulltrackers-module 1.0.239 → 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 } = require('./utils/utils');
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
- const earliestDates = {
159
- portfolio: new Date('2025-09-25T00:00:00Z'),
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" for maximum reliability.
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
- // (You can make this dynamic or config-driven)
36
- const earliestDates = {
37
- portfolio: new Date('2025-09-25T00:00:00Z'),
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,2 +1,2 @@
1
1
  // Change this string to force a global re-computation
2
- module.exports = "v1.0-epoch-1";
2
+ module.exports = "v1.0-epoch-2";
@@ -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) assuming perfect data availability.
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.237';
13
+ let packageVersion = '1.0.300';
14
14
 
15
15
 
16
16
  /**
@@ -33,7 +33,8 @@ 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
- await generateBuildReport(config, dependencies, manifest, 7, buildId);
36
+ // Defaulting to 90 days for the auto-run to capture full historical impact
37
+ await generateBuildReport(config, dependencies, manifest, 90, buildId);
37
38
 
38
39
  } catch (e) {
39
40
  logger.log('ERROR', `[BuildReporter] Auto-run check failed: ${e.message}`);
@@ -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 (default 7)
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 Availability
84
- // We force this to TRUE to prove logic changes.
85
- // We want to know: "IF data exists, would this run?"
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: true,
88
- hasInsights: true,
89
- hasSocial: true,
90
- hasHistory: true,
91
- hasPrices: true
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
- // We omit 'skipped' to save space unless explicitly IMPOSSIBLE
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
- // -- Blocked / Impossible --
128
+ // -- Impossible (Permanent) --
129
+ // Mapped from analysis.impossible (Missing Root Data or Explicit Impossible)
125
130
  analysis.impossible.forEach(item => {
126
- dateSummary.blocked.push({ name: item.name, reason: item.reason }); // e.g. "Permanently Impossible"
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.239",
3
+ "version": "1.0.241",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [