@ak--47/dungeon-master 1.3.0 → 1.3.1

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 (74) hide show
  1. package/dungeons/technical/array-of-object-lookup.js +0 -2
  2. package/dungeons/technical/simple.js +3 -4
  3. package/dungeons/technical/simplest-schema.json +5 -0
  4. package/dungeons/technical/text-generation.js +1 -1
  5. package/dungeons/vertical/ai-platform.js +192 -133
  6. package/dungeons/vertical/community.js +64 -34
  7. package/dungeons/vertical/crypto.js +333 -224
  8. package/dungeons/vertical/dating.js +228 -282
  9. package/dungeons/vertical/devtools.js +164 -62
  10. package/dungeons/vertical/ecommerce.js +240 -91
  11. package/dungeons/vertical/education.js +328 -310
  12. package/dungeons/vertical/fintech.js +437 -311
  13. package/dungeons/vertical/fitness.js +141 -58
  14. package/dungeons/vertical/food-delivery.js +298 -318
  15. package/dungeons/vertical/gaming.js +378 -231
  16. package/dungeons/vertical/healthcare.js +140 -60
  17. package/dungeons/vertical/insurance-application.js +168 -73
  18. package/dungeons/vertical/logistics.js +95 -6
  19. package/dungeons/vertical/marketplace.js +137 -51
  20. package/dungeons/vertical/media.js +241 -386
  21. package/dungeons/vertical/real-estate.js +322 -315
  22. package/dungeons/vertical/sass.js +253 -263
  23. package/dungeons/vertical/social.js +262 -206
  24. package/dungeons/vertical/travel.js +59 -16
  25. package/index.js +17 -17
  26. package/lib/core/config-validator.js +93 -21
  27. package/lib/core/context.js +10 -24
  28. package/lib/core/storage.js +6 -1
  29. package/lib/generators/events.js +11 -14
  30. package/lib/generators/funnels.js +12 -4
  31. package/lib/generators/mirror.js +3 -2
  32. package/lib/generators/product-names.js +1 -1
  33. package/lib/generators/scd.js +2 -1
  34. package/lib/generators/text.js +1 -1
  35. package/lib/orchestrators/user-loop.js +47 -47
  36. package/lib/utils/utils.js +71 -39
  37. package/package.json +1 -1
  38. package/scripts/smoke-test-all.mjs +162 -0
  39. package/scripts/verify-runner.mjs +72 -24
  40. package/types.d.ts +38 -15
  41. package/dungeons/technical/ad-spend-schema.json +0 -128
  42. package/dungeons/technical/anonymous-users-schema.json +0 -92
  43. package/dungeons/technical/array-of-object-lookup-schema.json +0 -191
  44. package/dungeons/technical/experiments-schema.json +0 -203
  45. package/dungeons/technical/foobar-schema.json +0 -362
  46. package/dungeons/technical/group-analytics-schema.json +0 -241
  47. package/dungeons/technical/mirror-strategies-schema.json +0 -84
  48. package/dungeons/technical/nested-objects-schema.json +0 -145
  49. package/dungeons/technical/retention-cadence-schema.json +0 -37
  50. package/dungeons/technical/sanity-schema.json +0 -185
  51. package/dungeons/technical/scale-test-schema.json +0 -70
  52. package/dungeons/technical/scd-schema.json +0 -467
  53. package/dungeons/technical/simple-schema.json +0 -362
  54. package/dungeons/technical/text-generation-schema.json +0 -1062
  55. package/dungeons/vertical/ai-platform-schema.json +0 -617
  56. package/dungeons/vertical/community-schema.json +0 -579
  57. package/dungeons/vertical/crypto-schema.json +0 -546
  58. package/dungeons/vertical/dating-schema.json +0 -401
  59. package/dungeons/vertical/devtools-schema.json +0 -601
  60. package/dungeons/vertical/ecommerce-schema.json +0 -604
  61. package/dungeons/vertical/education-schema.json +0 -5686
  62. package/dungeons/vertical/fintech-schema.json +0 -630
  63. package/dungeons/vertical/fitness-schema.json +0 -530
  64. package/dungeons/vertical/food-delivery-schema.json +0 -36728
  65. package/dungeons/vertical/gaming-schema.json +0 -2703
  66. package/dungeons/vertical/healthcare-schema.json +0 -549
  67. package/dungeons/vertical/insurance-application-schema.json +0 -485
  68. package/dungeons/vertical/logistics-schema.json +0 -574
  69. package/dungeons/vertical/marketplace-schema.json +0 -533
  70. package/dungeons/vertical/media-schema.json +0 -4749
  71. package/dungeons/vertical/real-estate-schema.json +0 -527
  72. package/dungeons/vertical/sass-schema.json +0 -3128
  73. package/dungeons/vertical/social-schema.json +0 -620
  74. package/dungeons/vertical/travel-schema.json +0 -580
@@ -46,85 +46,224 @@ const chance = u.initChance(SEED);
46
46
 
47
47
  /**
48
48
  * ===================================================================
49
- * ANALYTICS HOOKS (8 architected patterns)
49
+ * ANALYTICS HOOKS (10 hooks)
50
50
  * ===================================================================
51
51
  *
52
- * 1. WHALE WALLETS (everything hookpurchase value)
53
- * 2% of wallets do 60% of trade volume. Deterministic via
54
- * charCodeAt(0) % 50 === 0. Whale swaps are 50x bigger with
55
- * is_whale=true.
56
- * → Insights: "swap" total trade_amount_usd, breakdown is_whale
57
- * → Insights: "swap" count of unique users, filter is_whale = true
58
- * (expect ~2% of users, ~60% of total volume)
59
- *
60
- * 2. GAS PRICE SPIKE (event + everything hook — time-based)
61
- * Days 35-37, network congestion. Gas fees 10x on swap/transfer,
62
- * gas_spike=true. 40% of swaps in this window fail.
63
- * → Insights: "swap" avg gas_fee_usd by day
64
- * (expect massive spike at days 35-37)
65
- * → Insights: "swap" count, breakdown swap_status, filter gas_spike=true
66
- * (expect ~40% failed during spike)
67
- *
68
- * 3. TOKEN LAUNCH SURGE (event + everything hook — timed release)
69
- * Day 50, "MOON" token lists. After day 50, 25% of swaps become
70
- * MOON trades. MOON traders get 5x event volume via cloned swaps.
71
- * → Insights: "swap" total by day, breakdown moon_trade
72
- * (expect large surge after day 50)
73
- * → Insights: "swap" total trade_amount_usd, filter moon_trade=true
74
- *
75
- * 4. AIRDROP HUNTER CHURN (everything hook — churn)
76
- * Users who claim airdrops but never swap are bots. 95% of their
77
- * events after the airdrop claim are removed.
78
- * → Retention: any event, segment by users who did "claim airdrop"
79
- * (expect abysmal retention for airdrop-only users)
80
- * → Insights: "claim airdrop" unique users vs "swap" unique users
81
- *
82
- * 5. KYC FUNNEL COMPLETION (everything hook — conversion)
83
- * KYC-verified users deposit 4x more and swap 8x more (cloned
84
- * events). kyc_verified=true flagged on post-KYC events.
85
- * → Insights: "deposit" avg deposit_amount_usd, breakdown kyc_verified
86
- * (expect ~4x for verified users)
87
- * → Insights: "swap" count per user, breakdown kyc_verified
88
- *
89
- * 6. STAKE-TO-RETAIN (everything hook — retention)
90
- * Users who stake within first 14 days get 70% D60 retention
91
- * (events injected). Non-stakers lose events after day 60 to
92
- * simulate 15% retention.
93
- * → Retention: any event, segment staked_early=true vs false
94
- * (expect dramatic retention gap at D60)
95
- * → Insights: event count by day, breakdown staked_early
96
- *
97
- * 7. PRO TIER MAKER FEES (everything hook — subscription tier)
98
- * Pro users pay 0.05% maker fees (vs 0.30%). Pro users trade 6x
99
- * volume. pro_advantage=true on Pro swap events.
100
- * → Insights: "swap" avg maker_fee_pct, breakdown trading_tier
101
- * (expect Pro ~0.05, Standard ~0.30)
102
- * → Insights: "swap" total trade_amount_usd, breakdown pro_advantage
103
- *
104
- * 8. RUG-PULL AFTERMATH (everything hook — time-based churn)
105
- * Day 70, "SCAM" token rugs. Users who held SCAM (swapped it
106
- * before day 70) lose 80% of events after day 70. Flagged
107
- * rug_pull_victim=true.
108
- * → Retention: any event, segment rug_pull_victim=true vs others
109
- * (expect massive drop-off at day 70 for victims)
110
- * → Insights: any event total by day, filter rug_pull_victim=true
52
+ * NOTE: All cohort effects are HIDDEN no flag stamping. Discoverable
53
+ * via behavioral cohorts (count event per user, observe trade_amount
54
+ * distribution) or raw-prop breakdowns (token_pair, day, trading_tier).
111
55
  *
112
- * ===================================================================
113
- * ADVANCED ANALYSIS IDEAS
114
- * ===================================================================
56
+ * 1. WHALE WALLETS (everything)
57
+ *
58
+ * PATTERN: 2% of wallets (deterministic via id hash) get swap
59
+ * trade_amount_usd boosted 50x. No flag — analyst sees long-tail
60
+ * trade-amount distribution.
61
+ *
62
+ * HOW TO FIND IT IN MIXPANEL:
63
+ *
64
+ * Report 1: Trade Amount Distribution
65
+ * - Report type: Insights
66
+ * - Event: "swap"
67
+ * - Measure: Distribution of "trade_amount_usd"
68
+ * - Expected: heavy long tail; top 2% of users dominate volume
69
+ *
70
+ * Report 2: Volume Share by Top Traders Cohort
71
+ * - Cohort A: top 5% by total swap volume per user
72
+ * - Event: "swap"
73
+ * - Measure: Total of "trade_amount_usd"
74
+ * - Expected: cohort A drives ~ 60%+ of total volume
75
+ *
76
+ * REAL-WORLD ANALOGUE: Whale wallets dominate exchange volume.
77
+ *
78
+ * ---------------------------------------------------------------
79
+ * 2. GAS PRICE SPIKE (event + everything)
80
+ *
81
+ * PATTERN: Days 35-37, gas_fee_usd 10x on swap + transfer events.
82
+ * In window, 40% of swaps get swap_status flipped to "failed". No flag.
83
+ *
84
+ * HOW TO FIND IT IN MIXPANEL:
85
+ *
86
+ * Report 1: Avg Gas Fee Over Time
87
+ * - Report type: Insights
88
+ * - Event: "swap"
89
+ * - Measure: Average of "gas_fee_usd"
90
+ * - Line chart by day
91
+ * - Expected: spike days 35-37 (~10x baseline)
92
+ *
93
+ * Report 2: Swap Failure Rate Over Time
94
+ * - Report type: Insights
95
+ * - Event: "swap"
96
+ * - Measure: Total
97
+ * - Filter: swap_status = "failed"
98
+ * - Line chart by day
99
+ * - Expected: failure rate spikes during gas window
100
+ *
101
+ * REAL-WORLD ANALOGUE: Network congestion breaks transactions.
102
+ *
103
+ * ---------------------------------------------------------------
104
+ * 3. TOKEN LAUNCH SURGE (event + everything)
105
+ *
106
+ * PATTERN: Day 50+, 25% of swaps get token_pair flipped to a MOON
107
+ * pair. Each MOON swap clones 4 extra swap events with unique offset.
108
+ * No flag — discover via token_pair breakdown over time.
109
+ *
110
+ * HOW TO FIND IT IN MIXPANEL:
111
+ *
112
+ * Report 1: Swap Volume by Token Pair Over Time
113
+ * - Report type: Insights
114
+ * - Event: "swap"
115
+ * - Measure: Total
116
+ * - Filter: token_pair contains "MOON"
117
+ * - Line chart by day
118
+ * - Expected: appears at day 50, surges thereafter
119
+ *
120
+ * REAL-WORLD ANALOGUE: Meme/altcoin listings drive frenzied volume.
121
+ *
122
+ * ---------------------------------------------------------------
123
+ * 4. AIRDROP HUNTER CHURN (everything)
124
+ *
125
+ * PATTERN: 4% of users (deterministic via charCodeAt(1) % 25 === 0)
126
+ * are airdrop-farming bots. After their first "claim airdrop" event,
127
+ * 95% of subsequent events are removed.
128
+ *
129
+ * HOW TO FIND IT IN MIXPANEL:
130
+ *
131
+ * Report 1: Retention by Airdrop Claim
132
+ * - Report type: Retention
133
+ * - Event A: "claim airdrop"
134
+ * - Event B: any event
135
+ * - Expected: claimers retain dramatically worse than overall users
136
+ *
137
+ * Report 2: Airdrop Hunters vs Real Traders
138
+ * - Report type: Insights
139
+ * - Events: "claim airdrop" unique users vs "swap" unique users
140
+ * - Expected: large overlap gap — many claimers never swap again
141
+ *
142
+ * REAL-WORLD ANALOGUE: Airdrop farms are a well-known DeFi growth
143
+ * tax — bots claim free tokens and immediately abandon the platform.
144
+ *
145
+ * ---------------------------------------------------------------
146
+ * 5. KYC FUNNEL COMPLETION (everything)
147
+ *
148
+ * PATTERN: Users with kyc-completed get post-KYC deposit_amount_usd
149
+ * boosted 4x and 7 extra cloned swaps per existing post-KYC swap.
150
+ * No flag — discover via cohort builder.
151
+ *
152
+ * HOW TO FIND IT IN MIXPANEL:
153
+ *
154
+ * Report 1: Avg Deposit by KYC Cohort
155
+ * - Report type: Insights (with cohort)
156
+ * - Cohort A: users with >= 1 "kyc completed"
157
+ * - Cohort B: rest
158
+ * - Event: "deposit"
159
+ * - Measure: Average of "deposit_amount_usd"
160
+ * - Expected: A ~ 4x B
161
+ *
162
+ * REAL-WORLD ANALOGUE: KYC unlocks higher limits.
163
+ *
164
+ * ---------------------------------------------------------------
165
+ * 6. STAKE-TO-RETAIN (everything)
166
+ *
167
+ * PATTERN: Users who stake any token within first 14 days get extra
168
+ * cloned swap + portfolio events past day 60. Non-stakers lose 85% of
169
+ * post-day-60 events. No flag — discover via retention cohort.
170
+ *
171
+ * HOW TO FIND IT IN MIXPANEL:
172
+ *
173
+ * Report 1: Retention by Early Stake Cohort
174
+ * - Report type: Retention
175
+ * - Cohort A: users with >= 1 "stake" in first 14 days
176
+ * - Cohort B: rest
177
+ * - Expected: A ~ 70% D60 vs B ~ 15%
178
+ *
179
+ * REAL-WORLD ANALOGUE: Staking creates skin in the game.
180
+ *
181
+ * ---------------------------------------------------------------
182
+ * 7. PRO TIER MAKER FEES (everything)
183
+ *
184
+ * PATTERN: Pro-tier users (profile.trading_tier) get maker_fee_pct
185
+ * pinned to 0.05 (vs Standard 0.30) on swap events plus 5 extra
186
+ * cloned swaps per existing. Mutates raw prop. Discover via
187
+ * trading_tier breakdown on maker_fee_pct.
188
+ *
189
+ * HOW TO FIND IT IN MIXPANEL:
190
+ *
191
+ * Report 1: Avg Maker Fee by Tier
192
+ * - Report type: Insights
193
+ * - Event: "swap"
194
+ * - Measure: Average of "maker_fee_pct"
195
+ * - Breakdown: "trading_tier"
196
+ * - Expected: Pro ~ 0.05, Standard ~ 0.30
197
+ *
198
+ * REAL-WORLD ANALOGUE: Tiered fees retain volume traders.
199
+ *
200
+ * ---------------------------------------------------------------
201
+ * 8. RUG-PULL AFTERMATH (everything)
202
+ *
203
+ * PATTERN: ~8% of pre-day-70 swaps get token_pair flipped to a SCAM
204
+ * pair. Users who held SCAM lose 80% of post-day-70 events. No flag.
205
+ *
206
+ * HOW TO FIND IT IN MIXPANEL:
207
+ *
208
+ * Report 1: Retention by SCAM Holder Cohort
209
+ * - Report type: Retention
210
+ * - Cohort A: users with >= 1 swap where token_pair contains "SCAM"
211
+ * - Cohort B: rest
212
+ * - Expected: A retention drops sharply at day 70
213
+ *
214
+ * REAL-WORLD ANALOGUE: Rug-pulls collapse trust.
215
+ *
216
+ * ---------------------------------------------------------------
217
+ * 9. TRADING FUNNEL TIME-TO-CONVERT (funnel-post)
115
218
  *
116
- * Cross-hook patterns:
117
- * - Whale + MOON: Do whales drive the MOON token surge?
118
- * - Gas Spike + Rug Pull: Do SCAM holders panic-sell during gas spikes?
119
- * - KYC + Pro Tier: Do verified users upgrade to Pro faster?
120
- * - Stakers + Whales: Do whales stake more, or just trade?
121
- * - Airdrop Hunters + Rug Pull: Overlap between bots and victims?
219
+ * PATTERN: Pro tier users complete deposit→swap→withdrawal funnel
220
+ * 1.4x faster than baseline (factor 0.7); Standard 1.3x slower
221
+ * (factor 1.3). Mutates funnel event timestamps.
122
222
  *
123
- * Cohort analysis:
124
- * - By preferred_chain: Ethereum vs Solana engagement
125
- * - By wallet_type: MetaMask vs Phantom retention
126
- * - By trading_tier: Standard→Pro upgrade path
127
- * - By kyc_status: verified vs pending conversion rates
223
+ * HOW TO FIND IT IN MIXPANEL:
224
+ *
225
+ * Report 1: Trading Funnel Median Time-to-Convert by Tier
226
+ * - Report type: Funnels
227
+ * - Steps: "deposit" -> "swap" -> "withdrawal"
228
+ * - Measure: Median time to convert
229
+ * - Breakdown: "trading_tier"
230
+ * - Expected: Pro ~ 0.7x; Standard ~ 1.3x
231
+ *
232
+ * NOTE (funnel-post measurement): visible only via Mixpanel funnel
233
+ * median TTC. Cross-event MIN→MIN SQL queries on raw events do NOT
234
+ * show this — funnel-post adjusts gaps within funnel instances, not
235
+ * across the user's full event history.
236
+ *
237
+ * REAL-WORLD ANALOGUE: Pro traders execute faster end-to-end.
238
+ *
239
+ * ---------------------------------------------------------------
240
+ * 10. SWAP-COUNT MAGIC NUMBER (everything)
241
+ *
242
+ * PATTERN: Users with 8-20 swaps in dataset get +30% on stake
243
+ * amount_usd plus 1-2 extra cloned stake events per existing.
244
+ * Users with 21+ swaps drop 40% of portfolio-viewed events
245
+ * (over-active traders ignore portfolio review). No flag.
246
+ *
247
+ * HOW TO FIND IT IN MIXPANEL:
248
+ *
249
+ * Report 1: Avg Stake Amount by Swap-Count Bucket
250
+ * - Report type: Insights (with cohort)
251
+ * - Cohort A: users with 8-20 "swap"
252
+ * - Cohort B: users with 0-7
253
+ * - Event: "stake"
254
+ * - Measure: Average of "amount_usd"
255
+ * - Expected: A ~ 1.3x B
256
+ *
257
+ * Report 2: Portfolio Views per User on Heavy Swappers
258
+ * - Report type: Insights (with cohort)
259
+ * - Cohort C: users with >= 21 "swap"
260
+ * - Cohort A: users with 8-20
261
+ * - Event: "portfolio viewed"
262
+ * - Measure: Total per user
263
+ * - Expected: C ~ 40% fewer portfolio views per user
264
+ *
265
+ * REAL-WORLD ANALOGUE: Engaged swappers grow stake; over-active
266
+ * day-traders ignore long-term portfolio review.
128
267
  *
129
268
  * ===================================================================
130
269
  * EXPECTED METRICS SUMMARY
@@ -132,14 +271,17 @@ const chance = u.initChance(SEED);
132
271
  *
133
272
  * Hook | Metric | Baseline | Effect | Ratio
134
273
  * ----------------------|-----------------------|----------|---------|------
135
- * Whale Wallets | Avg trade_amount_usd | $200 | $10,000 | 50x
136
- * Gas Price Spike | Avg gas_fee_usd | $5 | $50 | 10x
137
- * Token Launch Surge | Swap count post-D50 | 1x | 5x | 5x
138
- * Airdrop Hunter Churn | Post-airdrop events | 100% | 5% | 0.05x
139
- * KYC Completion | Avg deposit_amount_usd| $500 | $2,000 | 4x
140
- * Stake-to-Retain | D60 retention | 15% | 70% | ~5x
141
- * Pro Tier Fees | Avg maker_fee_pct | 0.30 | 0.05 | 6x
142
- * Rug-Pull Aftermath | Post-D70 events | 100% | 20% | 0.2x
274
+ * Whale Wallets | Top 5% trade share | 5% | ~ 60% | n/a
275
+ * Gas Price Spike | gas_fee_usd days 35-7 | 1x | 10x | 10x
276
+ * Token Launch Surge | MOON pair share post-D50 | 0% | ~ 25%+ | new
277
+ * Airdrop Hunter Churn | post-airdrop events | 1x | 0.05x | -95%
278
+ * KYC Completion | deposit_amount_usd | 1x | 4x | 4x
279
+ * Stake-to-Retain | D60 retention | 15% | 70% | ~ 5x
280
+ * Pro Tier Fees | maker_fee_pct | 0.30 | 0.05 | -83%
281
+ * Rug-Pull Aftermath | victim post-D70 | 1x | 0.2x | -80%
282
+ * Trading T2C | median min by tier | 1x | 0.7x/1.3x | 1.86x range
283
+ * Swap Magic Number | sweet stake amount | 1x | 1.3x | 1.3x
284
+ * Swap Magic Number | over portfolio/user | 1x | 0.6x | -40%
143
285
  */
144
286
 
145
287
  // Token pairs used in swap events
@@ -167,7 +309,9 @@ const NFT_COLLECTIONS = [
167
309
  const config = {
168
310
  token,
169
311
  seed: SEED,
170
- numDays: num_days,
312
+ datasetStart: "2026-01-01T00:00:00Z",
313
+ datasetEnd: "2026-04-28T23:59:59Z",
314
+ // numDays: num_days,
171
315
  avgEventsPerUserPerDay: avg_events_per_user_per_day,
172
316
  numUsers: num_users,
173
317
  hasAnonIds: false,
@@ -254,7 +398,6 @@ const config = {
254
398
  deposit_amount_usd: u.weighNumRange(10, 5000, 0.3, 500),
255
399
  chain: ["Ethereum", "Solana", "Base", "Arbitrum", "Polygon"],
256
400
  deposit_method: ["wallet_transfer", "bridge", "on_ramp", "exchange_transfer"],
257
- kyc_verified: [false],
258
401
  }
259
402
  },
260
403
  {
@@ -277,13 +420,6 @@ const config = {
277
420
  swap_status: ["completed", "completed", "completed", "completed", "pending", "failed"],
278
421
  slippage_pct: u.weighNumRange(0.01, 5, 0.3, 0.5),
279
422
  maker_fee_pct: [0.30],
280
- is_whale: [false],
281
- kyc_verified: [false],
282
- gas_spike: [false],
283
- pro_advantage: [false],
284
- rug_pull_victim: [false],
285
- moon_trade: [false],
286
- staked_early: [false],
287
423
  }
288
424
  },
289
425
  {
@@ -363,7 +499,6 @@ const config = {
363
499
  amount_usd: u.weighNumRange(10, 5000, 0.3, 300),
364
500
  gas_fee_usd: u.weighNumRange(0.5, 30, 0.3, 5),
365
501
  destination_type: ["wallet", "exchange", "contract", "ens_name"],
366
- gas_spike: [false],
367
502
  }
368
503
  },
369
504
  ],
@@ -372,7 +507,6 @@ const config = {
372
507
  trading_tier: ["Standard", "Standard", "Standard", "Pro"],
373
508
  preferred_chain: ["Ethereum", "Solana", "Base", "Arbitrum", "Polygon"],
374
509
  wallet_type: ["MetaMask", "Phantom", "Coinbase Wallet", "Rainbow", "WalletConnect"],
375
- staked_early: [false],
376
510
  },
377
511
 
378
512
  userProps: {
@@ -382,70 +516,40 @@ const config = {
382
516
  total_trade_volume: u.weighNumRange(0, 500000, 0.3, 5000),
383
517
  portfolio_value: u.weighNumRange(0, 200000, 0.3, 3000),
384
518
  kyc_status: ["pending"],
385
- has_staked: [false],
386
- staked_early: [false],
387
519
  },
388
520
 
389
521
  groupKeys: [],
390
522
  groupProps: {},
391
523
  lookupTables: [],
392
524
 
393
- /**
394
- * ARCHITECTED ANALYTICS HOOKS
395
- *
396
- * This hook function creates 8 deliberate patterns in the data:
397
- *
398
- * 1. WHALE WALLETS: 2% of users (deterministic) trade 50x volume, is_whale=true
399
- * 2. GAS PRICE SPIKE: Days 35-37 gas fees 10x, 40% swaps fail, gas_spike=true
400
- * 3. TOKEN LAUNCH SURGE: Day 50+ MOON token, 25% swaps become MOON, 5x volume for MOON traders
401
- * 4. AIRDROP HUNTER CHURN: Airdrop claimers with no swaps lose 95% of events post-claim
402
- * 5. KYC COMPLETION: Verified users deposit 4x more, swap 8x more, kyc_verified=true
403
- * 6. STAKE-TO-RETAIN: Early stakers (first 14 days) get 70% D60 retention vs 15%
404
- * 7. PRO TIER FEES: Pro users pay 0.05% fees (vs 0.30%), trade 6x volume, pro_advantage=true
405
- * 8. RUG-PULL AFTERMATH: Day 70 SCAM token rugs, holders lose 80% of post-D70 events
406
- */
407
525
  hook: function (record, type, meta) {
408
- const NOW = dayjs();
409
- const DATASET_START = NOW.subtract(num_days, "days");
410
-
411
- // ===============================================================
412
- // Hook #2 (partial): GAS PRICE SPIKE (event)
413
- // Days 35-37, network congestion. Gas fees 10x on swap/transfer
414
- // events and gas_spike=true.
415
- // ===============================================================
416
- if (type === "event") {
417
- const EVENT_TIME = dayjs(record.time);
418
- const dayInDataset = EVENT_TIME.diff(DATASET_START, "day");
419
-
420
- // Gas price spike: days 35-37
421
- if (dayInDataset >= 35 && dayInDataset <= 37) {
422
- if (record.event === "swap") {
423
- record.gas_fee_usd = Math.round((record.gas_fee_usd || 5) * 10);
424
- record.gas_spike = true;
425
- }
426
- if (record.event === "transfer") {
427
- record.gas_fee_usd = Math.round((record.gas_fee_usd || 5) * 10);
428
- record.gas_spike = true;
429
- }
430
- }
431
-
432
- // ===============================================================
433
- // Hook #3 (partial): TOKEN LAUNCH SURGE (event)
434
- // After day 50, 25% of swap events get token_pair changed to
435
- // include "MOON". Tagged moon_trade=true.
436
- // ===============================================================
437
- if (record.event === "swap" && dayInDataset >= 50) {
438
- if (chance.bool({ likelihood: 25 })) {
439
- record.token_pair = chance.pickone(["MOON/USDC", "MOON/ETH", "ETH/MOON"]);
440
- record.moon_trade = true;
526
+ // HOOKS 2 + 3: GAS PRICE SPIKE and TOKEN LAUNCH SURGE moved to everything
527
+ // hook below — event hook fires before bunchIntoSessions reshuffles timestamps,
528
+ // causing day-window tags to leak across the boundary.
529
+
530
+ // HOOK 9 (T2C): TRADING FUNNEL TIME-TO-CONVERT (funnel-post)
531
+ // Pro tier users complete deposit→swap→withdrawal funnel 1.4x faster
532
+ // (factor 0.7 on inter-event gaps); Standard 1.3x slower (factor 1.3).
533
+ if (type === "funnel-post") {
534
+ const segment = meta?.profile?.trading_tier;
535
+ if (Array.isArray(record) && record.length > 1) {
536
+ const factor = (
537
+ segment === "Pro" ? 0.7 :
538
+ segment === "Standard" ? 1.3 :
539
+ 1.0
540
+ );
541
+ if (factor !== 1.0) {
542
+ for (let i = 1; i < record.length; i++) {
543
+ const prev = dayjs(record[i - 1].time);
544
+ const newGap = Math.round(dayjs(record[i].time).diff(prev) * factor);
545
+ record[i].time = prev.add(newGap, "milliseconds").toISOString();
546
+ }
441
547
  }
442
548
  }
443
549
  }
444
550
 
445
- // ===============================================================
446
- // EVERYTHING HOOK — all complex behavioral patterns
447
- // ===============================================================
448
551
  if (type === "everything") {
552
+ const datasetStart = dayjs.unix(meta.datasetStart);
449
553
  const userEvents = record;
450
554
  const profile = meta.profile;
451
555
 
@@ -454,17 +558,12 @@ const config = {
454
558
  e.trading_tier = profile.trading_tier;
455
559
  e.preferred_chain = profile.preferred_chain;
456
560
  e.wallet_type = profile.wallet_type;
457
- e.staked_early = profile.staked_early;
458
561
  });
459
562
 
460
563
  const firstEventTime = userEvents.length > 0 ? dayjs(userEvents[0].time) : null;
461
564
 
462
- // -----------------------------------------------------------
463
- // Hook #1: WHALE WALLETS
464
- // 2% of wallets do massive volume. Deterministic selection via
465
- // charCodeAt(0) % 50 === 0. Whales get 50x trade_amount_usd
466
- // on all swap events with is_whale=true.
467
- // -----------------------------------------------------------
565
+ // HOOK 1: WHALE WALLETS — 2% of users (charCodeAt(0) % 50 === 0)
566
+ // get swap trade_amount_usd boosted 50x. No flag.
468
567
  const userId = userEvents.length > 0 ? (userEvents[0].user_id || userEvents[0].distinct_id || "") : "";
469
568
  const isWhale = userId.length > 0 && userId.charCodeAt(0) % 50 === 0;
470
569
 
@@ -472,30 +571,41 @@ const config = {
472
571
  userEvents.forEach(e => {
473
572
  if (e.event === "swap") {
474
573
  e.trade_amount_usd = Math.round((e.trade_amount_usd || 200) * 50);
475
- e.is_whale = true;
476
574
  }
477
575
  });
478
576
  }
479
577
 
480
- // -----------------------------------------------------------
481
- // Hook #2 (continued): GAS PRICE SPIKE failed swaps
482
- // During days 35-37, 40% of swaps get swap_status changed to
483
- // "failed".
484
- // -----------------------------------------------------------
578
+ // HOOK 2: GAS PRICE SPIKE — days 35-37 swap+transfer gas_fee_usd 10x,
579
+ // 40% of swaps get swap_status=failed. Runs in everything hook so
580
+ // timestamp checks see post-bunchIntoSessions times.
581
+ const day35 = datasetStart.add(35, "days");
582
+ const day38 = datasetStart.add(38, "days");
485
583
  userEvents.forEach(e => {
486
- if (e.event === "swap" && e.gas_spike === true) {
487
- if (chance.bool({ likelihood: 40 })) {
584
+ if (e.event !== "swap" && e.event !== "transfer") return;
585
+ const t = dayjs(e.time);
586
+ if (t.isAfter(day35) && t.isBefore(day38)) {
587
+ e.gas_fee_usd = Math.round((e.gas_fee_usd || 5) * 10);
588
+ if (e.event === "swap" && chance.bool({ likelihood: 40 })) {
488
589
  e.swap_status = "failed";
489
590
  }
490
591
  }
491
592
  });
492
593
 
493
- // -----------------------------------------------------------
494
- // Hook #3 (continued): TOKEN LAUNCH SURGE — volume boost
495
- // Users who traded MOON get 5x swap event volume via cloned
496
- // events spread over days after day 50.
497
- // -----------------------------------------------------------
498
- const moonSwaps = userEvents.filter(e => e.event === "swap" && e.moon_trade === true);
594
+ // HOOK 3: TOKEN LAUNCH SURGE — after d50, 25% of swaps flip token_pair to MOON.
595
+ const day50 = datasetStart.add(50, "days");
596
+ userEvents.forEach(e => {
597
+ if (e.event === "swap" && dayjs(e.time).isAfter(day50) && chance.bool({ likelihood: 25 })) {
598
+ e.token_pair = chance.pickone(["MOON/USDC", "MOON/ETH", "ETH/MOON"]);
599
+ }
600
+ });
601
+
602
+ // HOOK 3 (cont): TOKEN LAUNCH SURGE — clone 4 extra MOON-pair
603
+ // swap events per existing MOON swap. Cloned with unique offset.
604
+ const moonSwaps = userEvents.filter(e =>
605
+ e.event === "swap" &&
606
+ typeof e.token_pair === "string" &&
607
+ e.token_pair.includes("MOON")
608
+ );
499
609
  if (moonSwaps.length > 0) {
500
610
  const clonedMoonEvents = [];
501
611
  moonSwaps.forEach(moonEvt => {
@@ -514,14 +624,16 @@ const config = {
514
624
 
515
625
  // -----------------------------------------------------------
516
626
  // Hook #4: AIRDROP HUNTER CHURN
517
- // Users who have "claim airdrop" events but zero "swap"
518
- // events are bots/hunters. Remove 95% of events after the
519
- // first airdrop claim.
627
+ // 4% of users are deterministically tagged as airdrop-farming bots
628
+ // via charCodeAt(1) % 25 === 0. Bots that have ever claimed an airdrop
629
+ // lose 95% of events after their first claim. (Original cohort
630
+ // "claimed-but-never-swapped" was empty because every claimer also
631
+ // has organic swap events at this scale.)
520
632
  // -----------------------------------------------------------
633
+ const isAirdropBot = userId.length > 1 && userId.charCodeAt(1) % 25 === 0;
521
634
  const hasAirdropClaim = userEvents.some(e => e.event === "claim airdrop");
522
- const hasSwap = userEvents.some(e => e.event === "swap");
523
635
 
524
- if (hasAirdropClaim && !hasSwap) {
636
+ if (isAirdropBot && hasAirdropClaim) {
525
637
  const firstClaim = userEvents.find(e => e.event === "claim airdrop");
526
638
  if (firstClaim) {
527
639
  const claimTime = dayjs(firstClaim.time);
@@ -536,31 +648,22 @@ const config = {
536
648
  }
537
649
  }
538
650
 
539
- // -----------------------------------------------------------
540
- // Hook #5: KYC FUNNEL COMPLETION
541
- // Users with "kyc completed" events get 4x deposit_amount_usd
542
- // and 8x more swap events (cloned). Flag kyc_verified=true on
543
- // post-KYC events.
544
- // -----------------------------------------------------------
651
+ // HOOK 5: KYC FUNNEL COMPLETION — users with kyc-completed
652
+ // get post-KYC deposit_amount_usd boosted 4x and 7 extra cloned
653
+ // swaps per existing post-KYC swap. No flag.
545
654
  const kycCompleted = userEvents.find(e => e.event === "kyc completed");
546
655
  if (kycCompleted) {
547
656
  const kycTime = dayjs(kycCompleted.time);
548
657
 
549
- // Boost deposits and flag post-KYC events
550
658
  userEvents.forEach(e => {
551
- if (dayjs(e.time).isAfter(kycTime)) {
552
- if (e.event === "deposit") {
553
- e.deposit_amount_usd = Math.round((e.deposit_amount_usd || 500) * 4);
554
- e.kyc_verified = true;
555
- }
556
- if (e.event === "swap") {
557
- e.kyc_verified = true;
558
- }
659
+ if (dayjs(e.time).isAfter(kycTime) && e.event === "deposit") {
660
+ e.deposit_amount_usd = Math.round((e.deposit_amount_usd || 500) * 4);
559
661
  }
560
662
  });
561
663
 
562
- // Clone swap events for 8x volume
563
- const postKycSwaps = userEvents.filter(e => e.event === "swap" && e.kyc_verified === true);
664
+ const postKycSwaps = userEvents.filter(e =>
665
+ e.event === "swap" && dayjs(e.time).isAfter(kycTime)
666
+ );
564
667
  const clonedKycSwaps = [];
565
668
  postKycSwaps.forEach(swapEvt => {
566
669
  const swapTime = dayjs(swapEvt.time);
@@ -570,7 +673,6 @@ const config = {
570
673
  time: swapTime.add(chance.integer({ min: 1, max: 48 }), "hours").toISOString(),
571
674
  user_id: swapEvt.user_id,
572
675
  trade_amount_usd: Math.round((swapEvt.trade_amount_usd || 200) * chance.floating({ min: 0.8, max: 1.5 })),
573
- kyc_verified: true,
574
676
  });
575
677
  }
576
678
  });
@@ -583,19 +685,15 @@ const config = {
583
685
  // dataset have 70% D60 retention (events injected beyond D60).
584
686
  // Non-stakers lose events after day 60 to simulate 15% retention.
585
687
  // -----------------------------------------------------------
586
- const day14 = DATASET_START.add(14, "days");
587
- const day60 = DATASET_START.add(60, "days");
688
+ const day14 = datasetStart.add(14, "days");
689
+ const day60 = datasetStart.add(60, "days");
588
690
 
589
691
  const stakedEarly = userEvents.some(e =>
590
692
  e.event === "stake" && dayjs(e.time).isBefore(day14)
591
693
  );
592
694
 
593
695
  if (stakedEarly) {
594
- // Mark all events for this user
595
- userEvents.forEach(e => { e.staked_early = true; });
596
-
597
- // 70% retention: inject late-stage events for stakers
598
- // (only inject if they don't already have many post-D60 events)
696
+ // 70% retention: inject late-stage events for stakers (no flag)
599
697
  const postD60Events = userEvents.filter(e => dayjs(e.time).isAfter(day60));
600
698
  if (postD60Events.length < 5) {
601
699
  const swapTemplate = userEvents.find(e => e.event === "swap");
@@ -607,7 +705,6 @@ const config = {
607
705
  time: day60.add(chance.integer({ min: 1, max: 55 }), "days").toISOString(),
608
706
  user_id: swapTemplate.user_id,
609
707
  trade_amount_usd: Math.round((swapTemplate.trade_amount_usd || 200) * chance.floating({ min: 0.5, max: 2.0 })),
610
- staked_early: true,
611
708
  });
612
709
  }
613
710
  }
@@ -617,7 +714,6 @@ const config = {
617
714
  ...portfolioTemplate,
618
715
  time: day60.add(chance.integer({ min: 1, max: 55 }), "days").toISOString(),
619
716
  user_id: portfolioTemplate.user_id,
620
- staked_early: true,
621
717
  });
622
718
  }
623
719
  }
@@ -634,21 +730,14 @@ const config = {
634
730
  }
635
731
  }
636
732
 
637
- // -----------------------------------------------------------
638
- // Hook #7: PRO TIER MAKER FEES
639
- // Pro users (from profile.trading_tier) pay maker_fee_pct=0.05
640
- // vs standard 0.30. Pro users also trade 6x volume.
641
- // pro_advantage=true on Pro swap events.
642
- // -----------------------------------------------------------
733
+ // HOOK 7: PRO TIER MAKER FEES — Pro users pay maker_fee_pct=0.05
734
+ // (vs Standard 0.30) and get 5 extra cloned swaps. Mutates raw
735
+ // maker_fee_pct prop. Reads trading_tier from profile.
643
736
  if (profile.trading_tier === "Pro") {
644
737
  userEvents.forEach(e => {
645
- if (e.event === "swap") {
646
- e.maker_fee_pct = 0.05;
647
- e.pro_advantage = true;
648
- }
738
+ if (e.event === "swap") e.maker_fee_pct = 0.05;
649
739
  });
650
740
 
651
- // Clone swap events for 6x volume
652
741
  const proSwaps = userEvents.filter(e => e.event === "swap");
653
742
  const clonedProSwaps = [];
654
743
  proSwaps.forEach(swapEvt => {
@@ -660,27 +749,23 @@ const config = {
660
749
  user_id: swapEvt.user_id,
661
750
  trade_amount_usd: Math.round((swapEvt.trade_amount_usd || 200) * chance.floating({ min: 0.5, max: 3.0 })),
662
751
  maker_fee_pct: 0.05,
663
- pro_advantage: true,
664
752
  });
665
753
  }
666
754
  });
667
755
  userEvents.push(...clonedProSwaps);
668
756
  } else {
669
- // Ensure standard fee on non-Pro swap events
670
757
  userEvents.forEach(e => {
671
- if (e.event === "swap") {
672
- e.maker_fee_pct = 0.30;
673
- }
758
+ if (e.event === "swap") e.maker_fee_pct = 0.30;
674
759
  });
675
760
  }
676
761
 
677
762
  // -----------------------------------------------------------
678
763
  // Hook #8: RUG-PULL AFTERMATH
679
764
  // Day 70, "SCAM" token rugs. Users who swapped SCAM token
680
- // before day 70 lose 80% of events after day 70.
681
- // rug_pull_victim=true on remaining events.
765
+ // before day 70 lose 80% of events after day 70. No flag —
766
+ // derive cohort by detecting users with token_pair containing "SCAM".
682
767
  // -----------------------------------------------------------
683
- const day70 = DATASET_START.add(70, "days");
768
+ const day70 = datasetStart.add(70, "days");
684
769
 
685
770
  // Check if user traded SCAM before day 70
686
771
  // ~10% of pre-day-70 swaps naturally get SCAM token pair
@@ -688,7 +773,7 @@ const config = {
688
773
  let hadScam = false;
689
774
  userEvents.forEach(e => {
690
775
  if (e.event === "swap") {
691
- const swapDay = dayjs(e.time).diff(DATASET_START, "day");
776
+ const swapDay = dayjs(e.time).diff(datasetStart, "day");
692
777
  // Before day 70, ~8% of swaps randomly become SCAM trades
693
778
  if (swapDay >= 10 && swapDay < 70 && chance.bool({ likelihood: 8 })) {
694
779
  e.token_pair = chance.pickone(["SCAM/USDC", "SCAM/ETH", "ETH/SCAM"]);
@@ -700,17 +785,41 @@ const config = {
700
785
  if (hadScam) {
701
786
  for (let i = userEvents.length - 1; i >= 0; i--) {
702
787
  const evt = userEvents[i];
703
- if (dayjs(evt.time).isAfter(day70)) {
704
- if (chance.bool({ likelihood: 80 })) {
705
- userEvents.splice(i, 1);
706
- } else {
707
- evt.rug_pull_victim = true;
788
+ if (dayjs(evt.time).isAfter(day70) && chance.bool({ likelihood: 80 })) {
789
+ userEvents.splice(i, 1);
790
+ }
791
+ }
792
+ }
793
+
794
+ // HOOK 10: SWAP-COUNT MAGIC NUMBER (no flags)
795
+ // Sweet 8-20 swaps → +30% on stake amount_usd; clone 1-2 extra
796
+ // stake events per existing. Over 21+ → drop 40% of portfolio
797
+ // viewed events (over-active traders ignore their portfolio).
798
+ const swapCount = userEvents.filter(e => e.event === "swap").length;
799
+ if (swapCount >= 8 && swapCount <= 20) {
800
+ const stakeTemplate = userEvents.find(e => e.event === "stake");
801
+ if (stakeTemplate) {
802
+ const stakes = userEvents.filter(e => e.event === "stake");
803
+ stakes.forEach(s => {
804
+ if (typeof s.amount_usd === "number") s.amount_usd = Math.round(s.amount_usd * 1.3);
805
+ const extras = chance.integer({ min: 1, max: 2 });
806
+ for (let k = 0; k < extras; k++) {
807
+ userEvents.push({
808
+ ...s,
809
+ time: dayjs(s.time).add(chance.integer({ min: 5, max: 360 }), "minutes").toISOString(),
810
+ user_id: s.user_id,
811
+ });
708
812
  }
813
+ });
814
+ }
815
+ } else if (swapCount >= 21) {
816
+ for (let i = userEvents.length - 1; i >= 0; i--) {
817
+ if (userEvents[i].event === "portfolio viewed" && chance.bool({ likelihood: 40 })) {
818
+ userEvents.splice(i, 1);
709
819
  }
710
820
  }
711
821
  }
712
822
 
713
- // Sort by time after all mutations
714
823
  userEvents.sort((a, b) => new Date(a.time) - new Date(b.time));
715
824
  }
716
825