bulltrackers-module 1.0.263 → 1.0.265
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.
- package/functions/computation-system/WorkflowOrchestrator.js +58 -22
- package/functions/computation-system/context/ManifestBuilder.js +37 -9
- package/functions/computation-system/executors/StandardExecutor.js +42 -7
- package/functions/computation-system/layers/profiling.js +309 -149
- package/functions/computation-system/persistence/FirestoreUtils.js +2 -10
- package/functions/computation-system/persistence/ResultCommitter.js +106 -199
- package/functions/computation-system/persistence/StatusRepository.js +16 -5
- package/functions/computation-system/tools/BuildReporter.js +9 -19
- package/functions/root-data-indexer/index.js +34 -63
- package/package.json +1 -1
|
@@ -5,14 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const { FieldValue } = require('@google-cloud/firestore');
|
|
8
|
-
const pLimit
|
|
8
|
+
const pLimit = require('p-limit');
|
|
9
9
|
|
|
10
10
|
// Hardcoded verification blocks as per logic requirements
|
|
11
11
|
const CANARY_BLOCK_ID = '19M';
|
|
12
|
-
const CANARY_PART_ID
|
|
13
|
-
|
|
14
|
-
// [FIX] Hardcoded to 'shard_0' based on your confirmed data path (/asset_prices/shard_0)
|
|
15
|
-
const PRICE_SHARD_ID = 'shard_0';
|
|
12
|
+
const CANARY_PART_ID = 'part_0';
|
|
13
|
+
const PRICE_SHARD_ID = 'shard_0';
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
16
|
* Main pipe: pipe.maintenance.runRootDataIndexer
|
|
@@ -25,36 +23,21 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
25
23
|
collections
|
|
26
24
|
} = config;
|
|
27
25
|
|
|
28
|
-
// [FIX] Hardcode the collection name to ignore any incorrect config values
|
|
29
26
|
const PRICE_COLLECTION_NAME = 'asset_prices';
|
|
30
|
-
|
|
31
27
|
logger.log('INFO', '[RootDataIndexer] Starting Root Data Availability Scan...');
|
|
32
|
-
|
|
33
|
-
// 1. Pre-fetch Price Data Availability (Optimization)
|
|
34
28
|
const priceAvailabilitySet = new Set();
|
|
35
|
-
|
|
36
|
-
// --- DEBUGGING START ---
|
|
37
29
|
logger.log('INFO', `[RootDataIndexer] DEBUG: Attempting to fetch price shard. Collection: "${PRICE_COLLECTION_NAME}", Doc ID: "${PRICE_SHARD_ID}"`);
|
|
38
|
-
// --- DEBUGGING END ---
|
|
39
|
-
|
|
40
30
|
try {
|
|
41
|
-
// [FIX] Use the hardcoded collection name
|
|
42
31
|
const priceShardRef = db.collection(PRICE_COLLECTION_NAME).doc(PRICE_SHARD_ID);
|
|
43
32
|
const priceSnap = await priceShardRef.get();
|
|
44
|
-
|
|
45
33
|
if (priceSnap.exists) {
|
|
46
|
-
const data
|
|
34
|
+
const data = priceSnap.data();
|
|
47
35
|
const instruments = Object.values(data);
|
|
48
|
-
|
|
49
|
-
// --- DEBUGGING START ---
|
|
50
36
|
logger.log('INFO', `[RootDataIndexer] DEBUG: Shard document found. Contains ${instruments.length} instrument entries.`);
|
|
51
|
-
|
|
52
37
|
if (instruments.length > 0) {
|
|
53
|
-
// Log the structure of the first instrument found to verify schema match
|
|
54
38
|
const sampleKey = Object.keys(data)[0];
|
|
55
39
|
const sampleVal = data[sampleKey];
|
|
56
40
|
logger.log('INFO', `[RootDataIndexer] DEBUG: Sample Instrument Data (ID: ${sampleKey}):`, sampleVal);
|
|
57
|
-
|
|
58
41
|
if (!sampleVal.prices) {
|
|
59
42
|
logger.log('WARN', `[RootDataIndexer] DEBUG: ⚠️ Sample instrument is MISSING the 'prices' field! Available fields: ${Object.keys(sampleVal).join(', ')}`);
|
|
60
43
|
} else {
|
|
@@ -64,23 +47,10 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
64
47
|
} else {
|
|
65
48
|
logger.log('WARN', '[RootDataIndexer] DEBUG: Shard document exists but appears empty (0 instruments found).');
|
|
66
49
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Iterate over all instruments in this shard to find any available dates
|
|
70
|
-
Object.values(data).forEach(instrument => {
|
|
71
|
-
if (instrument.prices) {
|
|
72
|
-
Object.keys(instrument.prices).forEach(dateKey => {
|
|
73
|
-
// Validate format YYYY-MM-DD
|
|
74
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(dateKey)) {
|
|
75
|
-
priceAvailabilitySet.add(dateKey);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
});
|
|
50
|
+
|
|
51
|
+
Object.values(data).forEach(instrument => { if (instrument.prices) { Object.keys(instrument.prices).forEach(dateKey => { if (/^\d{4}-\d{2}-\d{2}$/.test(dateKey)) { priceAvailabilitySet.add(dateKey); } }); } });
|
|
80
52
|
} else {
|
|
81
|
-
// --- DEBUGGING START ---
|
|
82
53
|
logger.log('ERROR', `[RootDataIndexer] DEBUG: 🛑 FATAL: Document "${PRICE_SHARD_ID}" does NOT exist in collection "${PRICE_COLLECTION_NAME}". Price availability will be false for all dates.`);
|
|
83
|
-
// --- DEBUGGING END ---
|
|
84
54
|
}
|
|
85
55
|
logger.log('INFO', `[RootDataIndexer] Loaded price availability map. Found prices for ${priceAvailabilitySet.size} unique dates.`);
|
|
86
56
|
} catch (e) {
|
|
@@ -89,18 +59,16 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
89
59
|
|
|
90
60
|
// 2. Determine Date Range (Earliest -> Tomorrow)
|
|
91
61
|
const start = new Date(earliestDate || '2023-01-01');
|
|
92
|
-
const end
|
|
62
|
+
const end = new Date();
|
|
93
63
|
end.setDate(end.getDate() + 1); // Look ahead 1 day
|
|
94
64
|
|
|
95
65
|
const datesToScan = [];
|
|
96
|
-
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
|
|
97
|
-
datesToScan.push(d.toISOString().slice(0, 10));
|
|
98
|
-
}
|
|
66
|
+
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) { datesToScan.push(d.toISOString().slice(0, 10)); }
|
|
99
67
|
|
|
100
68
|
logger.log('INFO', `[RootDataIndexer] Scanning ${datesToScan.length} dates from ${datesToScan[0]} to ${datesToScan[datesToScan.length-1]}`);
|
|
101
69
|
|
|
102
70
|
// 3. Scan in Parallel
|
|
103
|
-
const limit
|
|
71
|
+
const limit = pLimit(20); // Concurrent date checks
|
|
104
72
|
let updatesCount = 0;
|
|
105
73
|
|
|
106
74
|
const promises = datesToScan.map(dateStr => limit(async () => {
|
|
@@ -111,17 +79,17 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
111
79
|
|
|
112
80
|
// Defaults
|
|
113
81
|
hasPortfolio: false,
|
|
114
|
-
hasHistory:
|
|
115
|
-
hasSocial:
|
|
116
|
-
hasInsights:
|
|
117
|
-
hasPrices:
|
|
82
|
+
hasHistory: false,
|
|
83
|
+
hasSocial: false,
|
|
84
|
+
hasInsights: false,
|
|
85
|
+
hasPrices: false,
|
|
118
86
|
|
|
119
87
|
// Detailed breakdown
|
|
120
88
|
details: {
|
|
121
|
-
normalPortfolio:
|
|
89
|
+
normalPortfolio: false,
|
|
122
90
|
speculatorPortfolio: false,
|
|
123
|
-
normalHistory:
|
|
124
|
-
speculatorHistory:
|
|
91
|
+
normalHistory: false,
|
|
92
|
+
speculatorHistory: false
|
|
125
93
|
}
|
|
126
94
|
};
|
|
127
95
|
|
|
@@ -165,32 +133,35 @@ exports.runRootDataIndexer = async (config, dependencies) => {
|
|
|
165
133
|
|
|
166
134
|
// --- EXECUTE CHECKS ---
|
|
167
135
|
const [
|
|
168
|
-
normPortSnap,
|
|
169
|
-
|
|
170
|
-
|
|
136
|
+
normPortSnap,
|
|
137
|
+
specPortSnap,
|
|
138
|
+
normHistSnap,
|
|
139
|
+
specHistSnap,
|
|
140
|
+
insightsSnap,
|
|
141
|
+
socialQuerySnap
|
|
171
142
|
] = await Promise.all([
|
|
172
|
-
normPortRef.get(),
|
|
173
|
-
|
|
143
|
+
normPortRef.get(),
|
|
144
|
+
specPortRef.get(),
|
|
145
|
+
normHistRef.get(),
|
|
146
|
+
specHistRef.get(),
|
|
174
147
|
insightsRef.get(),
|
|
175
148
|
socialPostsRef.limit(1).get()
|
|
176
149
|
]);
|
|
177
150
|
|
|
178
151
|
// Evaluate Findings
|
|
179
|
-
availability.details.normalPortfolio
|
|
152
|
+
availability.details.normalPortfolio = normPortSnap.exists;
|
|
180
153
|
availability.details.speculatorPortfolio = specPortSnap.exists;
|
|
181
|
-
availability.hasPortfolio
|
|
154
|
+
availability.hasPortfolio = normPortSnap.exists || specPortSnap.exists;
|
|
182
155
|
|
|
183
|
-
availability.details.normalHistory
|
|
184
|
-
availability.details.speculatorHistory
|
|
185
|
-
availability.hasHistory
|
|
156
|
+
availability.details.normalHistory = normHistSnap.exists;
|
|
157
|
+
availability.details.speculatorHistory = specHistSnap.exists;
|
|
158
|
+
availability.hasHistory = normHistSnap.exists || specHistSnap.exists;
|
|
186
159
|
|
|
187
|
-
availability.hasInsights
|
|
188
|
-
availability.hasSocial
|
|
160
|
+
availability.hasInsights = insightsSnap.exists;
|
|
161
|
+
availability.hasSocial = !socialQuerySnap.empty;
|
|
189
162
|
|
|
190
|
-
|
|
191
|
-
availability.hasPrices = priceAvailabilitySet.has(dateStr);
|
|
163
|
+
availability.hasPrices = priceAvailabilitySet.has(dateStr);
|
|
192
164
|
|
|
193
|
-
// Write to Index
|
|
194
165
|
await db.collection(availabilityCollection).doc(dateStr).set(availability);
|
|
195
166
|
updatesCount++;
|
|
196
167
|
|