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.
Files changed (106) hide show
  1. package/functions/computation-system-v2/README.md +152 -0
  2. package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +720 -0
  3. package/functions/computation-system-v2/computations/PopularInvestorRiskAssessment.js +176 -0
  4. package/functions/computation-system-v2/computations/PopularInvestorRiskMetrics.js +294 -0
  5. package/functions/computation-system-v2/computations/TestComputation.js +46 -0
  6. package/functions/computation-system-v2/computations/UserPortfolioSummary.js +172 -0
  7. package/functions/computation-system-v2/config/bulltrackers.config.js +317 -0
  8. package/functions/computation-system-v2/framework/core/Computation.js +73 -0
  9. package/functions/computation-system-v2/framework/core/Manifest.js +223 -0
  10. package/functions/computation-system-v2/framework/core/RuleInjector.js +53 -0
  11. package/functions/computation-system-v2/framework/core/Rules.js +231 -0
  12. package/functions/computation-system-v2/framework/core/RunAnalyzer.js +163 -0
  13. package/functions/computation-system-v2/framework/cost/CostTracker.js +154 -0
  14. package/functions/computation-system-v2/framework/data/DataFetcher.js +399 -0
  15. package/functions/computation-system-v2/framework/data/QueryBuilder.js +232 -0
  16. package/functions/computation-system-v2/framework/data/SchemaRegistry.js +287 -0
  17. package/functions/computation-system-v2/framework/execution/Orchestrator.js +498 -0
  18. package/functions/computation-system-v2/framework/execution/TaskRunner.js +35 -0
  19. package/functions/computation-system-v2/framework/execution/middleware/CostTrackerMiddleware.js +32 -0
  20. package/functions/computation-system-v2/framework/execution/middleware/LineageMiddleware.js +32 -0
  21. package/functions/computation-system-v2/framework/execution/middleware/Middleware.js +14 -0
  22. package/functions/computation-system-v2/framework/execution/middleware/ProfilerMiddleware.js +47 -0
  23. package/functions/computation-system-v2/framework/index.js +45 -0
  24. package/functions/computation-system-v2/framework/lineage/LineageTracker.js +147 -0
  25. package/functions/computation-system-v2/framework/monitoring/Profiler.js +80 -0
  26. package/functions/computation-system-v2/framework/resilience/Checkpointer.js +66 -0
  27. package/functions/computation-system-v2/framework/scheduling/ScheduleValidator.js +327 -0
  28. package/functions/computation-system-v2/framework/storage/StateRepository.js +286 -0
  29. package/functions/computation-system-v2/framework/storage/StorageManager.js +469 -0
  30. package/functions/computation-system-v2/framework/storage/index.js +9 -0
  31. package/functions/computation-system-v2/framework/testing/ComputationTester.js +86 -0
  32. package/functions/computation-system-v2/framework/utils/Graph.js +205 -0
  33. package/functions/computation-system-v2/handlers/dispatcher.js +109 -0
  34. package/functions/computation-system-v2/handlers/index.js +23 -0
  35. package/functions/computation-system-v2/handlers/onDemand.js +289 -0
  36. package/functions/computation-system-v2/handlers/scheduler.js +327 -0
  37. package/functions/computation-system-v2/index.js +163 -0
  38. package/functions/computation-system-v2/rules/index.js +49 -0
  39. package/functions/computation-system-v2/rules/instruments.js +465 -0
  40. package/functions/computation-system-v2/rules/metrics.js +304 -0
  41. package/functions/computation-system-v2/rules/portfolio.js +534 -0
  42. package/functions/computation-system-v2/rules/rankings.js +655 -0
  43. package/functions/computation-system-v2/rules/social.js +562 -0
  44. package/functions/computation-system-v2/rules/trades.js +545 -0
  45. package/functions/computation-system-v2/scripts/migrate-sectors.js +73 -0
  46. package/functions/computation-system-v2/test/test-dispatcher.js +317 -0
  47. package/functions/computation-system-v2/test/test-framework.js +500 -0
  48. package/functions/computation-system-v2/test/test-real-execution.js +166 -0
  49. package/functions/computation-system-v2/test/test-real-integration.js +194 -0
  50. package/functions/computation-system-v2/test/test-refactor-e2e.js +131 -0
  51. package/functions/computation-system-v2/test/test-results.json +31 -0
  52. package/functions/computation-system-v2/test/test-risk-metrics-computation.js +329 -0
  53. package/functions/computation-system-v2/test/test-scheduler.js +204 -0
  54. package/functions/computation-system-v2/test/test-storage.js +449 -0
  55. package/functions/orchestrator/index.js +24 -30
  56. package/index.js +8 -29
  57. package/package.json +3 -2
  58. package/functions/computation-system/WorkflowOrchestrator.js +0 -213
  59. package/functions/computation-system/config/monitoring_config.js +0 -31
  60. package/functions/computation-system/config/validation_overrides.js +0 -10
  61. package/functions/computation-system/context/ContextFactory.js +0 -143
  62. package/functions/computation-system/context/ManifestBuilder.js +0 -379
  63. package/functions/computation-system/data/AvailabilityChecker.js +0 -236
  64. package/functions/computation-system/data/CachedDataLoader.js +0 -325
  65. package/functions/computation-system/data/DependencyFetcher.js +0 -455
  66. package/functions/computation-system/executors/MetaExecutor.js +0 -279
  67. package/functions/computation-system/executors/PriceBatchExecutor.js +0 -108
  68. package/functions/computation-system/executors/StandardExecutor.js +0 -465
  69. package/functions/computation-system/helpers/computation_dispatcher.js +0 -750
  70. package/functions/computation-system/helpers/computation_worker.js +0 -375
  71. package/functions/computation-system/helpers/monitor.js +0 -64
  72. package/functions/computation-system/helpers/on_demand_helpers.js +0 -154
  73. package/functions/computation-system/layers/extractors.js +0 -1097
  74. package/functions/computation-system/layers/index.js +0 -40
  75. package/functions/computation-system/layers/mathematics.js +0 -522
  76. package/functions/computation-system/layers/profiling.js +0 -537
  77. package/functions/computation-system/layers/validators.js +0 -170
  78. package/functions/computation-system/legacy/AvailabilityCheckerOld.js +0 -388
  79. package/functions/computation-system/legacy/CachedDataLoaderOld.js +0 -357
  80. package/functions/computation-system/legacy/DependencyFetcherOld.js +0 -478
  81. package/functions/computation-system/legacy/MetaExecutorold.js +0 -364
  82. package/functions/computation-system/legacy/StandardExecutorold.js +0 -476
  83. package/functions/computation-system/legacy/computation_dispatcherold.js +0 -944
  84. package/functions/computation-system/logger/logger.js +0 -297
  85. package/functions/computation-system/persistence/ContractValidator.js +0 -81
  86. package/functions/computation-system/persistence/FirestoreUtils.js +0 -56
  87. package/functions/computation-system/persistence/ResultCommitter.js +0 -283
  88. package/functions/computation-system/persistence/ResultsValidator.js +0 -130
  89. package/functions/computation-system/persistence/RunRecorder.js +0 -142
  90. package/functions/computation-system/persistence/StatusRepository.js +0 -52
  91. package/functions/computation-system/reporter_epoch.js +0 -6
  92. package/functions/computation-system/scripts/UpdateContracts.js +0 -128
  93. package/functions/computation-system/services/SnapshotService.js +0 -148
  94. package/functions/computation-system/simulation/Fabricator.js +0 -285
  95. package/functions/computation-system/simulation/SeededRandom.js +0 -41
  96. package/functions/computation-system/simulation/SimRunner.js +0 -51
  97. package/functions/computation-system/system_epoch.js +0 -2
  98. package/functions/computation-system/tools/BuildReporter.js +0 -531
  99. package/functions/computation-system/tools/ContractDiscoverer.js +0 -144
  100. package/functions/computation-system/tools/DeploymentValidator.js +0 -536
  101. package/functions/computation-system/tools/FinalSweepReporter.js +0 -322
  102. package/functions/computation-system/topology/HashManager.js +0 -55
  103. package/functions/computation-system/topology/ManifestLoader.js +0 -47
  104. package/functions/computation-system/utils/data_loader.js +0 -675
  105. package/functions/computation-system/utils/schema_capture.js +0 -121
  106. 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
- const project = process.env.GCP_PROJECT || process.env.GOOGLE_CLOUD_PROJECT;
33
- const location = process.env.GCP_LOCATION || 'us-central1'; // Default to us-central1 if not set
34
- // Fallback URL construction or use passed override
35
- const orchestratorUrl = orchestratorUrlOverride || `https://${location}-${project}.cloudfunctions.net/orchestrator-http`;
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
- // Cloud Tasks Config
72
- const project = process.env.GCP_PROJECT || process.env.GOOGLE_CLOUD_PROJECT;
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
- oidcToken: {
151
- serviceAccountEmail: process.env.GCP_SERVICE_ACCOUNT_EMAIL
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 (Essential so tasks don't fail looking for data)
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
- // Note: We don't rollback Firestore here; manual retry or idempotency handles it.
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: Don't run if already done
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 / Helper Wrappers (Preserved for compatibility) ---
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
- // Computation System
34
- const { build: buildManifest } = require('./functions/computation-system/context/ManifestBuilder');
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
- dispatchComputationPass,
108
- handleComputationTask,
109
- dataLoader,
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 (has --startDate or --endDate)
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.732",
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 };