bulltrackers-module 1.0.237 → 1.0.238

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,7 +1,6 @@
1
1
  /**
2
2
  * @fileoverview Main Orchestrator. Coordinates the topological execution.
3
- * UPDATED: Detects Category changes to trigger migration/cleanup.
4
- * FIX: Decouples migration detection from hash verification to handle simultaneous code & category changes.
3
+ * UPDATED: Exports analyzeDateExecution for Build Reporting tools.
5
4
  */
6
5
  const { normalizeName } = require('./utils/utils');
7
6
  const { checkRootDataAvailability } = require('./data/AvailabilityChecker');
@@ -124,7 +123,6 @@ function analyzeDateExecution(dateStr, calcsInPass, rootDataStatus, dailyStatus,
124
123
  report.runnable.push(calc);
125
124
  } else if (storedHash !== currentHash) {
126
125
  // Hash Mismatch (Code Changed).
127
- // Pass migration info here too, in case category ALSO changed.
128
126
  report.reRuns.push({
129
127
  name: cName,
130
128
  oldHash: storedHash,
@@ -268,4 +266,4 @@ async function runDateComputation(dateStr, passToRun, calcsInThisPass, config, d
268
266
  return { date: dateStr, updates: dateUpdates };
269
267
  }
270
268
 
271
- module.exports = { runDateComputation, groupByPass };
269
+ module.exports = { runDateComputation, groupByPass, analyzeDateExecution };
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @fileoverview Build Reporter & Auto-Runner.
3
+ * Generates a "Pre-Flight" report of what the computation system WILL do.
4
+ * Simulates execution logic (Hash Mismatches) assuming perfect data availability.
5
+ */
6
+
7
+ const { analyzeDateExecution } = require('../WorkflowOrchestrator');
8
+ const { fetchComputationStatus } = require('../persistence/StatusRepository');
9
+ const { normalizeName, getExpectedDateStrings } = require('../utils/utils');
10
+ const { FieldValue } = require('@google-cloud/firestore');
11
+
12
+ // Attempt to load package.json to get version. Path depends on where this is invoked.
13
+ let packageVersion = '1.0.237';
14
+
15
+
16
+ /**
17
+ * AUTO-RUN ENTRY POINT
18
+ * Checks if a report for the current version exists. If not, runs it.
19
+ * Designed to be called "Fire-and-Forget" at system init.
20
+ */
21
+ async function ensureBuildReport(config, dependencies, manifest) {
22
+ const { db, logger } = dependencies;
23
+ const buildId = `v${packageVersion}`;
24
+ const reportRef = db.collection('computation_build_records').doc(buildId);
25
+
26
+ try {
27
+ const doc = await reportRef.get();
28
+ if (doc.exists) {
29
+ logger.log('INFO', `[BuildReporter] ✅ Pre-flight check for ${buildId} already exists. Skipping.`);
30
+ return;
31
+ }
32
+
33
+ logger.log('INFO', `[BuildReporter] 🚀 New Version Detected (${buildId}). Auto-running Pre-flight Report...`);
34
+ // We do NOT await this in the main thread if called during init,
35
+ // but here we are in an async function so we proceed.
36
+ await generateBuildReport(config, dependencies, manifest, 7, buildId);
37
+
38
+ } catch (e) {
39
+ logger.log('ERROR', `[BuildReporter] Auto-run check failed: ${e.message}`);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Generates the report and saves to Firestore.
45
+ * @param {object} config
46
+ * @param {object} dependencies
47
+ * @param {Array} manifest
48
+ * @param {number} daysBack - Days to simulate (default 7)
49
+ * @param {string} customBuildId - Optional ID override
50
+ */
51
+ async function generateBuildReport(config, dependencies, manifest, daysBack = 7, customBuildId = null) {
52
+ const { db, logger } = dependencies;
53
+ const buildId = customBuildId || `manual_${Date.now()}`;
54
+
55
+ logger.log('INFO', `[BuildReporter] Generating Build Report: ${buildId} (Scope: ${daysBack} days)...`);
56
+
57
+ // 1. Determine Date Range
58
+ const today = new Date();
59
+ const startDate = new Date();
60
+ startDate.setDate(today.getDate() - daysBack);
61
+
62
+ // We check UP TO yesterday usually, as today might be partial.
63
+ // But let's check today too to see immediate effects.
64
+ const datesToCheck = getExpectedDateStrings(startDate, today);
65
+ const manifestMap = new Map(manifest.map(c => [normalizeName(c.name), c]));
66
+
67
+ const reportData = {
68
+ buildId,
69
+ version: packageVersion,
70
+ generatedAt: new Date().toISOString(),
71
+ summary: {},
72
+ dates: {}
73
+ };
74
+
75
+ let totalReRuns = 0;
76
+ let totalNew = 0;
77
+
78
+ // 2. Iterate Dates & Simulate
79
+ for (const dateStr of datesToCheck) {
80
+ // A. Fetch REAL status from DB (What ran previously?)
81
+ const dailyStatus = await fetchComputationStatus(dateStr, config, dependencies);
82
+
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?"
86
+ const mockRootDataStatus = {
87
+ hasPortfolio: true,
88
+ hasInsights: true,
89
+ hasSocial: true,
90
+ hasHistory: true,
91
+ hasPrices: true
92
+ };
93
+
94
+ // C. Run Logic Analysis
95
+ // Pass ENTIRE manifest to see global state
96
+ const analysis = analyzeDateExecution(dateStr, manifest, mockRootDataStatus, dailyStatus, manifestMap);
97
+
98
+ // D. Format Findings
99
+ const dateSummary = {
100
+ willRun: [],
101
+ willReRun: [],
102
+ blocked: []
103
+ // We omit 'skipped' to save space unless explicitly IMPOSSIBLE
104
+ };
105
+
106
+ // -- Runnable (New) --
107
+ analysis.runnable.forEach(item => {
108
+ dateSummary.willRun.push({ name: item.name, reason: "New / No Previous Record" });
109
+ });
110
+
111
+ // -- Re-Runs (Hash Mismatch / Migration) --
112
+ analysis.reRuns.forEach(item => {
113
+ let reason = "Hash Mismatch";
114
+ let details = `Old: ${item.oldHash?.substring(0,6)}... New: ${item.newHash?.substring(0,6)}...`;
115
+
116
+ if (item.previousCategory) {
117
+ reason = "Migration";
118
+ details = `Moving ${item.previousCategory} -> ${item.newCategory}`;
119
+ }
120
+
121
+ dateSummary.willReRun.push({ name: item.name, reason, details });
122
+ });
123
+
124
+ // -- Blocked / Impossible --
125
+ analysis.impossible.forEach(item => {
126
+ dateSummary.blocked.push({ name: item.name, reason: item.reason }); // e.g. "Permanently Impossible"
127
+ });
128
+ analysis.failedDependency.forEach(item => {
129
+ dateSummary.blocked.push({ name: item.name, reason: `Dependency Missing: ${item.missing.join(', ')}` });
130
+ });
131
+
132
+ // Only add date to report if something interesting is happening
133
+ if (dateSummary.willRun.length || dateSummary.willReRun.length || dateSummary.blocked.length) {
134
+ reportData.dates[dateStr] = dateSummary;
135
+ totalNew += dateSummary.willRun.length;
136
+ totalReRuns += dateSummary.willReRun.length;
137
+ }
138
+ }
139
+
140
+ reportData.summary = { totalReRuns, totalNew, scanRange: `${datesToCheck[0]} to ${datesToCheck[datesToCheck.length-1]}` };
141
+
142
+ // 3. Store Report
143
+ const reportRef = db.collection('computation_build_records').doc(buildId);
144
+ await reportRef.set(reportData);
145
+
146
+ // 4. Update 'latest' pointer
147
+ await db.collection('computation_build_records').doc('latest').set({
148
+ ...reportData,
149
+ note: "Latest build report pointer."
150
+ });
151
+
152
+ logger.log('SUCCESS', `[BuildReporter] Report ${buildId} saved. Re-runs: ${totalReRuns}, New: ${totalNew}.`);
153
+
154
+ return {
155
+ success: true,
156
+ reportId: buildId,
157
+ summary: reportData.summary
158
+ };
159
+ }
160
+
161
+ module.exports = { ensureBuildReport, generateBuildReport };
package/index.js CHANGED
@@ -30,6 +30,9 @@ const { build: buildManifest } = require('./functions
30
30
  const { runDateComputation: runComputationPass } = require('./functions/computation-system/WorkflowOrchestrator');
31
31
  const { dispatchComputationPass } = require('./functions/computation-system/helpers/computation_dispatcher');
32
32
  const { handleComputationTask } = require('./functions/computation-system/helpers/computation_worker');
33
+ // [NEW] Import Report Tools
34
+ const { ensureBuildReport, generateBuildReport } = require('./functions/computation-system/tools/BuildReporter');
35
+
33
36
  const dataLoader = require('./functions/computation-system/utils/data_loader');
34
37
  const computationUtils = require('./functions/computation-system/utils/utils');
35
38
 
@@ -87,6 +90,9 @@ const computationSystem = {
87
90
  dataLoader,
88
91
  computationUtils,
89
92
  buildManifest,
93
+ // [NEW] Export Tools
94
+ ensureBuildReport,
95
+ generateBuildReport,
90
96
  };
91
97
 
92
98
  const api = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.237",
3
+ "version": "1.0.238",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [