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:
|
|
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.
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
//
|
|
113
|
-
|
|
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
|
-
//
|
|
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 = '
|
|
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) {
|