bulltrackers-module 1.0.731 → 1.0.733

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 (52) hide show
  1. package/functions/orchestrator/index.js +19 -17
  2. package/index.js +8 -29
  3. package/package.json +6 -5
  4. package/functions/computation-system/WorkflowOrchestrator.js +0 -213
  5. package/functions/computation-system/config/monitoring_config.js +0 -31
  6. package/functions/computation-system/config/validation_overrides.js +0 -10
  7. package/functions/computation-system/context/ContextFactory.js +0 -132
  8. package/functions/computation-system/context/ManifestBuilder.js +0 -379
  9. package/functions/computation-system/data/AvailabilityChecker.js +0 -236
  10. package/functions/computation-system/data/CachedDataLoader.js +0 -325
  11. package/functions/computation-system/data/DependencyFetcher.js +0 -455
  12. package/functions/computation-system/executors/MetaExecutor.js +0 -279
  13. package/functions/computation-system/executors/PriceBatchExecutor.js +0 -108
  14. package/functions/computation-system/executors/StandardExecutor.js +0 -465
  15. package/functions/computation-system/helpers/computation_dispatcher.js +0 -750
  16. package/functions/computation-system/helpers/computation_worker.js +0 -375
  17. package/functions/computation-system/helpers/monitor.js +0 -64
  18. package/functions/computation-system/helpers/on_demand_helpers.js +0 -154
  19. package/functions/computation-system/layers/extractors.js +0 -1097
  20. package/functions/computation-system/layers/index.js +0 -40
  21. package/functions/computation-system/layers/mathematics.js +0 -522
  22. package/functions/computation-system/layers/profiling.js +0 -537
  23. package/functions/computation-system/layers/validators.js +0 -170
  24. package/functions/computation-system/legacy/AvailabilityCheckerOld.js +0 -388
  25. package/functions/computation-system/legacy/CachedDataLoaderOld.js +0 -357
  26. package/functions/computation-system/legacy/DependencyFetcherOld.js +0 -478
  27. package/functions/computation-system/legacy/MetaExecutorold.js +0 -364
  28. package/functions/computation-system/legacy/StandardExecutorold.js +0 -476
  29. package/functions/computation-system/legacy/computation_dispatcherold.js +0 -944
  30. package/functions/computation-system/logger/logger.js +0 -297
  31. package/functions/computation-system/persistence/ContractValidator.js +0 -81
  32. package/functions/computation-system/persistence/FirestoreUtils.js +0 -56
  33. package/functions/computation-system/persistence/ResultCommitter.js +0 -283
  34. package/functions/computation-system/persistence/ResultsValidator.js +0 -130
  35. package/functions/computation-system/persistence/RunRecorder.js +0 -142
  36. package/functions/computation-system/persistence/StatusRepository.js +0 -52
  37. package/functions/computation-system/reporter_epoch.js +0 -6
  38. package/functions/computation-system/scripts/UpdateContracts.js +0 -128
  39. package/functions/computation-system/services/SnapshotService.js +0 -148
  40. package/functions/computation-system/simulation/Fabricator.js +0 -285
  41. package/functions/computation-system/simulation/SeededRandom.js +0 -41
  42. package/functions/computation-system/simulation/SimRunner.js +0 -51
  43. package/functions/computation-system/system_epoch.js +0 -2
  44. package/functions/computation-system/tools/BuildReporter.js +0 -531
  45. package/functions/computation-system/tools/ContractDiscoverer.js +0 -144
  46. package/functions/computation-system/tools/DeploymentValidator.js +0 -536
  47. package/functions/computation-system/tools/FinalSweepReporter.js +0 -322
  48. package/functions/computation-system/topology/HashManager.js +0 -55
  49. package/functions/computation-system/topology/ManifestLoader.js +0 -47
  50. package/functions/computation-system/utils/data_loader.js +0 -597
  51. package/functions/computation-system/utils/schema_capture.js +0 -121
  52. package/functions/computation-system/utils/utils.js +0 -188
@@ -1,536 +0,0 @@
1
- /**
2
- * @fileoverview Comprehensive Computation Validator
3
- * Validates computation structure, metadata, and code compliance during build
4
- * UPDATED: Added Static Dependency Verification to prove context.computed access.
5
- */
6
-
7
- const acorn = require('acorn');
8
- const walk = require('acorn-walk');
9
-
10
- // Import allowed layer exports for validation
11
- const mathLayer = require('../layers/mathematics');
12
- const extractorsLayer = require('../layers/extractors');
13
- const profilingLayer = require('../layers/profiling');
14
- const validatorsLayer = require('../layers/validators');
15
-
16
- /**
17
- * VALIDATION RULESET CONFIGURATION
18
- */
19
- const VALIDATION_RULES = {
20
- // Allowed metadata fields
21
- ALLOWED_METADATA_FIELDS: new Set([
22
- 'name', 'type', 'category', 'isPage', 'isHistorical', 'isTest',
23
- 'rootDataDependencies', 'rootDataSeries', 'dependencySeries',
24
- 'mandatoryRoots', 'canHaveMissingRoots', 'canHaveMissingSeries',
25
- 'userType', 'schedule', 'ttlDays', 'isAlertComputation',
26
- 'requiresEarliestDataDate'
27
- ]),
28
-
29
- // Valid computation types
30
- VALID_TYPES: new Set(['standard', 'meta']),
31
-
32
- // Valid user types
33
- VALID_USER_TYPES: new Set([
34
- 'all', 'normal', 'speculator', 'popular_investor', 'signed_in_user',
35
- 'NORMAL', 'SPECULATOR', 'POPULAR_INVESTOR', 'SIGNED_IN_USER'
36
- ]),
37
-
38
- // Valid root data dependencies
39
- VALID_ROOT_DATA_DEPS: new Set([
40
- 'portfolio', 'history', 'social', 'insights', 'price',
41
- 'rankings', 'verification', 'ratings', 'pageViews',
42
- 'watchlist', 'alerts', 'piMasterList'
43
- ]),
44
-
45
- // Valid schedule types
46
- VALID_SCHEDULE_TYPES: new Set(['DAILY', 'WEEKLY', 'MONTHLY']),
47
-
48
- // Context structure for 'standard' type
49
- STANDARD_CONTEXT_STRUCTURE: new Set([
50
- 'user', 'date', 'insights', 'social', 'mappings', 'math',
51
- 'computed', 'previousComputed', 'meta', 'config', 'deps',
52
- 'globalData', 'system'
53
- ]),
54
-
55
- // Context structure for 'meta' type
56
- META_CONTEXT_STRUCTURE: new Set([
57
- 'date', 'insights', 'social', 'prices', 'mappings', 'math',
58
- 'computed', 'previousComputed', 'meta', 'config', 'deps',
59
- 'globalData'
60
- ]),
61
-
62
- // Allowed layer functions (built dynamically)
63
- ALLOWED_LAYER_FUNCTIONS: new Map(),
64
-
65
- // Forbidden patterns
66
- FORBIDDEN_PATTERNS: [
67
- { pattern: /localStorage/g, message: 'localStorage is not supported in Cloud Functions' },
68
- { pattern: /sessionStorage/g, message: 'sessionStorage is not supported in Cloud Functions' },
69
- { pattern: /window\./g, message: 'window object is not available in Node.js environment' },
70
- { pattern: /document\./g, message: 'document object is not available in Node.js environment' },
71
- { pattern: /require\(/g, message: 'Dynamic require() is forbidden. Use dependency injection.' },
72
- { pattern: /eval\(/g, message: 'eval() is forbidden for security reasons' },
73
- { pattern: /Function\(/g, message: 'Function constructor is forbidden for security reasons' }
74
- ],
75
-
76
- // Warning patterns (non-blocking)
77
- WARNING_PATTERNS: [
78
- { pattern: /console\.log/g, message: 'Use context.deps.logger instead of console.log' },
79
- { pattern: /Math\.random/g, message: 'Math.random() is non-deterministic. Consider using SeededRandom for reproducibility.' },
80
- { pattern: /new Date\(\)/g, message: 'new Date() without arguments may cause timezone issues. Use context.date.today.' }
81
- ]
82
- };
83
-
84
- // Build allowed layer functions map
85
- function buildLayerFunctionsMap() {
86
- const map = new Map();
87
-
88
- const layers = {
89
- math: mathLayer,
90
- extractors: extractorsLayer,
91
- profiling: profilingLayer,
92
- validators: validatorsLayer
93
- };
94
-
95
- for (const [layerName, layerExports] of Object.entries(layers)) {
96
- for (const exportName of Object.keys(layerExports)) {
97
- const fullPath = `${layerName}.${exportName}`;
98
- map.set(fullPath, { layer: layerName, export: exportName });
99
-
100
- // Also allow direct access (e.g., MathPrimitives)
101
- map.set(exportName, { layer: layerName, export: exportName });
102
- }
103
- }
104
-
105
- return map;
106
- }
107
-
108
- VALIDATION_RULES.ALLOWED_LAYER_FUNCTIONS = buildLayerFunctionsMap();
109
-
110
- /**
111
- * MAIN VALIDATOR CLASS
112
- */
113
- class ComputationValidator {
114
- constructor() {
115
- this.errors = [];
116
- this.warnings = [];
117
- }
118
-
119
- /**
120
- * Validates a single calculation class
121
- */
122
- validate(CalcClass) {
123
- const name = CalcClass.name || 'Unknown';
124
-
125
- try {
126
- // 1. Structural Validation
127
- this.validateStructure(CalcClass, name);
128
-
129
- // 2. Metadata Validation
130
- const metadata = CalcClass.getMetadata();
131
- this.validateMetadata(metadata, name);
132
-
133
- // 3. Dependencies Validation
134
- const dependencies = CalcClass.getDependencies();
135
- this.validateDependencies(dependencies, name);
136
-
137
- // 4. Code Analysis (AST)
138
- // UPDATED: Passing dependencies to enable context.computed verification
139
- this.validateCode(CalcClass, name, metadata, dependencies);
140
-
141
- // 5. Schema Validation (if present)
142
- if (typeof CalcClass.getSchema === 'function') {
143
- this.validateSchema(CalcClass.getSchema(), name);
144
- }
145
-
146
- } catch (e) {
147
- this.errors.push(`[${name}] Validation crashed: ${e.message}`);
148
- }
149
- }
150
-
151
- /**
152
- * 1. Structural Validation
153
- */
154
- validateStructure(CalcClass, name) {
155
- const proto = CalcClass.prototype;
156
-
157
- // Required static methods
158
- if (typeof CalcClass.getMetadata !== 'function') {
159
- this.errors.push(`[${name}] Missing static getMetadata() method`);
160
- }
161
-
162
- if (typeof CalcClass.getDependencies !== 'function') {
163
- this.errors.push(`[${name}] Missing static getDependencies() method`);
164
- }
165
-
166
- // Required instance methods
167
- if (typeof proto.process !== 'function') {
168
- this.errors.push(`[${name}] Missing process() instance method`);
169
- }
170
-
171
- if (typeof proto.getResult !== 'function') {
172
- this.errors.push(`[${name}] Missing getResult() instance method`);
173
- }
174
- }
175
-
176
- /**
177
- * 2. Metadata Validation
178
- */
179
- validateMetadata(metadata, name) {
180
- if (!metadata || typeof metadata !== 'object') {
181
- this.errors.push(`[${name}] getMetadata() must return an object`);
182
- return;
183
- }
184
-
185
- // Check for unknown fields
186
- for (const field of Object.keys(metadata)) {
187
- if (!VALIDATION_RULES.ALLOWED_METADATA_FIELDS.has(field)) {
188
- this.warnings.push(`[${name}] Unknown metadata field: "${field}"`);
189
- }
190
- }
191
-
192
- // Validate type
193
- if (!metadata.type) {
194
- this.errors.push(`[${name}] Missing required metadata field: "type"`);
195
- } else if (!VALIDATION_RULES.VALID_TYPES.has(metadata.type)) {
196
- this.errors.push(`[${name}] Invalid type "${metadata.type}". Must be "standard" or "meta"`);
197
- }
198
-
199
- // Validate category
200
- if (!metadata.category) {
201
- this.warnings.push(`[${name}] Missing metadata field: "category"`);
202
- }
203
-
204
- // Validate userType (for standard computations)
205
- if (metadata.type === 'standard') {
206
- if (!metadata.userType) {
207
- this.warnings.push(`[${name}] Standard computation missing userType. Defaulting to "all"`);
208
- } else if (!VALIDATION_RULES.VALID_USER_TYPES.has(metadata.userType)) {
209
- this.errors.push(`[${name}] Invalid userType "${metadata.userType}"`);
210
- }
211
- }
212
-
213
- // Validate rootDataDependencies
214
- if (metadata.rootDataDependencies) {
215
- if (!Array.isArray(metadata.rootDataDependencies)) {
216
- this.errors.push(`[${name}] rootDataDependencies must be an array`);
217
- } else {
218
- for (const dep of metadata.rootDataDependencies) {
219
- if (!VALIDATION_RULES.VALID_ROOT_DATA_DEPS.has(dep)) {
220
- this.errors.push(`[${name}] Invalid root data dependency: "${dep}"`);
221
- }
222
- }
223
- }
224
- }
225
-
226
- // Validate schedule
227
- if (metadata.schedule) {
228
- if (!metadata.schedule.type || !VALIDATION_RULES.VALID_SCHEDULE_TYPES.has(metadata.schedule.type)) {
229
- this.errors.push(`[${name}] Invalid schedule type. Must be DAILY, WEEKLY, or MONTHLY`);
230
- }
231
-
232
- if (metadata.schedule.type === 'WEEKLY' && !metadata.schedule.days) {
233
- this.errors.push(`[${name}] Weekly schedule missing "days" array`);
234
- }
235
-
236
- if (metadata.schedule.type === 'MONTHLY' && !metadata.schedule.days) {
237
- this.errors.push(`[${name}] Monthly schedule missing "days" array`);
238
- }
239
- }
240
-
241
- // Validate TTL
242
- if (metadata.ttlDays !== undefined) {
243
- if (typeof metadata.ttlDays !== 'number' || metadata.ttlDays < 0) {
244
- this.errors.push(`[${name}] ttlDays must be a positive number`);
245
- }
246
- }
247
-
248
- // Validate boolean flags
249
- const booleanFields = ['isPage', 'isHistorical', 'isTest', 'canHaveMissingRoots', 'canHaveMissingSeries', 'isAlertComputation'];
250
- for (const field of booleanFields) {
251
- if (metadata[field] !== undefined && typeof metadata[field] !== 'boolean') {
252
- this.errors.push(`[${name}] ${field} must be a boolean`);
253
- }
254
- }
255
-
256
- // Validate series configurations
257
- if (metadata.rootDataSeries) {
258
- this.validateSeriesConfig(metadata.rootDataSeries, name, 'rootDataSeries');
259
- }
260
-
261
- if (metadata.dependencySeries) {
262
- this.validateSeriesConfig(metadata.dependencySeries, name, 'dependencySeries');
263
- }
264
- }
265
-
266
- validateSeriesConfig(seriesConfig, name, fieldName) {
267
- if (typeof seriesConfig !== 'object') {
268
- this.errors.push(`[${name}] ${fieldName} must be an object`);
269
- return;
270
- }
271
-
272
- for (const [key, config] of Object.entries(seriesConfig)) {
273
- if (typeof config === 'number') {
274
- if (config < 1 || config > 365) {
275
- this.warnings.push(`[${name}] ${fieldName}.${key} lookback of ${config} days seems unusual`);
276
- }
277
- } else if (typeof config === 'object') {
278
- if (!config.lookback || typeof config.lookback !== 'number') {
279
- this.errors.push(`[${name}] ${fieldName}.${key} missing valid lookback property`);
280
- }
281
- } else {
282
- this.errors.push(`[${name}] ${fieldName}.${key} must be a number or object with lookback`);
283
- }
284
- }
285
- }
286
-
287
- /**
288
- * 3. Dependencies Validation
289
- */
290
- validateDependencies(dependencies, name) {
291
- if (!Array.isArray(dependencies)) {
292
- this.errors.push(`[${name}] getDependencies() must return an array`);
293
- return;
294
- }
295
-
296
- // Check for self-dependency
297
- if (dependencies.includes(name)) {
298
- this.errors.push(`[${name}] Computation cannot depend on itself`);
299
- }
300
-
301
- // Warn about empty dependencies for complex calculations
302
- if (dependencies.length === 0) {
303
- this.warnings.push(`[${name}] No dependencies declared. Is this intentional?`);
304
- }
305
- }
306
-
307
- /**
308
- * 4. Code Analysis (AST-based)
309
- */
310
- validateCode(CalcClass, name, metadata, dependencies) {
311
- const processSource = CalcClass.prototype.process.toString();
312
-
313
- // Parse AST
314
- let ast;
315
- try {
316
- const wrappedSource = `class __Guard { ${processSource} }`;
317
- ast = acorn.parse(wrappedSource, { ecmaVersion: 2022, sourceType: 'script' });
318
- } catch (parseError) {
319
- this.errors.push(`[${name}] Failed to parse process() code: ${parseError.message}`);
320
- return;
321
- }
322
-
323
- // Check forbidden patterns
324
- for (const { pattern, message } of VALIDATION_RULES.FORBIDDEN_PATTERNS) {
325
- if (pattern.test(processSource)) {
326
- this.errors.push(`[${name}] ${message}`);
327
- }
328
- }
329
-
330
- // Check warning patterns
331
- for (const { pattern, message } of VALIDATION_RULES.WARNING_PATTERNS) {
332
- if (pattern.test(processSource)) {
333
- this.warnings.push(`[${name}] ${message}`);
334
- }
335
- }
336
-
337
- // AST Analysis
338
- this.analyzeContextUsage(ast, name, metadata);
339
- this.analyzeLayerUsage(ast, name);
340
- this.analyzeResultAssignment(ast, name, metadata);
341
- // UPDATED: Analyze Dependency Validity
342
- this.analyzeDependencyUsage(ast, name, dependencies);
343
- }
344
-
345
- analyzeContextUsage(ast, name, metadata) {
346
- const allowedContext = metadata.type === 'standard'
347
- ? VALIDATION_RULES.STANDARD_CONTEXT_STRUCTURE
348
- : VALIDATION_RULES.META_CONTEXT_STRUCTURE;
349
-
350
- const usedContextProps = new Set();
351
-
352
- walk.simple(ast, {
353
- MemberExpression(node) {
354
- // Check for context.PROPERTY patterns
355
- if (node.object.type === 'Identifier' && node.object.name === 'context') {
356
- if (node.property.type === 'Identifier') {
357
- usedContextProps.add(node.property.name);
358
- }
359
- }
360
- }
361
- });
362
-
363
- // Validate used context properties
364
- for (const prop of usedContextProps) {
365
- if (!allowedContext.has(prop)) {
366
- this.warnings.push(`[${name}] Unknown context property: context.${prop}`);
367
- }
368
- }
369
- }
370
-
371
- analyzeLayerUsage(ast, name) {
372
- walk.simple(ast, {
373
- MemberExpression(node) {
374
- // Check for context.math.FUNCTION patterns
375
- if (node.object.type === 'MemberExpression' &&
376
- node.object.object.type === 'Identifier' &&
377
- node.object.object.name === 'context' &&
378
- node.object.property.name === 'math') {
379
-
380
- if (node.property.type === 'Identifier') {
381
- const funcName = node.property.name;
382
-
383
- // Check if it's a known layer export
384
- if (!VALIDATION_RULES.ALLOWED_LAYER_FUNCTIONS.has(funcName)) {
385
- this.warnings.push(`[${name}] Unknown math layer function: ${funcName}`);
386
- }
387
- }
388
- }
389
- }
390
- });
391
- }
392
-
393
- /**
394
- * [NEW] Analyzes usage of context.computed to ensure variables exist
395
- */
396
- analyzeDependencyUsage(ast, name, dependencies) {
397
- const declaredSet = new Set(dependencies);
398
- const self = this;
399
-
400
- walk.simple(ast, {
401
- MemberExpression(node) {
402
- // Look for: context.computed['Key'] OR context.computed.Key
403
- if (node.object.type === 'MemberExpression' &&
404
- node.object.object.type === 'Identifier' &&
405
- node.object.object.name === 'context' &&
406
- node.object.property.name === 'computed') {
407
-
408
- let accessedKey = null;
409
-
410
- // Case 1: Dot notation (context.computed.SomeDep)
411
- if (!node.computed && node.property.type === 'Identifier') {
412
- accessedKey = node.property.name;
413
- }
414
- // Case 2: Bracket notation with string literal (context.computed['SomeDep'])
415
- else if (node.computed && node.property.type === 'Literal') {
416
- accessedKey = node.property.value;
417
- }
418
-
419
- if (accessedKey) {
420
- if (!declaredSet.has(accessedKey)) {
421
- // Check for casing mismatches to give helpful errors
422
- const caseInsensitiveMatch = dependencies.find(d => d.toLowerCase() === accessedKey.toLowerCase());
423
-
424
- if (caseInsensitiveMatch) {
425
- self.errors.push(`[${name}] Dependency Casing Mismatch: Accessed '${accessedKey}' but declared '${caseInsensitiveMatch}'. Keys are case-sensitive.`);
426
- } else {
427
- self.errors.push(`[${name}] Accessing undeclared dependency: '${accessedKey}'. Add it to getDependencies() or fix the typo.`);
428
- }
429
- }
430
- } else if (node.computed) {
431
- // Dynamic access (e.g. context.computed[someVar])
432
- self.warnings.push(`[${name}] Dynamic access to context.computed detected. Cannot statically verify dependency existence.`);
433
- }
434
- }
435
- }
436
- });
437
- }
438
-
439
- analyzeResultAssignment(ast, name, metadata) {
440
- let assignsToResults = false;
441
- let hasReturn = false;
442
-
443
- walk.simple(ast, {
444
- ReturnStatement(node) {
445
- if (node.argument !== null) hasReturn = true;
446
- },
447
- AssignmentExpression(node) {
448
- let target = node.left;
449
- while (target && target.type === 'MemberExpression') {
450
- if (target.object.type === 'ThisExpression' &&
451
- target.property.name === 'results') {
452
- assignsToResults = true;
453
- break;
454
- }
455
- target = target.object;
456
- }
457
- }
458
- });
459
-
460
- // Contract enforcement
461
- if (metadata.type === 'meta' && !hasReturn) {
462
- this.errors.push(`[${name}] Meta computation missing ReturnStatement in process()`);
463
- }
464
-
465
- if (!assignsToResults && metadata.type === 'standard') {
466
- this.warnings.push(`[${name}] Standard computation never assigns to this.results`);
467
- }
468
- }
469
-
470
- /**
471
- * 5. Schema Validation
472
- */
473
- validateSchema(schema, name) {
474
- if (!schema || typeof schema !== 'object') {
475
- this.warnings.push(`[${name}] getSchema() should return a valid JSON Schema object`);
476
- return;
477
- }
478
-
479
- // Basic schema structure check
480
- if (!schema.type) {
481
- this.warnings.push(`[${name}] Schema missing "type" field`);
482
- }
483
-
484
- // Check for common schema patterns
485
- if (schema.type === 'object') {
486
- if (!schema.properties && !schema.patternProperties) {
487
- this.warnings.push(`[${name}] Object schema has no properties or patternProperties`);
488
- }
489
- }
490
- }
491
-
492
- /**
493
- * Get validation results
494
- */
495
- getResults() {
496
- return {
497
- hasErrors: this.errors.length > 0,
498
- errors: this.errors,
499
- warnings: this.warnings
500
- };
501
- }
502
-
503
- /**
504
- * Generate formatted report
505
- */
506
- generateReport() {
507
- const divider = '='.repeat(80);
508
- const lines = [];
509
-
510
- if (this.errors.length > 0) {
511
- lines.push(`\n${divider}`);
512
- lines.push(`VALIDATION ERRORS (${this.errors.length}):`);
513
- this.errors.forEach((err, i) => {
514
- lines.push(` ${i + 1}. ${err}`);
515
- });
516
- }
517
-
518
- if (this.warnings.length > 0) {
519
- lines.push(`\n${divider}`);
520
- lines.push(`VALIDATION WARNINGS (${this.warnings.length}):`);
521
- this.warnings.forEach((warn, i) => {
522
- lines.push(` ${i + 1}. ${warn}`);
523
- });
524
- }
525
-
526
- if (this.errors.length === 0 && this.warnings.length === 0) {
527
- lines.push(`\n${divider}`);
528
- lines.push('✓ ALL VALIDATIONS PASSED');
529
- }
530
-
531
- lines.push(`${divider}\n`);
532
- return lines.join('\n');
533
- }
534
- }
535
-
536
- module.exports = { ComputationValidator, VALIDATION_RULES };