bulltrackers-module 1.0.250 → 1.0.251

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,7 @@
1
1
  /**
2
2
  * @fileoverview Build Reporter & Auto-Runner.
3
3
  * Generates a "Pre-Flight" report of what the computation system WILL do.
4
- * UPDATED: Removed "Smart Mocking" in favor of REAL data availability checks to detect gaps/impossible dates.
4
+ * UPDATED: Now fetches 'prevDailyStatus' to enforce strict historical continuity checks.
5
5
  */
6
6
 
7
7
  const { analyzeDateExecution } = require('../WorkflowOrchestrator');
@@ -88,7 +88,6 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
88
88
 
89
89
  // 2. PARALLEL PROCESSING (Fix for DEADLINE_EXCEEDED)
90
90
  // Run 20 reads in parallel.
91
- // This is now slightly heavier because we verify root data existence, but necessary for accuracy.
92
91
  const limit = pLimit(20);
93
92
 
94
93
  const processingPromises = datesToCheck.map(dateStr => limit(async () => {
@@ -96,9 +95,26 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
96
95
  // A. Fetch REAL status from DB (What ran previously?)
97
96
  const dailyStatus = await fetchComputationStatus(dateStr, config, dependencies);
98
97
 
99
- // B. REAL Root Data Check [FIXED]
100
- // Previously we mocked this based on dates. Now we check if the data ACTUALLY exists.
101
- // This ensures missing social data (even if after the start date) is flagged as IMPOSSIBLE.
98
+ // [NEW] B. Fetch YESTERDAY'S Status (For strict continuity checks)
99
+ let prevDailyStatus = null;
100
+
101
+ // Only fetch if ANY calculation in the manifest is historical
102
+ // (Optimization: In BuildReporter we pass the full manifest, so we check if any exist generally)
103
+ if (manifest.some(c => c.isHistorical)) {
104
+ const prevDate = new Date(dateStr + 'T00:00:00Z');
105
+ prevDate.setUTCDate(prevDate.getUTCDate() - 1);
106
+ const prevDateStr = prevDate.toISOString().slice(0, 10);
107
+
108
+ // Ensure we don't look before the dawn of time
109
+ if (prevDate >= DEFINITIVE_EARLIEST_DATES.absoluteEarliest) {
110
+ prevDailyStatus = await fetchComputationStatus(prevDateStr, config, dependencies);
111
+ } else {
112
+ prevDailyStatus = {}; // Pre-epoch is valid empty context
113
+ }
114
+ }
115
+
116
+ // C. REAL Root Data Check
117
+ // Uses the new Indexer logic (returns null refs, but valid status flags)
102
118
  const availability = await checkRootDataAvailability(dateStr, config, dependencies, DEFINITIVE_EARLIEST_DATES);
103
119
 
104
120
  const rootDataStatus = availability ? availability.status : {
@@ -109,10 +125,11 @@ async function generateBuildReport(config, dependencies, manifest, daysBack = 90
109
125
  hasPrices: false
110
126
  };
111
127
 
112
- // C. Run Logic Analysis
113
- const analysis = analyzeDateExecution(dateStr, manifest, rootDataStatus, dailyStatus, manifestMap);
128
+ // D. Run Logic Analysis
129
+ // Now passes prevDailyStatus to enable the "Blocked if yesterday missing" logic
130
+ const analysis = analyzeDateExecution(dateStr, manifest, rootDataStatus, dailyStatus, manifestMap, prevDailyStatus);
114
131
 
115
- // D. Format Findings
132
+ // E. Format Findings
116
133
  const dateSummary = {
117
134
  willRun: [],
118
135
  willReRun: [],
@@ -10,7 +10,7 @@ const pLimit = require('p-limit');
10
10
  // Hardcoded verification blocks as per logic requirements
11
11
  const CANARY_BLOCK_ID = '19M';
12
12
  const CANARY_PART_ID = 'part_0';
13
- const PRICE_SHARD_ID = 'shard_0';
13
+ const PRICE_SHARD_ID = 'shard_1'; // Shard_1 contains ETH price data, which has 24/7 prices since it's crypto, so if it exists for a given date, system worked for price data, if it doesn't exist, then the system failed for that date, best case assumption.
14
14
 
15
15
  /**
16
16
  * Main pipe: pipe.maintenance.runRootDataIndexer
@@ -28,11 +28,39 @@ exports.runRootDataIndexer = async (config, dependencies) => {
28
28
  // 1. Pre-fetch Price Data Availability (Optimization)
29
29
  // Instead of reading the shard N times, we read it once and map available dates.
30
30
  const priceAvailabilitySet = new Set();
31
+
32
+ // --- DEBUGGING START ---
33
+ logger.log('INFO', `[RootDataIndexer] DEBUG: Attempting to fetch price shard. Collection: "${collections.prices}", Doc ID: "${PRICE_SHARD_ID}"`);
34
+ // --- DEBUGGING END ---
35
+
31
36
  try {
32
37
  const priceShardRef = db.collection(collections.prices).doc(PRICE_SHARD_ID);
33
38
  const priceSnap = await priceShardRef.get();
39
+
34
40
  if (priceSnap.exists) {
35
41
  const data = priceSnap.data();
42
+ const instruments = Object.values(data);
43
+
44
+ // --- DEBUGGING START ---
45
+ logger.log('INFO', `[RootDataIndexer] DEBUG: Shard document found. Contains ${instruments.length} instrument entries.`);
46
+
47
+ if (instruments.length > 0) {
48
+ // Log the structure of the first instrument found to verify schema match
49
+ const sampleKey = Object.keys(data)[0];
50
+ const sampleVal = data[sampleKey];
51
+ logger.log('INFO', `[RootDataIndexer] DEBUG: Sample Instrument Data (ID: ${sampleKey}):`, sampleVal);
52
+
53
+ if (!sampleVal.prices) {
54
+ logger.log('WARN', `[RootDataIndexer] DEBUG: ⚠️ Sample instrument is MISSING the 'prices' field! Available fields: ${Object.keys(sampleVal).join(', ')}`);
55
+ } else {
56
+ const priceKeys = Object.keys(sampleVal.prices);
57
+ logger.log('INFO', `[RootDataIndexer] DEBUG: Sample 'prices' keys found (${priceKeys.length}): [${priceKeys.slice(0, 5).join(', ')}...]`);
58
+ }
59
+ } else {
60
+ logger.log('WARN', '[RootDataIndexer] DEBUG: Shard document exists but appears empty (0 instruments found).');
61
+ }
62
+ // --- DEBUGGING END ---
63
+
36
64
  // Iterate over all instruments in this shard to find any available dates
37
65
  Object.values(data).forEach(instrument => {
38
66
  if (instrument.prices) {
@@ -40,10 +68,17 @@ exports.runRootDataIndexer = async (config, dependencies) => {
40
68
  // Validate format YYYY-MM-DD
41
69
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateKey)) {
42
70
  priceAvailabilitySet.add(dateKey);
71
+ } else {
72
+ // Log regex failures occasionally
73
+ if (Math.random() < 0.001) logger.log('WARN', `[RootDataIndexer] DEBUG: Date key "${dateKey}" failed regex validation.`);
43
74
  }
44
75
  });
45
76
  }
46
77
  });
78
+ } else {
79
+ // --- DEBUGGING START ---
80
+ logger.log('ERROR', `[RootDataIndexer] DEBUG: 🛑 FATAL: Document "${PRICE_SHARD_ID}" does NOT exist in collection "${collections.prices}". Price availability will be false for all dates.`);
81
+ // --- DEBUGGING END ---
47
82
  }
48
83
  logger.log('INFO', `[RootDataIndexer] Loaded price availability map. Found prices for ${priceAvailabilitySet.size} unique dates.`);
49
84
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.250",
3
+ "version": "1.0.251",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [