bulltrackers-module 1.0.732 → 1.0.734
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-v2/README.md +152 -0
- package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +720 -0
- package/functions/computation-system-v2/computations/PopularInvestorRiskAssessment.js +176 -0
- package/functions/computation-system-v2/computations/PopularInvestorRiskMetrics.js +294 -0
- package/functions/computation-system-v2/computations/TestComputation.js +46 -0
- package/functions/computation-system-v2/computations/UserPortfolioSummary.js +172 -0
- package/functions/computation-system-v2/config/bulltrackers.config.js +317 -0
- package/functions/computation-system-v2/framework/core/Computation.js +73 -0
- package/functions/computation-system-v2/framework/core/Manifest.js +223 -0
- package/functions/computation-system-v2/framework/core/RuleInjector.js +53 -0
- package/functions/computation-system-v2/framework/core/Rules.js +231 -0
- package/functions/computation-system-v2/framework/core/RunAnalyzer.js +163 -0
- package/functions/computation-system-v2/framework/cost/CostTracker.js +154 -0
- package/functions/computation-system-v2/framework/data/DataFetcher.js +399 -0
- package/functions/computation-system-v2/framework/data/QueryBuilder.js +232 -0
- package/functions/computation-system-v2/framework/data/SchemaRegistry.js +287 -0
- package/functions/computation-system-v2/framework/execution/Orchestrator.js +498 -0
- package/functions/computation-system-v2/framework/execution/TaskRunner.js +35 -0
- package/functions/computation-system-v2/framework/execution/middleware/CostTrackerMiddleware.js +32 -0
- package/functions/computation-system-v2/framework/execution/middleware/LineageMiddleware.js +32 -0
- package/functions/computation-system-v2/framework/execution/middleware/Middleware.js +14 -0
- package/functions/computation-system-v2/framework/execution/middleware/ProfilerMiddleware.js +47 -0
- package/functions/computation-system-v2/framework/index.js +45 -0
- package/functions/computation-system-v2/framework/lineage/LineageTracker.js +147 -0
- package/functions/computation-system-v2/framework/monitoring/Profiler.js +80 -0
- package/functions/computation-system-v2/framework/resilience/Checkpointer.js +66 -0
- package/functions/computation-system-v2/framework/scheduling/ScheduleValidator.js +327 -0
- package/functions/computation-system-v2/framework/storage/StateRepository.js +286 -0
- package/functions/computation-system-v2/framework/storage/StorageManager.js +469 -0
- package/functions/computation-system-v2/framework/storage/index.js +9 -0
- package/functions/computation-system-v2/framework/testing/ComputationTester.js +86 -0
- package/functions/computation-system-v2/framework/utils/Graph.js +205 -0
- package/functions/computation-system-v2/handlers/dispatcher.js +109 -0
- package/functions/computation-system-v2/handlers/index.js +23 -0
- package/functions/computation-system-v2/handlers/onDemand.js +289 -0
- package/functions/computation-system-v2/handlers/scheduler.js +327 -0
- package/functions/computation-system-v2/index.js +163 -0
- package/functions/computation-system-v2/rules/index.js +49 -0
- package/functions/computation-system-v2/rules/instruments.js +465 -0
- package/functions/computation-system-v2/rules/metrics.js +304 -0
- package/functions/computation-system-v2/rules/portfolio.js +534 -0
- package/functions/computation-system-v2/rules/rankings.js +655 -0
- package/functions/computation-system-v2/rules/social.js +562 -0
- package/functions/computation-system-v2/rules/trades.js +545 -0
- package/functions/computation-system-v2/scripts/migrate-sectors.js +73 -0
- package/functions/computation-system-v2/test/test-dispatcher.js +317 -0
- package/functions/computation-system-v2/test/test-framework.js +500 -0
- package/functions/computation-system-v2/test/test-real-execution.js +166 -0
- package/functions/computation-system-v2/test/test-real-integration.js +194 -0
- package/functions/computation-system-v2/test/test-refactor-e2e.js +131 -0
- package/functions/computation-system-v2/test/test-results.json +31 -0
- package/functions/computation-system-v2/test/test-risk-metrics-computation.js +329 -0
- package/functions/computation-system-v2/test/test-scheduler.js +204 -0
- package/functions/computation-system-v2/test/test-storage.js +449 -0
- package/functions/orchestrator/index.js +24 -30
- package/index.js +8 -29
- package/package.json +3 -2
- package/functions/computation-system/WorkflowOrchestrator.js +0 -213
- package/functions/computation-system/config/monitoring_config.js +0 -31
- package/functions/computation-system/config/validation_overrides.js +0 -10
- package/functions/computation-system/context/ContextFactory.js +0 -143
- package/functions/computation-system/context/ManifestBuilder.js +0 -379
- package/functions/computation-system/data/AvailabilityChecker.js +0 -236
- package/functions/computation-system/data/CachedDataLoader.js +0 -325
- package/functions/computation-system/data/DependencyFetcher.js +0 -455
- package/functions/computation-system/executors/MetaExecutor.js +0 -279
- package/functions/computation-system/executors/PriceBatchExecutor.js +0 -108
- package/functions/computation-system/executors/StandardExecutor.js +0 -465
- package/functions/computation-system/helpers/computation_dispatcher.js +0 -750
- package/functions/computation-system/helpers/computation_worker.js +0 -375
- package/functions/computation-system/helpers/monitor.js +0 -64
- package/functions/computation-system/helpers/on_demand_helpers.js +0 -154
- package/functions/computation-system/layers/extractors.js +0 -1097
- package/functions/computation-system/layers/index.js +0 -40
- package/functions/computation-system/layers/mathematics.js +0 -522
- package/functions/computation-system/layers/profiling.js +0 -537
- package/functions/computation-system/layers/validators.js +0 -170
- package/functions/computation-system/legacy/AvailabilityCheckerOld.js +0 -388
- package/functions/computation-system/legacy/CachedDataLoaderOld.js +0 -357
- package/functions/computation-system/legacy/DependencyFetcherOld.js +0 -478
- package/functions/computation-system/legacy/MetaExecutorold.js +0 -364
- package/functions/computation-system/legacy/StandardExecutorold.js +0 -476
- package/functions/computation-system/legacy/computation_dispatcherold.js +0 -944
- package/functions/computation-system/logger/logger.js +0 -297
- package/functions/computation-system/persistence/ContractValidator.js +0 -81
- package/functions/computation-system/persistence/FirestoreUtils.js +0 -56
- package/functions/computation-system/persistence/ResultCommitter.js +0 -283
- package/functions/computation-system/persistence/ResultsValidator.js +0 -130
- package/functions/computation-system/persistence/RunRecorder.js +0 -142
- package/functions/computation-system/persistence/StatusRepository.js +0 -52
- package/functions/computation-system/reporter_epoch.js +0 -6
- package/functions/computation-system/scripts/UpdateContracts.js +0 -128
- package/functions/computation-system/services/SnapshotService.js +0 -148
- package/functions/computation-system/simulation/Fabricator.js +0 -285
- package/functions/computation-system/simulation/SeededRandom.js +0 -41
- package/functions/computation-system/simulation/SimRunner.js +0 -51
- package/functions/computation-system/system_epoch.js +0 -2
- package/functions/computation-system/tools/BuildReporter.js +0 -531
- package/functions/computation-system/tools/ContractDiscoverer.js +0 -144
- package/functions/computation-system/tools/DeploymentValidator.js +0 -536
- package/functions/computation-system/tools/FinalSweepReporter.js +0 -322
- package/functions/computation-system/topology/HashManager.js +0 -55
- package/functions/computation-system/topology/ManifestLoader.js +0 -47
- package/functions/computation-system/utils/data_loader.js +0 -675
- package/functions/computation-system/utils/schema_capture.js +0 -121
- package/functions/computation-system/utils/utils.js +0 -188
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Main orchestration logic.
|
|
3
3
|
* REFACTORED: Implements 'Active Scheduling' via Cloud Tasks to enforce 1-hour gaps.
|
|
4
|
-
* This allows the Workflow to finish immediately while Cloud Tasks manages the pacing.
|
|
5
4
|
*/
|
|
6
5
|
const { checkDiscoveryNeed, getDiscoveryCandidates, dispatchDiscovery } = require('./helpers/discovery_helpers');
|
|
7
6
|
const { getUpdateTargets, dispatchUpdates } = require('./helpers/update_helpers');
|
|
@@ -11,6 +10,12 @@ const { CloudTasksClient } = require('@google-cloud/tasks');
|
|
|
11
10
|
// Initialize Cloud Tasks Client
|
|
12
11
|
const cloudTasksClient = new CloudTasksClient();
|
|
13
12
|
|
|
13
|
+
// --- CONFIGURATION (Now via Env Vars) ---
|
|
14
|
+
// These are injected by deploy.mjs based on config.mjs
|
|
15
|
+
const QUEUE_NAME = process.env.ORCHESTRATOR_QUEUE || 'task-engine-queue';
|
|
16
|
+
const LOCATION = process.env.GCP_REGION || 'europe-west1';
|
|
17
|
+
const PROJECT = process.env.GCP_PROJECT_ID;
|
|
18
|
+
|
|
14
19
|
/**
|
|
15
20
|
* ENTRY POINT: HTTP Handler for Workflow Interaction
|
|
16
21
|
*/
|
|
@@ -28,11 +33,11 @@ async function handleOrchestratorHttp(req, res, dependencies, config) {
|
|
|
28
33
|
throw new Error("Missing userType or date for PLAN action");
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
// Determine self-URL for callback
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
// Determine self-URL for callback (Cloud Task needs to call this function back)
|
|
37
|
+
// We use the env var passed by GCF (FUNCTION_URI) or construct it manually
|
|
38
|
+
const orchestratorUrl = orchestratorUrlOverride ||
|
|
39
|
+
process.env.FUNCTION_URI ||
|
|
40
|
+
`https://${LOCATION}-${PROJECT}.cloudfunctions.net/${process.env.K_SERVICE || 'orchestrator-http'}`;
|
|
36
41
|
|
|
37
42
|
const result = await planDailyUpdates(userType, date, windows || 10, config, dependencies, orchestratorUrl);
|
|
38
43
|
res.status(200).send(result);
|
|
@@ -60,21 +65,12 @@ async function handleOrchestratorHttp(req, res, dependencies, config) {
|
|
|
60
65
|
|
|
61
66
|
/**
|
|
62
67
|
* LOGIC: Plan the updates (Split into windows AND Schedule Execution)
|
|
63
|
-
* 1. Fetches all users needing updates.
|
|
64
|
-
* 2. Shuffles them.
|
|
65
|
-
* 3. Splits them into 'n' windows.
|
|
66
|
-
* 4. Schedules Cloud Tasks for each window with a 1-hour delay between them.
|
|
67
68
|
*/
|
|
68
69
|
async function planDailyUpdates(userType, date, numberOfWindows, config, deps, orchestratorUrl) {
|
|
69
70
|
const { logger, db } = deps;
|
|
70
71
|
|
|
71
|
-
//
|
|
72
|
-
const
|
|
73
|
-
const location = process.env.GCP_LOCATION || 'us-central1';
|
|
74
|
-
const queue = process.env.GCP_QUEUE_NAME || 'orchestrator-queue'; // MUST EXIST in Cloud Console
|
|
75
|
-
|
|
76
|
-
// Construct the fully qualified queue name
|
|
77
|
-
const parentQueue = cloudTasksClient.queuePath(project, location, queue);
|
|
72
|
+
// Use Configured Queue
|
|
73
|
+
const parentQueue = cloudTasksClient.queuePath(PROJECT, LOCATION, QUEUE_NAME);
|
|
78
74
|
|
|
79
75
|
// 1. Get ALL targets
|
|
80
76
|
const now = new Date();
|
|
@@ -102,7 +98,6 @@ async function planDailyUpdates(userType, date, numberOfWindows, config, deps, o
|
|
|
102
98
|
const planId = `plan_${userType}_${date}`;
|
|
103
99
|
const batchWriter = db.batch();
|
|
104
100
|
|
|
105
|
-
// We collect task creation promises to await them at the end
|
|
106
101
|
const tasksToCreate = [];
|
|
107
102
|
|
|
108
103
|
for (let i = 0; i < numberOfWindows; i++) {
|
|
@@ -147,9 +142,10 @@ async function planDailyUpdates(userType, date, numberOfWindows, config, deps, o
|
|
|
147
142
|
url: orchestratorUrl,
|
|
148
143
|
headers: { 'Content-Type': 'application/json' },
|
|
149
144
|
body: Buffer.from(JSON.stringify(taskPayload)).toString('base64'),
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
// Use OIDC if service account is available in env
|
|
146
|
+
oidcToken: process.env.GCP_SERVICE_ACCOUNT_EMAIL
|
|
147
|
+
? { serviceAccountEmail: process.env.GCP_SERVICE_ACCOUNT_EMAIL }
|
|
148
|
+
: undefined
|
|
153
149
|
},
|
|
154
150
|
scheduleTime: {
|
|
155
151
|
seconds: scheduleTimeSeconds
|
|
@@ -161,20 +157,21 @@ async function planDailyUpdates(userType, date, numberOfWindows, config, deps, o
|
|
|
161
157
|
}
|
|
162
158
|
}
|
|
163
159
|
|
|
164
|
-
// Commit Firestore Writes First
|
|
160
|
+
// Commit Firestore Writes First
|
|
165
161
|
await batchWriter.commit();
|
|
166
162
|
logger.log('SUCCESS', `[Orchestrator Plan] Plan ${planId} saved to Firestore.`);
|
|
167
163
|
|
|
168
164
|
// Dispatch Cloud Tasks
|
|
169
|
-
logger.log('INFO', `[Orchestrator Plan] Scheduling ${tasksToCreate.length} tasks for ${userType}...`);
|
|
165
|
+
logger.log('INFO', `[Orchestrator Plan] Scheduling ${tasksToCreate.length} tasks for ${userType} to queue ${QUEUE_NAME}...`);
|
|
170
166
|
|
|
171
|
-
// Create tasks in parallel (with limit if needed, but usually fine for <50 tasks)
|
|
172
167
|
const scheduleResults = await Promise.allSettled(tasksToCreate.map(req => cloudTasksClient.createTask(req)));
|
|
173
168
|
|
|
174
169
|
const failedCount = scheduleResults.filter(r => r.status === 'rejected').length;
|
|
175
170
|
if (failedCount > 0) {
|
|
176
171
|
logger.log('ERROR', `[Orchestrator Plan] Failed to schedule ${failedCount} tasks.`);
|
|
177
|
-
|
|
172
|
+
scheduleResults.forEach((r, idx) => {
|
|
173
|
+
if (r.status === 'rejected') logger.log('ERROR', `Task ${idx} error:`, r.reason);
|
|
174
|
+
});
|
|
178
175
|
}
|
|
179
176
|
|
|
180
177
|
return {
|
|
@@ -188,7 +185,6 @@ async function planDailyUpdates(userType, date, numberOfWindows, config, deps, o
|
|
|
188
185
|
|
|
189
186
|
/**
|
|
190
187
|
* LOGIC: Execute a specific window
|
|
191
|
-
* Triggered by Cloud Tasks when the schedule time arrives.
|
|
192
188
|
*/
|
|
193
189
|
async function executeUpdateWindow(planId, windowId, userType, config, deps) {
|
|
194
190
|
const { logger, db } = deps;
|
|
@@ -203,7 +199,7 @@ async function executeUpdateWindow(planId, windowId, userType, config, deps) {
|
|
|
203
199
|
|
|
204
200
|
const data = windowDoc.data();
|
|
205
201
|
|
|
206
|
-
// Idempotency
|
|
202
|
+
// Idempotency
|
|
207
203
|
if (data.status === 'completed') {
|
|
208
204
|
logger.log('WARN', `[Orchestrator Execute] Window ${windowId} already completed. Skipping.`);
|
|
209
205
|
return { dispatchedCount: 0, status: 'already_completed' };
|
|
@@ -226,8 +222,7 @@ async function executeUpdateWindow(planId, windowId, userType, config, deps) {
|
|
|
226
222
|
return { dispatchedCount: targets.length, status: 'success' };
|
|
227
223
|
}
|
|
228
224
|
|
|
229
|
-
// --- Legacy
|
|
230
|
-
|
|
225
|
+
// --- Legacy Wrappers ---
|
|
231
226
|
async function runDiscoveryOrchestrator(config, deps) {
|
|
232
227
|
const { logger, firestoreUtils } = deps;
|
|
233
228
|
logger.log('INFO', '🚀 Discovery Orchestrator triggered...');
|
|
@@ -255,7 +250,6 @@ async function runUpdateOrchestrator(config, deps) {
|
|
|
255
250
|
}
|
|
256
251
|
|
|
257
252
|
async function runDiscovery(userType, userConfig, globalConfig, deps) {
|
|
258
|
-
const { logger } = deps;
|
|
259
253
|
const { needsDiscovery, blocksToFill } = await checkDiscoveryNeed(userType, userConfig, deps);
|
|
260
254
|
if (!needsDiscovery) return;
|
|
261
255
|
const candidates = await getDiscoveryCandidates(userType, blocksToFill, userConfig, deps);
|
package/index.js
CHANGED
|
@@ -30,24 +30,12 @@ const { handleDiscover } = require('./functions
|
|
|
30
30
|
const { handleVerify } = require('./functions/task-engine/helpers/verify_helpers');
|
|
31
31
|
const { handleUpdate } = require('./functions/task-engine/helpers/update_helpers');
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
const { dispatchComputationPass } = require('./functions/computation-system/helpers/computation_dispatcher');
|
|
36
|
-
const { handleComputationTask } = require('./functions/computation-system/helpers/computation_worker');
|
|
37
|
-
const {
|
|
38
|
-
requestBuildReport,
|
|
39
|
-
handleBuildReportTrigger,
|
|
40
|
-
generateBuildReport
|
|
41
|
-
} = require('./functions/computation-system/tools/BuildReporter');
|
|
42
|
-
|
|
43
|
-
const { checkPassStatus } = require('./functions/computation-system/helpers/monitor');
|
|
44
|
-
|
|
45
|
-
const dataLoader = require('./functions/computation-system/utils/data_loader');
|
|
46
|
-
const computationUtils = require('./functions/computation-system/utils/utils');
|
|
47
|
-
|
|
33
|
+
// --- COMPUTATION SYSTEM V2 (Replaces v1) ---
|
|
34
|
+
const computationSystemV2 = require('./functions/computation-system-v2/handlers/index');
|
|
48
35
|
|
|
49
36
|
const { createApiV2App } = require('./functions/api-v2/index');
|
|
50
37
|
|
|
38
|
+
// Maintenance & Backfills
|
|
51
39
|
const { fetchAndStoreInsights } = require('./functions/fetch-insights/helpers/handler_helpers');
|
|
52
40
|
const { fetchAndStorePrices } = require('./functions/etoro-price-fetcher/helpers/handler_helpers');
|
|
53
41
|
const { runSocialOrchestrator } = require('./functions/social-orchestrator/helpers/orchestrator_helpers');
|
|
@@ -103,16 +91,11 @@ const taskEngine = {
|
|
|
103
91
|
handleUpdate,
|
|
104
92
|
};
|
|
105
93
|
|
|
94
|
+
// Expose v2 handlers directly
|
|
106
95
|
const computationSystem = {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
computationUtils,
|
|
111
|
-
buildManifest,
|
|
112
|
-
requestBuildReport,
|
|
113
|
-
handleBuildReportTrigger,
|
|
114
|
-
generateBuildReport,
|
|
115
|
-
checkPassStatus
|
|
96
|
+
computeScheduler: computationSystemV2.computeScheduler,
|
|
97
|
+
computeDispatcher: computationSystemV2.computeDispatcher,
|
|
98
|
+
computeOnDemand: computationSystemV2.computeOnDemand
|
|
116
99
|
};
|
|
117
100
|
|
|
118
101
|
const api = {
|
|
@@ -154,7 +137,7 @@ module.exports = {
|
|
|
154
137
|
if (require.main === module) {
|
|
155
138
|
const args = process.argv.slice(2);
|
|
156
139
|
|
|
157
|
-
// Check if this looks like a backfill command
|
|
140
|
+
// Check if this looks like a backfill command
|
|
158
141
|
const isBackfillCommand = args.some(arg =>
|
|
159
142
|
arg.startsWith('--startDate=') ||
|
|
160
143
|
arg.startsWith('--endDate=') ||
|
|
@@ -162,14 +145,10 @@ if (require.main === module) {
|
|
|
162
145
|
);
|
|
163
146
|
|
|
164
147
|
if (isBackfillCommand) {
|
|
165
|
-
// Route to backfill function
|
|
166
148
|
console.log('🚀 Starting backfill from main entry point...\n');
|
|
167
149
|
backfillTaskEngineData(null, null).catch(error => {
|
|
168
150
|
console.error('Fatal error:', error);
|
|
169
151
|
process.exit(1);
|
|
170
152
|
});
|
|
171
|
-
} else {
|
|
172
|
-
// No recognized command, just export (normal module behavior)
|
|
173
|
-
// This allows the file to still work as a module when imported
|
|
174
153
|
}
|
|
175
154
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bulltrackers-module",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.734",
|
|
4
4
|
"description": "Helper Functions for Bulltrackers.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"functions/maintenance/backfill-pi-alert-history",
|
|
29
29
|
"functions/maintenance/backfill-pi-page-views",
|
|
30
30
|
"functions/maintenance/backfill-pi-ratings",
|
|
31
|
-
"functions/maintenance/backfill-watchlist-membership"
|
|
31
|
+
"functions/maintenance/backfill-watchlist-membership",
|
|
32
|
+
"functions/computation-system-v2/"
|
|
32
33
|
],
|
|
33
34
|
"keywords": [
|
|
34
35
|
"bulltrackers",
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FILENAME: computation-system/WorkflowOrchestrator.js
|
|
3
|
-
* UPDATED: Fixed 'Version Mismatch' deadlock for historical chains.
|
|
4
|
-
* UPDATED: Added Force-Run logic for 'isTest' computations on current day.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { normalizeName, DEFINITIVE_EARLIEST_DATES } = require('./utils/utils');
|
|
8
|
-
const { checkRootDataAvailability, checkRootDependencies } = require('./data/AvailabilityChecker');
|
|
9
|
-
const { fetchExistingResults } = require('./data/DependencyFetcher');
|
|
10
|
-
const { fetchComputationStatus, updateComputationStatus } = require('./persistence/StatusRepository'); // Unused
|
|
11
|
-
const { StandardExecutor } = require('./executors/StandardExecutor');
|
|
12
|
-
const { MetaExecutor } = require('./executors/MetaExecutor');
|
|
13
|
-
|
|
14
|
-
const STATUS_IMPOSSIBLE_PREFIX = 'IMPOSSIBLE';
|
|
15
|
-
|
|
16
|
-
function groupByPass(manifest) {
|
|
17
|
-
const passes = {};
|
|
18
|
-
manifest.forEach(calc => {
|
|
19
|
-
if (!passes[calc.pass]) passes[calc.pass] = [];
|
|
20
|
-
passes[calc.pass].push(calc);
|
|
21
|
-
});
|
|
22
|
-
return passes;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function isDependencyReady(depName, isHistoricalSelf, currentStatusMap, prevStatusMap, manifestMap, storedStatus) {
|
|
26
|
-
const norm = normalizeName(depName);
|
|
27
|
-
const targetStatus = isHistoricalSelf ? (prevStatusMap ? prevStatusMap[norm] : null) : currentStatusMap[norm];
|
|
28
|
-
const depManifest = manifestMap.get(norm);
|
|
29
|
-
|
|
30
|
-
if (!targetStatus) return { ready: false, reason: 'Missing' };
|
|
31
|
-
if (String(targetStatus.hash).startsWith(STATUS_IMPOSSIBLE_PREFIX)) return { ready: false, reason: 'Impossible Upstream' };
|
|
32
|
-
|
|
33
|
-
if (depManifest && targetStatus.hash !== depManifest.hash) {
|
|
34
|
-
return { ready: false, reason: 'Dependency Version Mismatch' };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (storedStatus && storedStatus.dependencyResultHashes) {
|
|
38
|
-
// FIX: Normalize the dependency name for lookup
|
|
39
|
-
const lastSeenResultHash = storedStatus.dependencyResultHashes[depName] || storedStatus.dependencyResultHashes[norm];
|
|
40
|
-
if (lastSeenResultHash && targetStatus.resultHash !== lastSeenResultHash) {
|
|
41
|
-
return { ready: true, dataChanged: true, reason: 'Dependency Data Update' };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return { ready: true, dataChanged: false };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function analyzeDateExecution(dateStr, calcsInPass, rootDataStatus, dailyStatus, manifestMap, prevDailyStatus = null) {
|
|
49
|
-
const report = { runnable: [], blocked: [], impossible: [], failedDependency: [], reRuns: [], skipped: [] };
|
|
50
|
-
const simulationStatus = { ...dailyStatus };
|
|
51
|
-
const isToday = dateStr === new Date().toISOString().slice(0, 10);
|
|
52
|
-
|
|
53
|
-
for (const calc of calcsInPass) {
|
|
54
|
-
const cName = normalizeName(calc.name);
|
|
55
|
-
const stored = simulationStatus[cName];
|
|
56
|
-
const currentHash = calc.hash;
|
|
57
|
-
|
|
58
|
-
// [NEW] Rule: 'isTest' computations always re-run on the current day.
|
|
59
|
-
// This ensures debug/test probes fire immediately to test system changes.
|
|
60
|
-
const shouldForceRun = isToday && (calc.isTest === true);
|
|
61
|
-
|
|
62
|
-
// 1. Root Data Check
|
|
63
|
-
const rootCheck = checkRootDependencies(calc, rootDataStatus);
|
|
64
|
-
if (!rootCheck.canRun) {
|
|
65
|
-
if (dateStr !== new Date().toISOString().slice(0, 10)) {
|
|
66
|
-
report.impossible.push({ name: cName, reason: `Missing Root: ${rootCheck.missing.join(', ')}` });
|
|
67
|
-
simulationStatus[cName] = { hash: `${STATUS_IMPOSSIBLE_PREFIX}:NO_DATA` };
|
|
68
|
-
} else {
|
|
69
|
-
report.blocked.push({ name: cName, reason: `Waiting for Root Data` });
|
|
70
|
-
}
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// --- OPTIMIZATION: Early skip if code matches AND data is stable ---
|
|
75
|
-
// [UPDATED] We bypass this optimization if shouldForceRun is true
|
|
76
|
-
if (stored?.hash === currentHash && !shouldForceRun) {
|
|
77
|
-
let hasDataDrift = false;
|
|
78
|
-
let isBlocked = false;
|
|
79
|
-
let missingDeps = [];
|
|
80
|
-
|
|
81
|
-
if (calc.dependencies) {
|
|
82
|
-
for (const dep of calc.dependencies) {
|
|
83
|
-
const check = isDependencyReady(dep, false, simulationStatus, null, manifestMap, stored);
|
|
84
|
-
if (!check.ready) missingDeps.push(dep);
|
|
85
|
-
else if (check.dataChanged) { hasDataDrift = true; break; }
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (!hasDataDrift && missingDeps.length === 0 && calc.isHistorical) {
|
|
90
|
-
const yesterday = new Date(dateStr + 'T00:00:00Z');
|
|
91
|
-
yesterday.setUTCDate(yesterday.getUTCDate() - 1);
|
|
92
|
-
if (yesterday >= DEFINITIVE_EARLIEST_DATES.absoluteEarliest) {
|
|
93
|
-
const check = isDependencyReady(calc.name, true, null, prevDailyStatus, manifestMap, stored);
|
|
94
|
-
if (!check.ready) {
|
|
95
|
-
// [FIX]: Treat Missing OR Version Mismatch as Data Drift (Fresh Start)
|
|
96
|
-
if (check.reason === 'Missing' || check.reason === 'Dependency Version Mismatch') {
|
|
97
|
-
hasDataDrift = true;
|
|
98
|
-
} else {
|
|
99
|
-
isBlocked = true;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
else if (check.dataChanged) hasDataDrift = true;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!hasDataDrift && !isBlocked && missingDeps.length === 0) {
|
|
107
|
-
report.skipped.push({ name: cName, reason: "Up To Date" });
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// --- END OPTIMIZATION ---
|
|
112
|
-
|
|
113
|
-
const missingDeps = [];
|
|
114
|
-
let hasDataDrift = false;
|
|
115
|
-
let isBlocked = false;
|
|
116
|
-
|
|
117
|
-
if (calc.dependencies) {
|
|
118
|
-
for (const dep of calc.dependencies) {
|
|
119
|
-
const check = isDependencyReady(dep, false, simulationStatus, null, manifestMap, stored);
|
|
120
|
-
if (!check.ready) missingDeps.push(dep);
|
|
121
|
-
else if (check.dataChanged) hasDataDrift = true;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (calc.isHistorical) {
|
|
126
|
-
const yesterday = new Date(dateStr + 'T00:00:00Z');
|
|
127
|
-
yesterday.setUTCDate(yesterday.getUTCDate() - 1);
|
|
128
|
-
if (yesterday >= DEFINITIVE_EARLIEST_DATES.absoluteEarliest) {
|
|
129
|
-
const check = isDependencyReady(calc.name, true, null, prevDailyStatus, manifestMap, stored);
|
|
130
|
-
if (!check.ready) {
|
|
131
|
-
// [FIX]: Allow fresh start if yesterday is Missing OR has different Code Version
|
|
132
|
-
if (check.reason === 'Missing' || check.reason === 'Dependency Version Mismatch') {
|
|
133
|
-
hasDataDrift = true;
|
|
134
|
-
} else {
|
|
135
|
-
isBlocked = true;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
else if (check.dataChanged) hasDataDrift = true;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (missingDeps.length > 0) {
|
|
143
|
-
const isImpossible = missingDeps.some(d => String(simulationStatus[normalizeName(d)]?.hash).startsWith(STATUS_IMPOSSIBLE_PREFIX));
|
|
144
|
-
if (isImpossible) {
|
|
145
|
-
report.impossible.push({ name: cName, reason: 'Upstream Impossible' });
|
|
146
|
-
simulationStatus[cName] = { hash: `${STATUS_IMPOSSIBLE_PREFIX}:UPSTREAM` };
|
|
147
|
-
} else {
|
|
148
|
-
report.failedDependency.push({ name: cName, missing: missingDeps });
|
|
149
|
-
}
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (isBlocked) {
|
|
154
|
-
report.blocked.push({ name: cName, reason: 'Waiting for Yesterday' });
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const currentDependencyResultHashes = {};
|
|
159
|
-
if (calc.dependencies) {
|
|
160
|
-
calc.dependencies.forEach(d => {
|
|
161
|
-
const resHash = simulationStatus[normalizeName(d)]?.resultHash;
|
|
162
|
-
if (resHash) currentDependencyResultHashes[d] = resHash;
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const taskPayload = { name: cName, dependencyResultHashes: currentDependencyResultHashes };
|
|
167
|
-
|
|
168
|
-
if (!stored?.hash) {
|
|
169
|
-
report.runnable.push({ ...taskPayload, reason: "New Calculation" });
|
|
170
|
-
} else if (stored.hash !== currentHash) {
|
|
171
|
-
report.reRuns.push({ ...taskPayload, oldHash: stored.hash, newHash: currentHash, reason: "Hash Mismatch" });
|
|
172
|
-
} else if (shouldForceRun) {
|
|
173
|
-
// [NEW] Logic to handle the forced run for Test probes
|
|
174
|
-
report.reRuns.push({ ...taskPayload, oldHash: stored.hash, newHash: currentHash, reason: "Test Computation (Always Run Today)" });
|
|
175
|
-
} else if (hasDataDrift) {
|
|
176
|
-
report.runnable.push({ ...taskPayload, reason: "Input Data Changed" });
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return report;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async function executeDispatchTask(dateStr, pass, targetComputation, config, dependencies, computationManifest, previousCategory = null, dependencyResultHashes = {}, metadata = {}) {
|
|
183
|
-
const { logger } = dependencies;
|
|
184
|
-
const manifestMap = new Map(computationManifest.map(c => [normalizeName(c.name), c]));
|
|
185
|
-
const calcManifest = manifestMap.get(normalizeName(targetComputation));
|
|
186
|
-
|
|
187
|
-
if (!calcManifest) throw new Error(`Calc '${targetComputation}' not found.`);
|
|
188
|
-
|
|
189
|
-
// Merge runtime metadata (like targetCid) into the manifest
|
|
190
|
-
// This allows the Executor to access it via 'calcInstance.manifest'
|
|
191
|
-
Object.assign(calcManifest, metadata);
|
|
192
|
-
|
|
193
|
-
calcManifest.dependencyResultHashes = dependencyResultHashes;
|
|
194
|
-
|
|
195
|
-
const rootData = await checkRootDataAvailability(dateStr, config, dependencies, DEFINITIVE_EARLIEST_DATES);
|
|
196
|
-
const calcsToRun = [calcManifest];
|
|
197
|
-
|
|
198
|
-
const existingResults = await fetchExistingResults(dateStr, calcsToRun, computationManifest, config, dependencies, false);
|
|
199
|
-
let previousResults = {};
|
|
200
|
-
if (calcManifest.isHistorical) {
|
|
201
|
-
const prev = new Date(dateStr + 'T00:00:00Z'); prev.setUTCDate(prev.getUTCDate() - 1);
|
|
202
|
-
previousResults = await fetchExistingResults(prev.toISOString().slice(0, 10), calcsToRun, computationManifest, config, dependencies, true);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const execDate = new Date(dateStr + 'T00:00:00Z');
|
|
206
|
-
const updates = (calcManifest.type === 'standard')
|
|
207
|
-
? await StandardExecutor.run(execDate, calcsToRun, `Pass ${pass}`, config, dependencies, rootData, existingResults, previousResults)
|
|
208
|
-
: await MetaExecutor.run(execDate, calcsToRun, `Pass ${pass}`, config, dependencies, rootData, existingResults, previousResults);
|
|
209
|
-
|
|
210
|
-
return { date: dateStr, updates };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
module.exports = { executeDispatchTask, analyzeDateExecution, groupByPass };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* computation-system/config/monitoring_config.js
|
|
3
|
-
* Configuration for Google Cloud Monitoring, Logging, and Tracing.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
7
|
-
// Toggle to easily disable all GCP telemetry without changing code
|
|
8
|
-
enabled: true,
|
|
9
|
-
|
|
10
|
-
// Your Google Cloud Project ID
|
|
11
|
-
project: process.env.GOOGLE_CLOUD_PROJECT_ID || process.env.GCP_PROJECT || 'your-project-id',
|
|
12
|
-
|
|
13
|
-
// Configuration for the "Eyeball" (Trace)
|
|
14
|
-
trace: {
|
|
15
|
-
enabled: true,
|
|
16
|
-
// Force sampling for these computations (can use '*' for all)
|
|
17
|
-
sampledTasks: ['*']
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
// Definitions for Custom Metrics
|
|
21
|
-
metrics: {
|
|
22
|
-
// The heartbeat metric replaces the Firestore 'active' check over time
|
|
23
|
-
heartbeat: 'custom.googleapis.com/computation/worker_heartbeat',
|
|
24
|
-
|
|
25
|
-
// Tracks memory usage per worker/task
|
|
26
|
-
memory: 'custom.googleapis.com/computation/memory_usage',
|
|
27
|
-
|
|
28
|
-
// Tracks duration of specific processing stages
|
|
29
|
-
duration: 'custom.googleapis.com/computation/stage_duration'
|
|
30
|
-
}
|
|
31
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
// Only add calculations here if the HeuristicValidator is too aggressive
|
|
3
|
-
// EXAMPLES :
|
|
4
|
-
// "bankruptcy-detector": { maxZeroPct: 100 }, // It's rare, so 100% 0s is fine
|
|
5
|
-
// "sparse-signal-generator": { maxNullPct: 99 }
|
|
6
|
-
|
|
7
|
-
"instrument-price-change-1d": { maxZeroPct: 100 }, // Because weekeends/holidays return 0 change, technically crypto means this can't hit 100% but it's usually quite close, so we override
|
|
8
|
-
"instrument-price-momentum-20d ": { maxZeroPct: 100 }, // Some assets can be very stagnant over a month, especially bonds or stablecoins
|
|
9
|
-
"mimetic-latency": { maxFlatlinePct: 100 },
|
|
10
|
-
};
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Factory for creating the Computation Context.
|
|
3
|
-
* UPDATED: Injects verification and rankings data into context globally and locally.
|
|
4
|
-
* UPDATED: Added support for historical ranking data in both Standard and Meta contexts.
|
|
5
|
-
* UPDATED: Added support for 'series' data (historical root data or computation results) in Global Data.
|
|
6
|
-
* UPDATED: Added 'utils.fetchLatest' to support on-demand BigQuery fallback.
|
|
7
|
-
*/
|
|
8
|
-
const mathLayer = require('../layers/index');
|
|
9
|
-
const DataLoader = require('../utils/data_loader'); // [NEW] Import DataLoader
|
|
10
|
-
const { LEGACY_MAPPING } = require('../topology/HashManager');
|
|
11
|
-
|
|
12
|
-
class ContextFactory {
|
|
13
|
-
static buildMathContext() {
|
|
14
|
-
const mathContext = {};
|
|
15
|
-
for (const [key, value] of Object.entries(mathLayer)) {
|
|
16
|
-
mathContext[key] = value;
|
|
17
|
-
const legacyKey = LEGACY_MAPPING[key];
|
|
18
|
-
if (legacyKey) { mathContext[legacyKey] = value; }
|
|
19
|
-
}
|
|
20
|
-
return mathContext;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static buildPerUserContext(options) {
|
|
24
|
-
const {
|
|
25
|
-
todayPortfolio,
|
|
26
|
-
yesterdayPortfolio,
|
|
27
|
-
todayHistory,
|
|
28
|
-
yesterdayHistory,
|
|
29
|
-
userId,
|
|
30
|
-
userType,
|
|
31
|
-
dateStr,
|
|
32
|
-
metadata,
|
|
33
|
-
mappings,
|
|
34
|
-
insights,
|
|
35
|
-
socialData,
|
|
36
|
-
computedDependencies,
|
|
37
|
-
previousComputedDependencies,
|
|
38
|
-
config,
|
|
39
|
-
deps,
|
|
40
|
-
verification,
|
|
41
|
-
rankings,
|
|
42
|
-
yesterdayRankings,
|
|
43
|
-
allRankings,
|
|
44
|
-
allRankingsYesterday,
|
|
45
|
-
allVerifications,
|
|
46
|
-
ratings,
|
|
47
|
-
pageViews,
|
|
48
|
-
watchlistMembership,
|
|
49
|
-
alertHistory,
|
|
50
|
-
piMasterList,
|
|
51
|
-
seriesData
|
|
52
|
-
} = options;
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
user: {
|
|
56
|
-
id: userId,
|
|
57
|
-
type: userType,
|
|
58
|
-
portfolio: { today: todayPortfolio, yesterday: yesterdayPortfolio },
|
|
59
|
-
history: { today: todayHistory, yesterday: yesterdayHistory },
|
|
60
|
-
verification: verification || null,
|
|
61
|
-
rankEntry: rankings || null,
|
|
62
|
-
rankEntryYesterday: yesterdayRankings || null
|
|
63
|
-
},
|
|
64
|
-
date: { today: dateStr },
|
|
65
|
-
insights: { today: insights?.today, yesterday: insights?.yesterday },
|
|
66
|
-
social: { today: socialData?.today, yesterday: socialData?.yesterday },
|
|
67
|
-
mappings: mappings || {},
|
|
68
|
-
math: ContextFactory.buildMathContext(),
|
|
69
|
-
computed: computedDependencies || {},
|
|
70
|
-
previousComputed: previousComputedDependencies || {},
|
|
71
|
-
meta: metadata, config, deps,
|
|
72
|
-
|
|
73
|
-
// [NEW] UTILS FOR ON-DEMAND FETCHING
|
|
74
|
-
utils: {
|
|
75
|
-
fetchLatest: async (rootType, lookbackDays) => {
|
|
76
|
-
return DataLoader.fetchLatestRootData(config, deps, rootType, userId, userType, lookbackDays);
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
globalData: {
|
|
81
|
-
rankings: allRankings || [],
|
|
82
|
-
rankingsYesterday: allRankingsYesterday || [],
|
|
83
|
-
verifications: allVerifications || {},
|
|
84
|
-
ratings: ratings || {},
|
|
85
|
-
pageViews: pageViews || {},
|
|
86
|
-
watchlistMembership: watchlistMembership || {},
|
|
87
|
-
alertHistory: alertHistory || {},
|
|
88
|
-
piMasterList: piMasterList || {},
|
|
89
|
-
series: seriesData || {}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
static buildMetaContext(options) {
|
|
95
|
-
// ... (No changes needed for MetaContext yet)
|
|
96
|
-
const {
|
|
97
|
-
dateStr,
|
|
98
|
-
metadata,
|
|
99
|
-
mappings,
|
|
100
|
-
insights,
|
|
101
|
-
socialData,
|
|
102
|
-
prices,
|
|
103
|
-
computedDependencies,
|
|
104
|
-
previousComputedDependencies,
|
|
105
|
-
config,
|
|
106
|
-
deps,
|
|
107
|
-
allRankings,
|
|
108
|
-
allRankingsYesterday,
|
|
109
|
-
allVerifications,
|
|
110
|
-
ratings,
|
|
111
|
-
pageViews,
|
|
112
|
-
watchlistMembership,
|
|
113
|
-
alertHistory,
|
|
114
|
-
seriesData,
|
|
115
|
-
piMasterList
|
|
116
|
-
} = options;
|
|
117
|
-
|
|
118
|
-
return {
|
|
119
|
-
date: { today: dateStr },
|
|
120
|
-
insights: { today: insights?.today, yesterday: insights?.yesterday },
|
|
121
|
-
social: { today: socialData?.today, yesterday: socialData?.yesterday },
|
|
122
|
-
prices: prices || {},
|
|
123
|
-
mappings: mappings || {},
|
|
124
|
-
math: ContextFactory.buildMathContext(),
|
|
125
|
-
computed: computedDependencies || {},
|
|
126
|
-
previousComputed: previousComputedDependencies || {},
|
|
127
|
-
meta: metadata, config, deps,
|
|
128
|
-
globalData: {
|
|
129
|
-
rankings: allRankings || [],
|
|
130
|
-
rankingsYesterday: allRankingsYesterday || [],
|
|
131
|
-
verifications: allVerifications || {},
|
|
132
|
-
ratings: ratings || {},
|
|
133
|
-
pageViews: pageViews || {},
|
|
134
|
-
watchlistMembership: watchlistMembership || {},
|
|
135
|
-
alertHistory: alertHistory || {},
|
|
136
|
-
series: seriesData || {},
|
|
137
|
-
piMasterList: piMasterList || {}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
module.exports = { ContextFactory };
|