aiden-shared-calculations-unified 1.0.44 → 1.0.45

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.
@@ -1,21 +1,31 @@
1
1
  /**
2
- * @fileoverview Meta-calculation (Pass 3) that analyzes "what" the crowd does
3
- * following a net deposit signal. It determines if the new capital is used to
4
- * buy *new* assets or *add* to existing ones.
2
+ * @fileoverview Meta-calculation (Pass 2) that analyzes "what" the crowd does
3
+ * following a net deposit signal.
4
+ *
5
+ * --- META REFACTOR (v2) ---
6
+ * This calc fetches *today's* dependencies from the runner, but still
7
+ * performs its own historical lookback for the *signal*.
5
8
  */
6
9
 
7
- // Note: This calculation still needs to read *historical* data for the signal.
8
- // Only same-day dependencies can be passed in-memory.
9
- // A full refactor would involve the orchestrator passing historical results
10
- // into the cache, but for now we leave the historical lookback.
11
-
12
10
  const { FieldValue } = require('@google-cloud/firestore');
13
11
 
14
12
  class CapitalDeploymentStrategy {
13
+
14
+ /**
15
+ * (NEW) Statically declare dependencies.
16
+ */
17
+ static getDependencies() {
18
+ return [
19
+ 'crowd-cash-flow-proxy',
20
+ 'new-allocation-percentage',
21
+ 'reallocation-increase-percentage'
22
+ ];
23
+ }
24
+
15
25
  constructor() {
16
26
  this.lookbackDays = 7;
17
27
  this.correlationWindow = 3; // How many days after a signal to link behavior
18
- this.depositSignalThreshold = -0.005; // Formerly -1.0
28
+ this.depositSignalThreshold = -0.005;
19
29
  }
20
30
 
21
31
  _getDateStr(baseDate, daysAgo) {
@@ -25,13 +35,14 @@ class CapitalDeploymentStrategy {
25
35
  }
26
36
 
27
37
  /**
38
+ * REFACTORED PROCESS METHOD
28
39
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
29
40
  * @param {object} dependencies The shared dependencies (db, logger).
30
41
  * @param {object} config The computation system configuration.
31
- * @param {object} computedDependencies In-memory results from previous passes.
42
+ * @param {object} fetchedDependencies In-memory results from previous passes.
32
43
  * @returns {Promise<object|null>} The analysis result or null.
33
44
  */
34
- async process(dateStr, dependencies, config, computedDependencies) {
45
+ async process(dateStr, dependencies, config, fetchedDependencies) {
35
46
  const { db, logger } = dependencies;
36
47
  const collection = config.resultsCollection;
37
48
  const resultsSub = config.resultsSubcollection || 'results';
@@ -85,9 +96,9 @@ class CapitalDeploymentStrategy {
85
96
  };
86
97
  }
87
98
 
88
- // 3. Fetch deployment data for *today* FROM IN-MEMORY CACHE
89
- const newAllocData = computedDependencies['new-allocation-percentage'];
90
- const reAllocData = computedDependencies['reallocation-increase-percentage'];
99
+ // 3. Fetch deployment data for *today* FROM `fetchedDependencies`
100
+ const newAllocData = fetchedDependencies['new-allocation-percentage'];
101
+ const reAllocData = fetchedDependencies['reallocation-increase-percentage'];
91
102
 
92
103
  // 4. Handle missing dependencies
93
104
  if (!newAllocData || !reAllocData) {
@@ -122,7 +133,6 @@ class CapitalDeploymentStrategy {
122
133
  };
123
134
  }
124
135
 
125
- // Must exist for the meta-computation runner
126
136
  async getResult() { return null; }
127
137
  reset() {}
128
138
  }
@@ -2,9 +2,22 @@
2
2
  * @fileoverview Meta-calculation (Pass 3) that tracks the performance
3
3
  * of assets that were heavily liquidated (sold) by the crowd to fund
4
4
  * a withdrawal event.
5
+ *
6
+ * --- META REFACTOR (v2) ---
7
+ * This calculation is now stateless. It declares its dependencies and
8
+ * expects them to be passed to its `process` method.
9
+ * It still loads its own price data.
5
10
  */
6
11
 
7
12
  class CapitalLiquidationPerformance {
13
+
14
+ /**
15
+ * (NEW) Statically declare dependencies.
16
+ */
17
+ static getDependencies() {
18
+ return ['cash-flow-liquidation'];
19
+ }
20
+
8
21
  constructor() {
9
22
  this.PERFORMANCE_WINDOW_DAYS = 7;
10
23
  this.dependenciesLoaded = false;
@@ -56,20 +69,21 @@ class CapitalLiquidationPerformance {
56
69
  }
57
70
 
58
71
  /**
72
+ * REFACTORED PROCESS METHOD
59
73
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
60
74
  * @param {object} dependencies The shared dependencies (db, logger, calculationUtils).
61
75
  * @param {object} config The computation system configuration.
62
- * @param {object} computedDependencies In-memory results from previous passes.
76
+ * @param {object} fetchedDependencies In-memory results from previous passes.
63
77
  * @returns {Promise<object|null>} The analysis result or null.
64
78
  */
65
- async process(dateStr, dependencies, config, computedDependencies) {
79
+ async process(dateStr, dependencies, config, fetchedDependencies) {
66
80
  const { db, logger, calculationUtils } = dependencies;
67
81
 
68
82
  // 1. Load all price/mapping data
69
83
  await this._loadDependencies(calculationUtils);
70
84
 
71
- // 2. Get dependency from in-memory cache
72
- const data = computedDependencies['cash-flow-liquidation'];
85
+ // 2. Get dependency from `fetchedDependencies`
86
+ const data = fetchedDependencies['cash-flow-liquidation'];
73
87
 
74
88
  if (!data || data.status !== 'analysis_complete') {
75
89
  logger.log('WARN', `[CapitalLiquidation] Skipping ${dateStr}, no valid 'cash-flow-liquidation' data found.`);
@@ -2,9 +2,22 @@
2
2
  * @fileoverview Meta-calculation (Pass 3) that tracks the performance
3
3
  * of capital "vintages" by analyzing the market returns of assets
4
4
  * that were bought following a crowd-wide deposit signal.
5
+ *
6
+ * --- META REFACTOR (v2) ---
7
+ * This calculation is now stateless. It declares its dependencies and
8
+ * expects them to be passed to its `process` method.
9
+ * It still loads its own price data.
5
10
  */
6
11
 
7
12
  class CapitalVintagePerformance {
13
+
14
+ /**
15
+ * (NEW) Statically declare dependencies.
16
+ */
17
+ static getDependencies() {
18
+ return ['cash-flow-deployment'];
19
+ }
20
+
8
21
  constructor() {
9
22
  this.PERFORMANCE_WINDOW_DAYS = 7;
10
23
  this.dependenciesLoaded = false;
@@ -56,20 +69,21 @@ class CapitalVintagePerformance {
56
69
  }
57
70
 
58
71
  /**
72
+ * REFACTORED PROCESS METHOD
59
73
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
60
74
  * @param {object} dependencies The shared dependencies (db, logger, calculationUtils).
61
75
  * @param {object} config The computation system configuration.
62
- * @param {object} computedDependencies In-memory results from previous passes.
76
+ * @param {object} fetchedDependencies In-memory results from previous passes.
63
77
  * @returns {Promise<object|null>} The analysis result or null.
64
78
  */
65
- async process(dateStr, dependencies, config, computedDependencies) {
79
+ async process(dateStr, dependencies, config, fetchedDependencies) {
66
80
  const { db, logger, calculationUtils } = dependencies;
67
81
 
68
82
  // 1. Load all price/mapping data
69
83
  await this._loadDependencies(calculationUtils);
70
84
 
71
- // 2. Get dependency from in-memory cache
72
- const data = computedDependencies['cash-flow-deployment'];
85
+ // 2. Get dependency from `fetchedDependencies`
86
+ const data = fetchedDependencies['cash-flow-deployment'];
73
87
 
74
88
  if (!data || data.status !== 'analysis_complete') {
75
89
  logger.log('WARN', `[CapitalVintage] Skipping ${dateStr}, no valid 'cash-flow-deployment' data found.`);
@@ -1,10 +1,27 @@
1
+ /**
2
+ * @fileoverview Correlates a crowd-wide deposit signal with the specific assets
3
+ * that are being bought with that new capital.
4
+ *
5
+ * --- META REFACTOR (v2) ---
6
+ * This calc fetches *today's* dependencies from the runner, but still
7
+ * performs its own historical lookback for the *signal*.
8
+ */
9
+
1
10
  const { FieldValue } = require('@google-cloud/firestore');
2
11
 
3
12
  class CashFlowDeployment {
13
+
14
+ /**
15
+ * (NEW) Statically declare dependencies.
16
+ */
17
+ static getDependencies() {
18
+ return ['crowd-cash-flow-proxy', 'asset-crowd-flow'];
19
+ }
20
+
4
21
  constructor() {
5
22
  this.lookbackDays = 7;
6
23
  this.correlationWindow = 3;
7
- this.depositSignalThreshold = -0.005; // Formerly -1.0
24
+ this.depositSignalThreshold = -0.005; // Negative value = deposit
8
25
  }
9
26
 
10
27
  _getDateStr(baseDate, daysAgo) {
@@ -13,21 +30,30 @@ class CashFlowDeployment {
13
30
  return date.toISOString().slice(0, 10);
14
31
  }
15
32
 
16
- async process(dateStr, dependencies, config, computedDependencies) {
33
+ /**
34
+ * REFACTORED PROCESS METHOD
35
+ * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
36
+ * @param {object} dependencies The shared dependencies (db, logger).
37
+ * @param {object} config The computation system configuration.
38
+ * @param {object} fetchedDependencies In-memory results from previous passes.
39
+ * @returns {Promise<object|null>} The analysis result or null.
40
+ */
41
+ async process(dateStr, dependencies, config, fetchedDependencies) {
17
42
  const { db, logger } = dependencies;
18
43
  const collection = config.resultsCollection;
44
+ const resultsSub = config.resultsSubcollection || 'results';
45
+ const compsSub = config.computationsSubcollection || 'computations';
19
46
 
20
- // --- MODIFICATION: Get same-day dependencies from cache ---
21
- const cashFlowData = computedDependencies['crowd-cash-flow-proxy'];
22
- const assetFlowData = computedDependencies['asset-crowd-flow'];
47
+ // 1. Get same-day dependencies from `fetchedDependencies`
48
+ const cashFlowData = fetchedDependencies['crowd-cash-flow-proxy'];
49
+ const assetFlowData = fetchedDependencies['asset-crowd-flow'];
23
50
 
24
51
  if (!cashFlowData || !assetFlowData) {
25
52
  logger.log('WARN', `[CashFlowDeployment] Missing critical in-memory dependency data for ${dateStr}. Skipping.`);
26
53
  return null;
27
54
  }
28
- // --- END MODIFICATION ---
29
55
 
30
- // --- Historical lookback for signal still uses Firestore ---
56
+ // 2. Historical lookback for signal (still uses Firestore)
31
57
  const refs = [];
32
58
  const dates = [];
33
59
  for (let i = 1; i <= this.lookbackDays; i++) {
@@ -36,18 +62,16 @@ class CashFlowDeployment {
36
62
  }
37
63
  const histRefs = dates.map(d =>
38
64
  db.collection(collection).doc(d.date)
39
- .collection('results').doc(d.category)
40
- .collection('computations').doc(d.computation)
65
+ .collection(resultsSub).doc(d.category)
66
+ .collection(compsSub).doc(d.computation)
41
67
  );
42
68
  const snapshots = await db.getAll(...histRefs);
43
69
  const dataMap = new Map();
44
70
  snapshots.forEach((snap, idx) => {
45
71
  if (snap.exists) dataMap.set(idx, snap.data());
46
72
  });
47
- // --- End historical lookback ---
48
-
49
73
 
50
- // find deposit signal
74
+ // 3. Find deposit signal
51
75
  let depositSignal = null;
52
76
  let depositSignalDay = null;
53
77
 
@@ -69,6 +93,7 @@ class CashFlowDeployment {
69
93
  };
70
94
  }
71
95
 
96
+ // 4. Check correlation window
72
97
  const daysSinceSignal = (new Date(dateStr) - new Date(depositSignalDay)) / (1000 * 60 * 60 * 24);
73
98
 
74
99
  if (daysSinceSignal <= 0 || daysSinceSignal > this.correlationWindow) {
@@ -79,13 +104,14 @@ class CashFlowDeployment {
79
104
  };
80
105
  }
81
106
 
82
- // Use the in-memory data for today
107
+ // 5. Use the in-memory data for today's analysis
83
108
  const netSpendPct = cashFlowData.components?.trading_effect || 0;
84
109
  const netDepositPct = Math.abs(depositSignal.cash_flow_effect_proxy);
85
110
 
111
+ // Find top *buys*
86
112
  const topBuys = Object.entries(assetFlowData)
87
- .filter(([ticker, data]) => data.net_crowd_flow_pct > 0)
88
- .sort(([, a], [, b]) => b.net_crowd_flow_pct - a.net_crowd_flow_pct)
113
+ .filter(([ticker, data]) => data.net_crowd_flow_pct > 0) // Find positive flow
114
+ .sort(([, a], [, b]) => b.net_crowd_flow_pct - a.net_crowd_flow_pct) // Sort descending
89
115
  .slice(0, 10)
90
116
  .map(([ticker, data]) => ({
91
117
  ticker,
@@ -98,7 +124,7 @@ class CashFlowDeployment {
98
124
  signal_date: depositSignalDay,
99
125
  days_since_signal: daysSinceSignal,
100
126
  signal_deposit_proxy_pct: netDepositPct,
101
- day_net_spend_pct: netSpendPct,
127
+ day_net_spend_pct: netSpendPct, // This value should be positive
102
128
  pct_of_deposit_deployed_today: (netSpendPct / netDepositPct) * 100,
103
129
  top_deployment_assets: topBuys
104
130
  };
@@ -1,17 +1,28 @@
1
1
  /**
2
2
  * @fileoverview Correlates a crowd-wide withdrawal signal with the specific assets
3
3
  * that are being sold (liquidated) to fund those withdrawals.
4
- * This is a meta-calculation that runs in Pass 3.
4
+ *
5
+ * --- META REFACTOR (v2) ---
6
+ * This calc fetches *today's* dependencies from the runner, but still
7
+ * performs its own historical lookback for the *signal*.
5
8
  */
6
9
 
7
10
  const { FieldValue } = require('@google-cloud/firestore');
8
11
 
9
12
  class CashFlowLiquidation {
13
+
14
+ /**
15
+ * (NEW) Statically declare dependencies.
16
+ */
17
+ static getDependencies() {
18
+ return ['crowd-cash-flow-proxy', 'asset-crowd-flow'];
19
+ }
20
+
10
21
  constructor() {
11
22
  this.lookbackDays = 7;
12
23
  this.correlationWindow = 3;
13
24
  // A positive value signals a net crowd withdrawal
14
- this.withdrawalSignalThreshold = 0.005; // Formerly 1.0
25
+ this.withdrawalSignalThreshold = 0.005;
15
26
  }
16
27
 
17
28
  _getDateStr(baseDate, daysAgo) {
@@ -21,27 +32,29 @@ class CashFlowLiquidation {
21
32
  }
22
33
 
23
34
  /**
35
+ * REFACTORED PROCESS METHOD
24
36
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
25
37
  * @param {object} dependencies The shared dependencies (db, logger).
26
38
  * @param {object} config The computation system configuration.
27
- * @param {object} computedDependencies In-memory results from previous passes.
39
+ * @param {object} fetchedDependencies In-memory results from previous passes.
28
40
  * @returns {Promise<object|null>} The analysis result or null.
29
41
  */
30
- async process(dateStr, dependencies, config, computedDependencies) {
42
+ async process(dateStr, dependencies, config, fetchedDependencies) {
31
43
  const { db, logger } = dependencies;
32
44
  const collection = config.resultsCollection;
45
+ const resultsSub = config.resultsSubcollection || 'results';
46
+ const compsSub = config.computationsSubcollection || 'computations';
33
47
 
34
- // --- MODIFICATION: Get same-day dependencies from cache ---
35
- const cashFlowData = computedDependencies['crowd-cash-flow-proxy'];
36
- const assetFlowData = computedDependencies['asset-crowd-flow'];
48
+ // 1. Get same-day dependencies from `fetchedDependencies`
49
+ const cashFlowData = fetchedDependencies['crowd-cash-flow-proxy'];
50
+ const assetFlowData = fetchedDependencies['asset-crowd-flow'];
37
51
 
38
52
  if (!cashFlowData || !assetFlowData) {
39
53
  logger.log('WARN', `[CashFlowLiquidation] Missing critical in-memory dependency data for ${dateStr}. Skipping.`);
40
54
  return null;
41
55
  }
42
- // --- END MODIFICATION ---
43
56
 
44
- // --- Historical lookback for signal still uses Firestore ---
57
+ // 2. Historical lookback for signal (still uses Firestore)
45
58
  const dates = [];
46
59
  for (let i = 1; i <= this.lookbackDays; i++) {
47
60
  const checkDate = this._getDateStr(dateStr, i);
@@ -49,16 +62,14 @@ class CashFlowLiquidation {
49
62
  }
50
63
  const refs = dates.map(d =>
51
64
  db.collection(collection).doc(d.date)
52
- .collection('results').doc(d.category)
53
- .collection('computations').doc(d.computation)
65
+ .collection(resultsSub).doc(d.category)
66
+ .collection(compsSub).doc(d.computation)
54
67
  );
55
68
  const snapshots = await db.getAll(...refs);
56
69
  const dataMap = new Map();
57
70
  snapshots.forEach((snap, idx) => {
58
71
  if (snap.exists) dataMap.set(idx, snap.data());
59
72
  });
60
- // --- End historical lookback ---
61
-
62
73
 
63
74
  // 2. Find the withdrawal signal
64
75
  let withdrawalSignal = null;
@@ -82,7 +93,8 @@ class CashFlowLiquidation {
82
93
  signal_threshold: this.withdrawalSignalThreshold
83
94
  };
84
95
  }
85
-
96
+
97
+ // 3. Check correlation window
86
98
  const daysSinceSignal = (new Date(dateStr) - new Date(withdrawalSignalDay)) / (1000 * 60 * 60 * 24);
87
99
 
88
100
  if (daysSinceSignal <= 0 || daysSinceSignal > this.correlationWindow) {
@@ -93,6 +105,7 @@ class CashFlowLiquidation {
93
105
  };
94
106
  }
95
107
 
108
+ // 4. Use in-memory data for today's analysis
96
109
  // 'trading_effect' will be negative if the crowd is net-selling
97
110
  const netSellPct = cashFlowData.components?.trading_effect || 0;
98
111
  const netWithdrawalPct = Math.abs(withdrawalSignal.cash_flow_effect_proxy);
@@ -119,7 +132,6 @@ class CashFlowLiquidation {
119
132
  };
120
133
  }
121
134
 
122
- // Must exist for the meta-computation runner
123
135
  async getResult() { return null; }
124
136
  reset() {}
125
137
  }
@@ -1,28 +1,41 @@
1
1
  /**
2
- * @fileoverview Meta-calculation (Pass 3) that correlates the asset flow
2
+ * @fileoverview Meta-calculation (Pass 2) that correlates the asset flow
3
3
  * of the "In Profit" cohort vs. the "In Loss" cohort to find
4
4
  * powerful divergence signals (e.g., profit-taking, capitulation).
5
+ *
6
+ * --- META REFACTOR (v2) ---
7
+ * This calculation is now stateless. It declares its dependencies and
8
+ * expects them to be passed to its `process` method.
5
9
  */
6
10
 
7
11
  class ProfitCohortDivergence {
12
+
13
+ /**
14
+ * (NEW) Statically declare dependencies.
15
+ */
16
+ static getDependencies() {
17
+ return ['in-profit-asset-crowd-flow', 'in-loss-asset-crowd-flow'];
18
+ }
19
+
8
20
  constructor() {
9
- this.flowThreshold = 0.005; // Min abs flow % to be considered a signal (formerly 0.5)
21
+ this.flowThreshold = 0.005; // Min abs flow %
10
22
  }
11
23
 
12
24
  /**
25
+ * REFACTORED PROCESS METHOD
13
26
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
14
27
  * @param {object} dependencies The shared dependencies (db, logger).
15
28
  * @param {object} config The computation system configuration.
16
- * @param {object} computedDependencies In-memory results from previous passes.
29
+ * @param {object} fetchedDependencies In-memory results from previous passes.
30
+ * e.g., { 'in-profit-asset-crowd-flow': ..., 'in-loss-asset-crowd-flow': ... }
17
31
  * @returns {Promise<object|null>} The analysis result or null.
18
32
  */
19
- async process(dateStr, dependencies, config, computedDependencies) {
33
+ async process(dateStr, dependencies, config, fetchedDependencies) {
20
34
  const { logger } = dependencies;
21
35
 
22
- // 1. Get dependencies directly from the new argument
23
- // Names are normalized to kebab-case by the orchestrator
24
- const profitFlowData = computedDependencies['in-profit-asset-crowd-flow'];
25
- const lossFlowData = computedDependencies['in-loss-asset-crowd-flow'];
36
+ // 1. Get dependencies
37
+ const profitFlowData = fetchedDependencies['in-profit-asset-crowd-flow'];
38
+ const lossFlowData = fetchedDependencies['in-loss-asset-crowd-flow'];
26
39
 
27
40
  // 2. Handle missing dependencies
28
41
  if (!profitFlowData || !lossFlowData) {
@@ -33,7 +46,7 @@ class ProfitCohortDivergence {
33
46
  const results = {};
34
47
  const allTickers = new Set([...Object.keys(profitFlowData), ...Object.keys(lossFlowData)]);
35
48
 
36
- // 4. Correlate
49
+ // 3. Correlate
37
50
  for (const ticker of allTickers) {
38
51
  const profitFlow = profitFlowData[ticker]?.net_crowd_flow_pct || 0;
39
52
  const lossFlow = lossFlowData[ticker]?.net_crowd_flow_pct || 0;
@@ -1,31 +1,41 @@
1
1
  /**
2
- * @fileoverview Meta-calculation (Pass 3) that correlates the asset/sector flow
2
+ * @fileoverview Meta-calculation (Pass 4) that correlates the asset/sector flow
3
3
  * of the "Smart Cohort" vs. the "Dumb Cohort" to find divergence signals.
4
4
  *
5
- * This identifies:
6
- * 1. "Capitulation": Smart cohort is buying what the dumb cohort is panic-selling.
7
- * 2. "Euphoria": Smart cohort is selling what the dumb cohort is FOMO-buying.
5
+ * --- META REFACTOR (v2) ---
6
+ * This calculation is now stateless. It declares its dependencies and
7
+ * expects them to be passed to its `process` method.
8
8
  */
9
9
 
10
10
  class SmartDumbDivergenceIndex {
11
+
12
+ /**
13
+ * (NEW) Statically declare dependencies.
14
+ */
15
+ static getDependencies() {
16
+ return ['smart-cohort-flow', 'dumb-cohort-flow'];
17
+ }
18
+
11
19
  constructor() {
12
20
  // Minimum net flow (as a percentage) to be considered a signal
13
21
  this.FLOW_THRESHOLD = 0.005; // Formerly 0.5
14
22
  }
15
23
 
16
24
  /**
25
+ * REFACTORED PROCESS METHOD
17
26
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
18
27
  * @param {object} dependencies The shared dependencies (db, logger).
19
28
  * @param {object} config The computation system configuration.
20
- * @param {object} computedDependencies In-memory results from previous passes.
29
+ * @param {object} fetchedDependencies In-memory results from previous passes.
30
+ * e.g., { 'smart-cohort-flow': ..., 'dumb-cohort-flow': ... }
21
31
  * @returns {Promise<object|null>} The analysis result or null.
22
32
  */
23
- async process(dateStr, dependencies, config, computedDependencies) {
33
+ async process(dateStr, dependencies, config, fetchedDependencies) {
24
34
  const { logger } = dependencies;
25
35
 
26
- // 1. Get dependencies from in-memory cache
27
- const smartData = computedDependencies['smart-cohort-flow'];
28
- const dumbData = computedDependencies['dumb-cohort-flow'];
36
+ // 1. Get dependencies from the new argument
37
+ const smartData = fetchedDependencies['smart-cohort-flow'];
38
+ const dumbData = fetchedDependencies['dumb-cohort-flow'];
29
39
 
30
40
  // 2. Handle missing dependencies
31
41
  if (!smartData || !dumbData) {
@@ -1,10 +1,21 @@
1
1
  /**
2
- * @fileoverview Meta-calculation (Pass 3) to correlate daily social sentiment with
3
- * the actual crowd asset flow. It identifies divergences between what the crowd
4
- * says and what they do.
2
+ * @fileoverview Meta-calculation (Pass 2) to correlate daily social sentiment with
3
+ * the actual crowd asset flow.
4
+ *
5
+ * --- META REFACTOR (v2) ---
6
+ * This calculation is now stateless. It declares its dependencies and
7
+ * expects them to be passed to its `process` method.
5
8
  */
6
9
 
7
10
  class SocialFlowCorrelation {
11
+
12
+ /**
13
+ * (NEW) Statically declare dependencies.
14
+ */
15
+ static getDependencies() {
16
+ return ['social-sentiment-aggregation', 'asset-crowd-flow'];
17
+ }
18
+
8
19
  constructor() {
9
20
  this.bullishSentimentThreshold = 70.0;
10
21
  this.bearishSentimentThreshold = 30.0;
@@ -13,18 +24,20 @@ class SocialFlowCorrelation {
13
24
  }
14
25
 
15
26
  /**
27
+ * REFACTORED PROCESS METHOD
16
28
  * @param {string} dateStr The date to run the analysis for (e.g., "2025-10-31").
17
29
  * @param {object} dependencies The shared dependencies (db, logger).
18
30
  * @param {object} config The computation system configuration.
19
- * @param {object} computedDependencies In-memory results from previous passes.
31
+ * @param {object} fetchedDependencies In-memory results from previous passes.
32
+ * e.g., { 'social-sentiment-aggregation': ..., 'asset-crowd-flow': ... }
20
33
  * @returns {Promise<object|null>} The analysis result or null.
21
34
  */
22
- async process(dateStr, dependencies, config, computedDependencies) {
35
+ async process(dateStr, dependencies, config, fetchedDependencies) {
23
36
  const { logger } = dependencies;
24
37
 
25
38
  // 1. Get dependencies from in-memory cache
26
- const socialData = computedDependencies['social-sentiment-aggregation'];
27
- const flowData = computedDependencies['asset-crowd-flow'];
39
+ const socialData = fetchedDependencies['social-sentiment-aggregation'];
40
+ const flowData = fetchedDependencies['asset-crowd-flow'];
28
41
 
29
42
  // 2. Handle missing dependencies
30
43
  if (!socialData || !flowData) {
@@ -92,7 +105,6 @@ class SocialFlowCorrelation {
92
105
  return correlationResults;
93
106
  }
94
107
 
95
- // Must exist for the meta-computation runner
96
108
  async getResult() { return null; }
97
109
  reset() {}
98
110
  }