bulltrackers-module 1.0.781 → 1.0.783
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-v3/DOCS/Computations.MD +235 -0
- package/functions/computation-system-v3/DOCS/VerificationProtocol.md +54 -0
- package/functions/computation-system-v3/DOCS.MD +144 -0
- package/functions/computation-system-v3/MemoryAdapters.js +110 -0
- package/functions/computation-system-v3/V2-to-V3.plan.md +413 -0
- package/functions/computation-system-v3/computations/BehavioralAnomaly.js +564 -0
- package/functions/computation-system-v3/computations/GlobalAumPerAsset30D.js +87 -0
- package/functions/computation-system-v3/computations/NewSectorExposure.js +185 -0
- package/functions/computation-system-v3/computations/NewSocialPost.js +125 -0
- package/functions/computation-system-v3/computations/PIDailyAssetAUM.js +143 -0
- package/functions/computation-system-v3/computations/PiFeatureVectors.js +190 -0
- package/functions/computation-system-v3/computations/PiRecommender.js +276 -0
- package/functions/computation-system-v3/computations/PopularInvestorProfileMetrics.js +432 -0
- package/functions/computation-system-v3/computations/PositionInvestedIncrease.js +167 -0
- package/functions/computation-system-v3/computations/RecipeAudit.report.md +38 -0
- package/functions/computation-system-v3/computations/RiskScoreIncrease.js +129 -0
- package/functions/computation-system-v3/computations/SectorCorrelations.js +185 -0
- package/functions/computation-system-v3/computations/SignedInUserMirrorHistory.js +139 -0
- package/functions/computation-system-v3/computations/SignedInUserPIProfileMetrics.js +120 -0
- package/functions/computation-system-v3/computations/SignedInUserProfileMetrics.js +316 -0
- package/functions/computation-system-v3/computations/index.js +36 -0
- package/functions/computation-system-v3/config/bulltrackers.config.js +129 -0
- package/functions/computation-system-v3/core-api.js +120 -0
- package/functions/computation-system-v3/debug-decision-tree.js +81 -0
- package/functions/computation-system-v3/debug-live-run.js +146 -0
- package/functions/computation-system-v3/framework/adapters/CloudTasks.js +254 -0
- package/functions/computation-system-v3/framework/adapters/StateRepository.js +256 -0
- package/functions/computation-system-v3/framework/adapters/StorageManager.js +176 -0
- package/functions/computation-system-v3/framework/adapters/bigquery/MaterializedViewManager.js +143 -0
- package/functions/{computation-system-v2/framework/data → computation-system-v3/framework/adapters/bigquery}/QueryBuilder.js +87 -98
- package/functions/computation-system-v3/framework/adapters/bigquery/SchemaRegistry.js +151 -0
- package/functions/{computation-system-v2/framework/data/DataFetcher.js → computation-system-v3/framework/adapters/bigquery/index.js} +200 -180
- package/functions/computation-system-v3/framework/bin/check-feasibility.js +205 -0
- package/functions/computation-system-v3/framework/bin/fetch-fixtures.js +58 -0
- package/functions/computation-system-v3/framework/bin/generate-graph.js +6 -0
- package/functions/computation-system-v3/framework/bin/v3-run.js +44 -0
- package/functions/computation-system-v3/framework/bin/verify-deployment.js +91 -0
- package/functions/computation-system-v3/framework/core/ContextBuilder.js +74 -0
- package/functions/computation-system-v3/framework/core/Coordinator.js +412 -0
- package/functions/computation-system-v3/framework/core/ExecutionResult.js +31 -0
- package/functions/computation-system-v3/framework/core/Manifest.js +254 -0
- package/functions/computation-system-v3/framework/core/RunAnalyzer.js +54 -0
- package/functions/computation-system-v3/framework/core/Runner.js +73 -0
- package/functions/computation-system-v3/framework/debug-local.js +27 -0
- package/functions/computation-system-v3/framework/lib/finance.js +174 -0
- package/functions/computation-system-v3/framework/lib/graph.js +193 -0
- package/functions/computation-system-v3/framework/lib/instruments.js +62 -0
- package/functions/computation-system-v3/framework/lib/math.js +144 -0
- package/functions/computation-system-v3/framework/lib/metrics.js +64 -0
- package/functions/computation-system-v3/framework/lib/portfolio.js +227 -0
- package/functions/computation-system-v3/framework/lib/rankings.js +157 -0
- package/functions/computation-system-v3/framework/lib/social.js +91 -0
- package/functions/computation-system-v3/framework/lib/time.js +174 -0
- package/functions/computation-system-v3/framework/lib/trades.js +134 -0
- package/functions/computation-system-v3/framework/middleware/Cost.js +37 -0
- package/functions/computation-system-v3/framework/middleware/Lineage.js +26 -0
- package/functions/computation-system-v3/framework/middleware/Profiler.js +29 -0
- package/functions/computation-system-v3/framework/middleware/index.js +11 -0
- package/functions/computation-system-v3/framework/scheduling/DependencyGraph.js +59 -0
- package/functions/computation-system-v3/framework/scheduling/ScheduleValidator.js +133 -0
- package/functions/computation-system-v3/framework/scheduling/TaskScheduler.js +190 -0
- package/functions/computation-system-v3/framework/testing/FileBasedDataAdapter.js +91 -0
- package/functions/computation-system-v3/framework/testing/InteractiveUtils.js +110 -0
- package/functions/computation-system-v3/framework/testing/LocalAdapters.js +139 -0
- package/functions/computation-system-v3/framework/testing/MockContext.js +49 -0
- package/functions/computation-system-v3/framework/testing/TestHarness.js +65 -0
- package/functions/computation-system-v3/framework/tests/interactive/ExplainDispatch.js +127 -0
- package/functions/computation-system-v3/framework/tests/interactive/InteractiveRunner.js +89 -0
- package/functions/computation-system-v3/framework/tests/planning/test-dispatcher-decision.js +108 -0
- package/functions/computation-system-v3/framework/tests/planning/test-planner-prediction.js +127 -0
- package/functions/computation-system-v3/framework/tests/system/CascadingDepth.test.js +155 -0
- package/functions/computation-system-v3/framework/tests/system/CircularDependency.test.js +138 -0
- package/functions/computation-system-v3/framework/tests/system/CodeChangeDetection.test.js +108 -0
- package/functions/computation-system-v3/framework/tests/system/ConcurrencyLimit.test.js +114 -0
- package/functions/computation-system-v3/framework/tests/system/CostTracking.test.js +92 -0
- package/functions/computation-system-v3/framework/tests/system/DryRunSafety.test.js +153 -0
- package/functions/computation-system-v3/framework/tests/system/FatDependency.test.js +122 -0
- package/functions/computation-system-v3/framework/tests/system/GranularInvalidation.test.js +156 -0
- package/functions/computation-system-v3/framework/tests/system/HappyPath.test.js +209 -0
- package/functions/computation-system-v3/framework/tests/system/Idempotency.test.js +145 -0
- package/functions/computation-system-v3/framework/tests/system/LostFinalizer.test.js +119 -0
- package/functions/computation-system-v3/framework/tests/system/PartialFailure.test.js +143 -0
- package/functions/computation-system-v3/framework/tests/system/PreFlightChecks.test.js +152 -0
- package/functions/computation-system-v3/framework/tests/system/ResultBasedCascading.test.js +181 -0
- package/functions/computation-system-v3/framework/tests/system/SystemIntegrity.test.js +272 -0
- package/functions/computation-system-v3/framework/tests/system/TimezoneSafety.test.js +111 -0
- package/functions/computation-system-v3/framework/tests/system/ZombieRecovery.test.js +142 -0
- package/functions/computation-system-v3/framework/tests/unit/Computation.test.js +50 -0
- package/functions/computation-system-v3/framework/tests/unit/Coordinator_Adaptive.test.js +157 -0
- package/functions/computation-system-v3/framework/tests/unit/StateRepository.test.js +144 -0
- package/functions/computation-system-v3/handlers/dispatcher.js +33 -0
- package/functions/computation-system-v3/handlers/index.js +39 -0
- package/functions/computation-system-v3/handlers/scheduler.js +26 -0
- package/functions/computation-system-v3/handlers/worker.js +41 -0
- package/functions/computation-system-v3/index.js +14 -0
- package/functions/computation-system-v3/integration-test.js +280 -0
- package/index.js +35 -35
- package/package.json +5 -3
- package/functions/computation-system-v2/README.md +0 -62
- package/functions/computation-system-v2/UserPortfolioMetrics.js +0 -50
- package/functions/computation-system-v2/computations/BehavioralAnomaly.js +0 -636
- package/functions/computation-system-v2/computations/GlobalAumPerAsset30D.js +0 -101
- package/functions/computation-system-v2/computations/NewSectorExposure.js +0 -182
- package/functions/computation-system-v2/computations/NewSocialPost.js +0 -127
- package/functions/computation-system-v2/computations/PIDailyAssetAUM.js +0 -132
- package/functions/computation-system-v2/computations/PiFeatureVectors.js +0 -181
- package/functions/computation-system-v2/computations/PiRecommender.js +0 -288
- package/functions/computation-system-v2/computations/PopularInvestorProfileMetrics.js +0 -433
- package/functions/computation-system-v2/computations/PositionInvestedIncrease.js +0 -148
- package/functions/computation-system-v2/computations/RiskScoreIncrease.js +0 -140
- package/functions/computation-system-v2/computations/SectorCorrelations.js +0 -228
- package/functions/computation-system-v2/computations/SignedInUserMirrorHistory.js +0 -121
- package/functions/computation-system-v2/computations/SignedInUserPIProfileMetrics.js +0 -106
- package/functions/computation-system-v2/computations/SignedInUserProfileMetrics.js +0 -324
- package/functions/computation-system-v2/config/bulltrackers.config.js +0 -333
- package/functions/computation-system-v2/core-api.js +0 -87
- package/functions/computation-system-v2/data_schema_reference.MD +0 -108
- package/functions/computation-system-v2/devtools/builder/builder.js +0 -362
- package/functions/computation-system-v2/devtools/builder/examples/user-metrics.yaml +0 -26
- package/functions/computation-system-v2/devtools/index.js +0 -36
- package/functions/computation-system-v2/devtools/shared/MockDataFactory.js +0 -235
- package/functions/computation-system-v2/devtools/shared/SchemaTemplates.js +0 -475
- package/functions/computation-system-v2/devtools/shared/SystemIntrospector.js +0 -517
- package/functions/computation-system-v2/devtools/shared/index.js +0 -16
- package/functions/computation-system-v2/devtools/simulation/DAGAnalyzer.js +0 -243
- package/functions/computation-system-v2/devtools/simulation/MockDataFetcher.js +0 -306
- package/functions/computation-system-v2/devtools/simulation/MockStorageManager.js +0 -336
- package/functions/computation-system-v2/devtools/simulation/SimulationEngine.js +0 -525
- package/functions/computation-system-v2/devtools/simulation/SimulationServer.js +0 -581
- package/functions/computation-system-v2/devtools/simulation/index.js +0 -17
- package/functions/computation-system-v2/devtools/simulation/simulate.js +0 -324
- package/functions/computation-system-v2/devtools/vscode-computation/package.json +0 -90
- package/functions/computation-system-v2/devtools/vscode-computation/snippets/computation.json +0 -128
- package/functions/computation-system-v2/devtools/vscode-computation/src/extension.ts +0 -401
- package/functions/computation-system-v2/devtools/vscode-computation/src/providers/codeActions.ts +0 -152
- package/functions/computation-system-v2/devtools/vscode-computation/src/providers/completions.ts +0 -207
- package/functions/computation-system-v2/devtools/vscode-computation/src/providers/diagnostics.ts +0 -205
- package/functions/computation-system-v2/devtools/vscode-computation/src/providers/hover.ts +0 -205
- package/functions/computation-system-v2/devtools/vscode-computation/tsconfig.json +0 -22
- package/functions/computation-system-v2/docs/HowToCreateComputations.MD +0 -602
- package/functions/computation-system-v2/framework/core/Computation.js +0 -73
- package/functions/computation-system-v2/framework/core/Manifest.js +0 -241
- package/functions/computation-system-v2/framework/core/RuleInjector.js +0 -53
- package/functions/computation-system-v2/framework/core/Rules.js +0 -231
- package/functions/computation-system-v2/framework/core/RunAnalyzer.js +0 -165
- package/functions/computation-system-v2/framework/cost/CostTracker.js +0 -154
- package/functions/computation-system-v2/framework/data/MaterializedViewManager.js +0 -84
- package/functions/computation-system-v2/framework/data/SchemaRegistry.js +0 -311
- package/functions/computation-system-v2/framework/execution/Orchestrator.js +0 -962
- package/functions/computation-system-v2/framework/execution/RemoteTaskRunner.js +0 -368
- package/functions/computation-system-v2/framework/execution/TaskRunner.js +0 -35
- package/functions/computation-system-v2/framework/execution/middleware/CostTrackerMiddleware.js +0 -32
- package/functions/computation-system-v2/framework/execution/middleware/LineageMiddleware.js +0 -37
- package/functions/computation-system-v2/framework/execution/middleware/Middleware.js +0 -14
- package/functions/computation-system-v2/framework/execution/middleware/ProfilerMiddleware.js +0 -35
- package/functions/computation-system-v2/framework/index.js +0 -52
- package/functions/computation-system-v2/framework/lineage/LineageTracker.js +0 -143
- package/functions/computation-system-v2/framework/monitoring/Profiler.js +0 -82
- package/functions/computation-system-v2/framework/resilience/Checkpointer.js +0 -212
- package/functions/computation-system-v2/framework/scheduling/ScheduleValidator.js +0 -325
- package/functions/computation-system-v2/framework/storage/StateRepository.js +0 -318
- package/functions/computation-system-v2/framework/storage/StorageManager.js +0 -822
- package/functions/computation-system-v2/framework/storage/index.js +0 -9
- package/functions/computation-system-v2/framework/testing/ComputationTester.js +0 -181
- package/functions/computation-system-v2/framework/utils/Graph.js +0 -205
- package/functions/computation-system-v2/handlers/adminTest.js +0 -390
- package/functions/computation-system-v2/handlers/dispatcher.js +0 -160
- package/functions/computation-system-v2/handlers/index.js +0 -40
- package/functions/computation-system-v2/handlers/onDemand.js +0 -289
- package/functions/computation-system-v2/handlers/scheduler.js +0 -365
- package/functions/computation-system-v2/handlers/worker.js +0 -171
- package/functions/computation-system-v2/index.js +0 -17
- package/functions/computation-system-v2/legacy/PiAssetRecommender.js.old +0 -115
- package/functions/computation-system-v2/legacy/PiSimilarityMatrix.js +0 -104
- package/functions/computation-system-v2/legacy/PiSimilarityVector.js +0 -71
- package/functions/computation-system-v2/rules/index.js +0 -49
- package/functions/computation-system-v2/rules/instruments.js +0 -465
- package/functions/computation-system-v2/rules/metrics.js +0 -304
- package/functions/computation-system-v2/rules/portfolio.js +0 -534
- package/functions/computation-system-v2/rules/rankings.js +0 -655
- package/functions/computation-system-v2/rules/social.js +0 -562
- package/functions/computation-system-v2/rules/trades.js +0 -545
- package/functions/computation-system-v2/scripts/debug_aggregation.js +0 -25
- package/functions/computation-system-v2/scripts/sh.md +0 -115
- package/functions/computation-system-v2/scripts/test-admin.sh +0 -223
- package/functions/computation-system-v2/scripts/test-computation-dag.js +0 -109
- package/functions/computation-system-v2/scripts/test-invalidation-scenarios.js +0 -234
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
# V3 Computation Development Guide
|
|
4
|
+
|
|
5
|
+
## 1. Core Philosophy
|
|
6
|
+
|
|
7
|
+
The V3 architecture is based on **Functional Composition**. A computation is a "Recipe" consisting of:
|
|
8
|
+
|
|
9
|
+
1. **Config:** Metadata, data requirements, and dependency graph definitions.
|
|
10
|
+
2. **Process:** A stateless, pure function that transforms inputs into outputs.
|
|
11
|
+
|
|
12
|
+
**System Constraints:**
|
|
13
|
+
|
|
14
|
+
* **Stateless:** Computations must not maintain internal state between runs.
|
|
15
|
+
* **Injection-Based:** Do not use `require()` for system libraries. All utilities are injected into the context.
|
|
16
|
+
* **Isolated:** Computations cannot directly access the database or network. They must request data via `config.requires`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 2. File Structure
|
|
21
|
+
|
|
22
|
+
Every computation is a Node.js module that must export exactly two properties: `config` and `process`.
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
/**
|
|
26
|
+
* Standard V3 Recipe Structure
|
|
27
|
+
*/
|
|
28
|
+
module.exports = {
|
|
29
|
+
config: {
|
|
30
|
+
// ... Metadata and Data Requirements
|
|
31
|
+
},
|
|
32
|
+
process: ({ data, lib, entityId, date, log }) => {
|
|
33
|
+
// ... Business Logic
|
|
34
|
+
return { /* Result Object */ };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 3. Configuration Schema (`config`)
|
|
43
|
+
|
|
44
|
+
The `config` object defines how the system prepares the execution environment.
|
|
45
|
+
|
|
46
|
+
| Field | Type | Required | Description |
|
|
47
|
+
| --- | --- | --- | --- |
|
|
48
|
+
| `name` | `string` | **Yes** | Unique CamelCase identifier (e.g., `UserVolatilityMetrics`). |
|
|
49
|
+
| `type` | `string` | **Yes** | `'per-entity'` (runs batch-wise per user/symbol) or `'global'` (runs once). |
|
|
50
|
+
| `dependencies` | `string[]` | No | Array of other computation names that must finish before this one runs. |
|
|
51
|
+
| `requires` | `Object` | No | Data fetching specification (see below). |
|
|
52
|
+
| `storage` | `Object` | No | Output destinations (defaults to BigQuery enabled). |
|
|
53
|
+
|
|
54
|
+
### 3.1 Data Requirements (`requires`)
|
|
55
|
+
|
|
56
|
+
Define what data the `BigQueryAdapter` must fetch. Keys correspond to table names or source identifiers.
|
|
57
|
+
|
|
58
|
+
```javascript
|
|
59
|
+
requires: {
|
|
60
|
+
// Example: Fetch raw portfolio snapshots
|
|
61
|
+
"portfolio_snapshots": {
|
|
62
|
+
fields: ["user_id", "timestamp", "equity", "positions"], // Columns to select
|
|
63
|
+
lookback: 30, // Days of history needed (0 = current date only)
|
|
64
|
+
mandatory: true, // If true, blocks execution if data is missing
|
|
65
|
+
filter: { // SQL WHERE clause equivalents
|
|
66
|
+
"status": "active"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
// Example: Fetch a metric from a dependency
|
|
70
|
+
"UserRiskScore": {
|
|
71
|
+
type: "metric", // Special type for previous computation results
|
|
72
|
+
source: "UserRiskScore",
|
|
73
|
+
lookback: 0
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 4. The Process Function (`process`)
|
|
82
|
+
|
|
83
|
+
The logic kernel. It receives a strictly defined `context` object.
|
|
84
|
+
|
|
85
|
+
**Signature:**
|
|
86
|
+
`(context) => Object | null`
|
|
87
|
+
|
|
88
|
+
### 4.1 The Context Object
|
|
89
|
+
|
|
90
|
+
| Property | Description |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `data` | Object containing arrays of rows keyed by the `requires` alias. |
|
|
93
|
+
| `lib` | The Standard Library (see Section 5). |
|
|
94
|
+
| `entityId` | The ID of the current entity being processed (if `type: 'per-entity'`). |
|
|
95
|
+
| `date` | The target execution date string (`YYYY-MM-DD`). |
|
|
96
|
+
| `log` | Helper function for structured logging. |
|
|
97
|
+
|
|
98
|
+
### 4.2 Return Value
|
|
99
|
+
|
|
100
|
+
* **Success:** Return a flat JSON object. Keys become columns in the results table.
|
|
101
|
+
* **Skip:** Return `null` if the entity should be skipped (e.g., insufficient history).
|
|
102
|
+
* **Failure:** Throw an `Error` to mark the entity as failed (will be logged in `computation_errors`).
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 5. The Standard Library (`lib`)
|
|
107
|
+
|
|
108
|
+
Do not write custom math or data parsing logic if a library function exists. The `lib` object is auto-injected.
|
|
109
|
+
|
|
110
|
+
**Available Modules:**
|
|
111
|
+
|
|
112
|
+
* **`lib.math`**: `mean`, `standardDeviation`, `round`, `clamp`, `percentileRank`.
|
|
113
|
+
* **`lib.finance`**: `calculateSharpeRatio`, `calculateMaxDrawdown`, `downsideDeviation`.
|
|
114
|
+
* **`lib.time`**: `parseDate`, `formatDate`, `addDays`, `subtractDays`, `getDateRange`.
|
|
115
|
+
* **`lib.portfolio`**: `extractPositions`, `calculateTotalValue`, `calculateSectorExposure`, `groupBySector`.
|
|
116
|
+
* **`lib.trades`**: `calculateTradeStats`, `filterByDateRange`, `groupByInstrument`.
|
|
117
|
+
* **`lib.social`**: `getPostEngagement`, `getRecentPosts`, `calculateEngagement`.
|
|
118
|
+
* **`lib.utils`**: General helpers.
|
|
119
|
+
|
|
120
|
+
The above is not exhaustive. Review the current lib to see available functions.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 6. Rules: Do's and Don'ts
|
|
125
|
+
|
|
126
|
+
### DO:
|
|
127
|
+
|
|
128
|
+
1. **Use `lib` functions:** Always prefer `lib.math.mean(arr)` over writing a loop to sum values.
|
|
129
|
+
2. **Handle missing data:** Check if `data.source_table` exists and has length before accessing index 0.
|
|
130
|
+
3. **Return JSON:** Ensure the output is serializable (no Functions or undefined values).
|
|
131
|
+
4. **Use `entityId`:** In `'per-entity'` mode, use `entityId` to correlate data if manually filtering (though the adapter usually handles this).
|
|
132
|
+
|
|
133
|
+
### DON'T:
|
|
134
|
+
|
|
135
|
+
1. **NO `require()`:** Never import external modules. All dependencies must be in `lib`.
|
|
136
|
+
2. **NO `this`:** Never rely on class instance context.
|
|
137
|
+
3. **NO Side Effects:** Do not attempt to write to files, call external APIs, or modify the global scope.
|
|
138
|
+
4. **NO Hardcoded Dates:** Always use `ctx.date` relative to the execution.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 7. Example Computation
|
|
143
|
+
|
|
144
|
+
**Goal:** Calculate the 30-day volatility of a user's portfolio.
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
/**
|
|
148
|
+
* Computation: UserVolatilityMetrics
|
|
149
|
+
* Calculates annualized volatility based on daily equity changes.
|
|
150
|
+
*/
|
|
151
|
+
module.exports = {
|
|
152
|
+
// 1. CONFIGURATION
|
|
153
|
+
config: {
|
|
154
|
+
name: "UserVolatilityMetrics",
|
|
155
|
+
type: "per-entity", // Batched execution per user
|
|
156
|
+
dependencies: [], // No upstream dependencies
|
|
157
|
+
requires: {
|
|
158
|
+
// Requirement 1: Daily portfolio history
|
|
159
|
+
"portfolio_daily_history": {
|
|
160
|
+
fields: ["date", "equity_usd"],
|
|
161
|
+
lookback: 30, // Need 30 days of history
|
|
162
|
+
mandatory: true
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
// 2. PROCESS LOGIC
|
|
168
|
+
process: ({ data, lib, entityId, date }) => {
|
|
169
|
+
// Access fetched data
|
|
170
|
+
const history = data.portfolio_daily_history || [];
|
|
171
|
+
|
|
172
|
+
// Validation: Need at least 2 points to calculate volatility
|
|
173
|
+
if (history.length < 2) {
|
|
174
|
+
return null; // Skip this entity
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Sort by date (ascending) using lib.time
|
|
178
|
+
// Note: Adapter usually returns sorted, but safety is good
|
|
179
|
+
history.sort((a, b) => new Date(a.date) - new Date(b.date));
|
|
180
|
+
|
|
181
|
+
// Calculate Daily Returns
|
|
182
|
+
const returns = [];
|
|
183
|
+
for (let i = 1; i < history.length; i++) {
|
|
184
|
+
const current = history[i].equity_usd;
|
|
185
|
+
const prev = history[i - 1].equity_usd;
|
|
186
|
+
|
|
187
|
+
if (prev > 0) {
|
|
188
|
+
const dailyReturn = (current - prev) / prev;
|
|
189
|
+
returns.push(dailyReturn);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Logic: Use Standard Library for Math
|
|
194
|
+
const stdev = lib.math.standardDeviation(returns);
|
|
195
|
+
const meanReturn = lib.math.mean(returns);
|
|
196
|
+
|
|
197
|
+
// Annualize (assuming 252 trading days)
|
|
198
|
+
const annualizedVolatility = stdev * Math.sqrt(252);
|
|
199
|
+
|
|
200
|
+
// Return Result
|
|
201
|
+
return {
|
|
202
|
+
calculation_date: date,
|
|
203
|
+
data_points: returns.length,
|
|
204
|
+
daily_mean_return: lib.math.round(meanReturn, 6),
|
|
205
|
+
daily_stdev: lib.math.round(stdev, 6),
|
|
206
|
+
annualized_volatility: lib.math.round(annualizedVolatility, 4),
|
|
207
|
+
is_high_risk: annualizedVolatility > 0.40 // Simple logic
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 8. Development & Testing Procedure
|
|
217
|
+
|
|
218
|
+
1. **Create File:** Create `computations/MyNewComputation.js`.
|
|
219
|
+
2. **Define Config:** Determine inputs in `requires`.
|
|
220
|
+
3. **Draft Logic:** Write the `process` function using `lib`.
|
|
221
|
+
4. **Unit Test:**
|
|
222
|
+
* Create `tests/unit/MyNewComputation.test.js`.
|
|
223
|
+
* Use `createTestContext` to inject mock data.
|
|
224
|
+
* Assert the output object.
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
5. **Integration Test (Local):**
|
|
228
|
+
* Use `framework/debug-local.js`.
|
|
229
|
+
* Modify the script to target your new computation.
|
|
230
|
+
* Run `node framework/debug-local.js [YYYY-MM-DD] MyNewComputation`.
|
|
231
|
+
|
|
232
|
+
5. **Schema Verification:**
|
|
233
|
+
* Use `framework/bin/fetch-fixtures.js`
|
|
234
|
+
* This gives the real data from big query, taken from the tables defined in configs, stored into a fixtures directory
|
|
235
|
+
* Run this to allow computations to be tested on real data, locally stored, mocks can be directed to use the local fixtures.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
### The Protocol Documentation
|
|
2
|
+
|
|
3
|
+
```markdown
|
|
4
|
+
# V3 Deployment Verification Protocol
|
|
5
|
+
|
|
6
|
+
Before merging to `main` or deploying to Cloud Functions, all changes must pass the **Verification Protocol**. This protocol runs tests in a specific dependency order to fail fast and ensure system integrity.
|
|
7
|
+
|
|
8
|
+
## 🏃 Running the Protocol
|
|
9
|
+
|
|
10
|
+
From the project root:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Make the script executable (first time only)
|
|
14
|
+
chmod +x framework/bin/verify-deployment.js
|
|
15
|
+
|
|
16
|
+
# Run the full protocol
|
|
17
|
+
node framework/bin/verify-deployment.js
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 🏗 Protocol Tiers
|
|
22
|
+
|
|
23
|
+
The script executes test suites in the following order. If a tier fails, the script **aborts immediately**.
|
|
24
|
+
|
|
25
|
+
### Tier 1: Unit Logic (`framework/tests/unit/`)
|
|
26
|
+
|
|
27
|
+
* **What it tests:** Individual recipes (e.g., `UserPortfolioMetrics`), math libraries, and utility functions.
|
|
28
|
+
* **Speed:** Very Fast (< 2s).
|
|
29
|
+
* **Goal:** Ensure the *business logic* is correct before checking if the system can run it.
|
|
30
|
+
* **Example Source:** `UserPortfolioMetrics.test.js`
|
|
31
|
+
|
|
32
|
+
### Tier 2: Planning & Integrity (`framework/tests/planning/`)
|
|
33
|
+
|
|
34
|
+
* **What it tests:** `Manifest.js`, `TaskScheduler`, and Hashing logic.
|
|
35
|
+
* **Speed:** Fast (~5s).
|
|
36
|
+
* **Goal:** Ensure the *Dependency Graph (DAG)* constructs correctly and the scheduler detects changes accurately.
|
|
37
|
+
* **Example Source:** `test-dispatcher-decision.js`, `test-planner-prediction.js`
|
|
38
|
+
|
|
39
|
+
### Tier 3: System Simulation (`framework/tests/system/`)
|
|
40
|
+
|
|
41
|
+
* **What it tests:** The `Coordinator`, `CloudTasks` mocks, and end-to-end flows like `HappyPath` and `CascadingDepth`.
|
|
42
|
+
* **Speed:** Slower (10s+).
|
|
43
|
+
* **Goal:** Ensure the V3 Core acts correctly (dispatching, retrying, state updates) when running the logic.
|
|
44
|
+
* **Example Source:** `HappyPath.test.js`, `CascadingDepth.test.js`
|
|
45
|
+
|
|
46
|
+
## 🚨 Troubleshooting Failures
|
|
47
|
+
|
|
48
|
+
* **Unit Failure:** You likely broke a calculation. Check the specific recipe file.
|
|
49
|
+
* **Planning Failure:** You likely introduced a circular dependency or invalid config in a recipe's `index.js`.
|
|
50
|
+
* **System Failure:** The Core infrastructure (Coordinator/Worker) is likely broken, or your mocks are out of sync with reality.
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
# Computation System V3: Debugging & Testing Toolkit
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
System V3 is designed around the principle of **"Trivial Testability."** Unlike V2, you do not need to deploy to Google Cloud, check logs in the console, or wait for scheduled runs to verify your logic.
|
|
8
|
+
|
|
9
|
+
We provide a **Local Test Harness** that completely mimics the production environment (Coordinator, Storage, State, and Cloud Tasks) directly on your laptop, using real data snapshots.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🛠 Core CLI Tools
|
|
14
|
+
|
|
15
|
+
### 1. The Fixture Fetcher
|
|
16
|
+
|
|
17
|
+
**Script:** `node framework/bin/fetch-fixtures.js [Date]`
|
|
18
|
+
|
|
19
|
+
This tool connects to BigQuery and downloads a "slice" of production data relevant to the specific date you want to test. It handles lookback windows automatically (e.g., fetching 30 days of price history for a specific date).
|
|
20
|
+
|
|
21
|
+
* **Usage:**
|
|
22
|
+
```bash
|
|
23
|
+
# Fetch data required to run calculations for Feb 2nd, 2026
|
|
24
|
+
node framework/bin/fetch-fixtures.js 2026-02-02
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
* **What it does:**
|
|
30
|
+
* Reads `config/bulltrackers.config.js` to find all table definitions.
|
|
31
|
+
* Executes smart queries (using `DATE_SUB` logic) to get relevant history.
|
|
32
|
+
* Saves data as JSON files in `tests/fixtures/`.
|
|
33
|
+
* **Note:** If no date is provided, it defaults to *today*.
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### 2. The Local Harness
|
|
38
|
+
|
|
39
|
+
**Script:** `node framework/debug-local.js [Date] [ComputationName]`
|
|
40
|
+
|
|
41
|
+
This is the main runner. It initializes the V3 Core with **Local Adapters** instead of Cloud Adapters. It reads from your local JSON fixtures and writes results to a local folder.
|
|
42
|
+
|
|
43
|
+
* **Usage:**
|
|
44
|
+
```bash
|
|
45
|
+
# Run the BehavioralAnomaly recipe for the date we just fetched
|
|
46
|
+
node framework/debug-local.js 2026-02-02 BehavioralAnomaly
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
* **What it does:**
|
|
52
|
+
* **Mocks BigQuery:** Reads from `tests/fixtures/{table}.json`.
|
|
53
|
+
* **Mocks Cloud Tasks:** Executes "worker" tasks immediately in-memory (using `setImmediate`).
|
|
54
|
+
* **Mocks State:** Writes status updates to `debug-out/state/`.
|
|
55
|
+
* **Mocks Storage:** Writes final JSON results to `debug-out/results/`.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 📂 Directory Structure & Outputs
|
|
62
|
+
|
|
63
|
+
When you run the tools, they interact with these specific directories:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
computation-system-v3/
|
|
67
|
+
├── computations/ # [INPUT] Your Recipe Logic (e.g., BehavioralAnomaly.js)
|
|
68
|
+
│
|
|
69
|
+
├── tests/
|
|
70
|
+
│ └── fixtures/ # [INPUT] Data snapshot from BigQuery
|
|
71
|
+
│ ├── portfolio_snapshots.json
|
|
72
|
+
│ ├── asset_prices.json
|
|
73
|
+
│ └── ...
|
|
74
|
+
│
|
|
75
|
+
├── debug-out/ # [OUTPUT] Generated by debug-local.js
|
|
76
|
+
│ ├── state/
|
|
77
|
+
│ │ └── computation_state.json # Tracks status (running -> completed)
|
|
78
|
+
│ │
|
|
79
|
+
│ └── results/ # The Final JSON Output
|
|
80
|
+
│ └── BehavioralAnomaly_2026-02-02_{timestamp}.json
|
|
81
|
+
│
|
|
82
|
+
└── framework/
|
|
83
|
+
├── bin/fetch-fixtures.js # Tool 1
|
|
84
|
+
└── debug-local.js # Tool 2
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 🚀 Workflow: How to Develop & Test a Recipe
|
|
91
|
+
|
|
92
|
+
Follow this loop when building or fixing a computation.
|
|
93
|
+
|
|
94
|
+
### Step 1: Get Real Data
|
|
95
|
+
|
|
96
|
+
Don't guess what the data looks like. Download a real snapshot.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
node framework/bin/fetch-fixtures.js 2023-10-25
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
*Tip: Pick a date where you know "interesting" things happened (e.g., a market crash or a user anomaly).*
|
|
104
|
+
|
|
105
|
+
### Step 2: Write/Modify Your Recipe
|
|
106
|
+
|
|
107
|
+
Edit your file in `computations/`. Remember, V3 recipes must be **stateless**.
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
exports.process = ({ data, lib }) => {
|
|
111
|
+
// ... your logic ...
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Step 3: Run Locally
|
|
117
|
+
|
|
118
|
+
Execute the harness. It runs instantly (no cloud latency).
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
node framework/debug-local.js 2023-10-25 MyRecipeName
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Step 4: Verify Output
|
|
126
|
+
|
|
127
|
+
Open the generated file in `debug-out/results/`.
|
|
128
|
+
|
|
129
|
+
* Does the JSON structure match what the frontend expects?
|
|
130
|
+
* Are the calculations correct?
|
|
131
|
+
* Did it handle edge cases (nulls, empty arrays)?
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 🧠 Best Practices
|
|
136
|
+
|
|
137
|
+
1. **Trust the Fixtures:**
|
|
138
|
+
The `FileBasedDataAdapter` is smart. It filters data exactly like the production system. If your local run works but production fails, it's likely because your local fixtures are stale. Re-run `fetch-fixtures.js`.
|
|
139
|
+
2. **Commit Small Fixtures:**
|
|
140
|
+
While `fetch-fixtures.js` grabs live data, you should keep a small set of "Golden Fixtures" in `tests/unit/data` for your automated unit tests (Jest/Mocha), so CI/CD can run without BigQuery access.
|
|
141
|
+
3. **Check the "State":**
|
|
142
|
+
If a run seems to hang or not finish, check `debug-out/state/computation_state.json`. It tells you if the system thinks it's `running`, `failed`, or `completed`.
|
|
143
|
+
4. **Simulate "Dry Runs":**
|
|
144
|
+
The harness runs in "Live Mode" by default (writing results). To test logic without writing, you can modify `debug-local.js` to pass `dryRun: true` to the `harness.run()` command.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Memory Adapters for Hybrid Testing
|
|
3
|
+
* FIX: MemoryCloudTasks now generates unique IDs per date to prevent false deduplication.
|
|
4
|
+
*/
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
|
|
9
|
+
class LocalDiskStorage {
|
|
10
|
+
constructor(baseDir) {
|
|
11
|
+
this.baseDir = baseDir;
|
|
12
|
+
if (!fs.existsSync(baseDir)) fs.mkdirSync(baseDir, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async saveResults({ entry, date, data }) {
|
|
16
|
+
const filename = `${entry.name.toLowerCase()}-${date}.json`;
|
|
17
|
+
const filePath = path.join(this.baseDir, filename);
|
|
18
|
+
let existing = {};
|
|
19
|
+
if (fs.existsSync(filePath)) {
|
|
20
|
+
try { existing = JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch (e) {}
|
|
21
|
+
}
|
|
22
|
+
const merged = { ...existing, ...data };
|
|
23
|
+
fs.writeFileSync(filePath, JSON.stringify(merged, null, 2));
|
|
24
|
+
console.log(`[Storage] Saving results to ${filePath} (Entities: ${Object.keys(merged).length})`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
readResults(computationName, date) {
|
|
28
|
+
const filename = `${computationName.toLowerCase()}-${date}.json`;
|
|
29
|
+
const filePath = path.join(this.baseDir, filename);
|
|
30
|
+
if (fs.existsSync(filePath)) {
|
|
31
|
+
try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch (e) { }
|
|
32
|
+
}
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class MemoryStateRepo {
|
|
38
|
+
constructor(storage) { this.storage = storage; }
|
|
39
|
+
|
|
40
|
+
async getDailyStatus(date) {
|
|
41
|
+
const files = fs.readdirSync(this.storage.baseDir);
|
|
42
|
+
const map = new Map();
|
|
43
|
+
files.forEach(f => {
|
|
44
|
+
if (f.includes(date)) {
|
|
45
|
+
const name = f.split('-')[0];
|
|
46
|
+
map.set(name, { status: 'completed', hash: 'MOCK_HASH', timestamp: Date.now() });
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return map;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async getResult(date, computationName) { return this.storage.readResults(computationName, date); }
|
|
53
|
+
|
|
54
|
+
async getBatchEntityResults(date, computationName, entityIds) {
|
|
55
|
+
const allResults = this.storage.readResults(computationName, date);
|
|
56
|
+
const subset = {};
|
|
57
|
+
if (Array.isArray(entityIds)) {
|
|
58
|
+
entityIds.forEach(id => { if (allResults[id]) subset[id] = allResults[id]; });
|
|
59
|
+
}
|
|
60
|
+
return subset;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async updateStatus() { return true; }
|
|
64
|
+
async findZombies() { return []; }
|
|
65
|
+
async claimZombie() {}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class MemoryCloudTasks {
|
|
69
|
+
constructor() {
|
|
70
|
+
this.queue = [];
|
|
71
|
+
this.history = [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getQueuePath() { return 'projects/test/locations/test/queues/test'; }
|
|
75
|
+
|
|
76
|
+
async createTask(parent, payload, options = {}) {
|
|
77
|
+
// [FIX] Deduplication check: Only drop if EXACT name exists
|
|
78
|
+
if (options.name && this.queue.some(t => t.name === options.name)) {
|
|
79
|
+
return { status: 'exists' };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const queuedTask = {
|
|
83
|
+
...payload,
|
|
84
|
+
id: options.name || `task-${Date.now()}-${Math.random()}`,
|
|
85
|
+
name: options.name,
|
|
86
|
+
targetDate: payload.targetDate || payload.date
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
this.queue.push(queuedTask);
|
|
90
|
+
this.history.push(queuedTask);
|
|
91
|
+
return { name: queuedTask.id };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async scheduleTask(t) {
|
|
95
|
+
// [FIX] Generate a UNIQUE name per date to prevent false deduplication
|
|
96
|
+
// Real adapter uses: root-{name}-{date}-{hash}-{random}
|
|
97
|
+
const suffix = crypto.randomBytes(3).toString('hex');
|
|
98
|
+
const dateStr = t.targetDate || t.date || 'nodate';
|
|
99
|
+
const uniqueName = `scheduled-${t.name}-${dateStr}-${suffix}`;
|
|
100
|
+
console.log(`[CloudTasks] Scheduling Task: ${uniqueName}`);
|
|
101
|
+
|
|
102
|
+
return this.createTask(null, t, { name: uniqueName });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getTasks() { return this.queue; }
|
|
106
|
+
clear() { this.queue = []; }
|
|
107
|
+
async listAndClean() { return { deleted: 0, activeKeys: new Set() }; }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = { LocalDiskStorage, MemoryStateRepo, MemoryCloudTasks };
|