@ak--47/dungeon-master 1.1.0 → 1.2.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 (72) hide show
  1. package/dungeons/technical/ad-spend-schema.json +2 -2
  2. package/dungeons/technical/ad-spend.js +16 -5
  3. package/dungeons/technical/anonymous-users-schema.json +4 -3
  4. package/dungeons/technical/anonymous-users.js +16 -6
  5. package/dungeons/technical/array-of-object-lookup-schema.json +1 -1
  6. package/dungeons/technical/array-of-object-lookup.js +22 -6
  7. package/dungeons/technical/experiments-schema.json +25 -19
  8. package/dungeons/technical/experiments.js +24 -6
  9. package/dungeons/technical/foobar.js +29 -13
  10. package/dungeons/technical/group-analytics-schema.json +92 -0
  11. package/dungeons/technical/group-analytics.js +16 -6
  12. package/dungeons/technical/mirror-strategies-schema.json +4 -4
  13. package/dungeons/technical/mirror-strategies.js +16 -6
  14. package/dungeons/technical/nested-objects.js +16 -5
  15. package/dungeons/technical/retention-cadence.js +14 -9
  16. package/dungeons/technical/sanity-schema.json +22 -22
  17. package/dungeons/technical/sanity.js +26 -6
  18. package/dungeons/technical/scale-test.js +16 -5
  19. package/dungeons/technical/scd-schema.json +230 -33
  20. package/dungeons/technical/scd.js +25 -5
  21. package/dungeons/technical/simple-schema.json +132 -48
  22. package/dungeons/technical/simple.js +21 -6
  23. package/dungeons/technical/simplest-schema.json +168 -79
  24. package/dungeons/technical/simplest.js +24 -7
  25. package/dungeons/technical/text-generation-schema.json +7 -4
  26. package/dungeons/technical/text-generation.js +23 -8
  27. package/dungeons/user/.gitkeep +0 -0
  28. package/dungeons/user/shalini.js +847 -0
  29. package/dungeons/vertical/community-schema.json +71 -49
  30. package/dungeons/vertical/community.js +57 -30
  31. package/dungeons/vertical/devtools-schema.json +69 -48
  32. package/dungeons/vertical/devtools.js +58 -31
  33. package/dungeons/vertical/ecommerce-schema.json +126 -108
  34. package/dungeons/vertical/ecommerce.js +32 -8
  35. package/dungeons/vertical/education-schema.json +5261 -272
  36. package/dungeons/vertical/education.js +45 -22
  37. package/dungeons/vertical/fintech-schema.json +165 -98
  38. package/dungeons/vertical/fintech.js +43 -11
  39. package/dungeons/vertical/fitness-schema.json +69 -47
  40. package/dungeons/vertical/fitness.js +56 -24
  41. package/dungeons/vertical/food-delivery-schema.json +36237 -187
  42. package/dungeons/vertical/food-delivery.js +67 -15
  43. package/dungeons/vertical/gaming-schema.json +104 -60
  44. package/dungeons/vertical/gaming.js +61 -16
  45. package/dungeons/vertical/healthcare-schema.json +70 -48
  46. package/dungeons/vertical/healthcare.js +77 -42
  47. package/dungeons/vertical/insurance-application-schema.json +66 -47
  48. package/dungeons/vertical/insurance-application.js +34 -10
  49. package/dungeons/vertical/logistics-schema.json +60 -38
  50. package/dungeons/vertical/logistics.js +77 -43
  51. package/dungeons/vertical/marketplace-schema.json +65 -43
  52. package/dungeons/vertical/marketplace.js +52 -21
  53. package/dungeons/vertical/media-schema.json +4085 -123
  54. package/dungeons/vertical/media.js +65 -18
  55. package/dungeons/vertical/rpg-schema.json +1984 -147
  56. package/dungeons/vertical/rpg.js +47 -11
  57. package/dungeons/vertical/sass-schema.json +2622 -147
  58. package/dungeons/vertical/sass.js +40 -10
  59. package/dungeons/vertical/social-schema.json +146 -78
  60. package/dungeons/vertical/social.js +39 -10
  61. package/dungeons/vertical/travel-schema.json +57 -35
  62. package/dungeons/vertical/travel.js +58 -21
  63. package/index.js +4 -1
  64. package/lib/core/config-validator.js +13 -2
  65. package/lib/core/context.js +9 -0
  66. package/lib/core/storage.js +2 -0
  67. package/lib/generators/events.js +3 -5
  68. package/lib/orchestrators/user-loop.js +24 -1
  69. package/lib/utils/utils.js +129 -9
  70. package/package.json +1 -1
  71. package/scripts/extract-dungeon-schema.mjs +64 -18
  72. package/types.d.ts +8 -3
@@ -1,16 +1,23 @@
1
+ // ── TWEAK THESE ──
2
+ const SEED = "harness-education";
3
+ const num_days = 100;
4
+ const num_users = 5_000;
5
+ const avg_events_per_user = 120;
6
+ let token = "your-mixpanel-token";
7
+
8
+ // ── env overrides ──
9
+ if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
10
+
1
11
  import dayjs from "dayjs";
2
12
  import utc from "dayjs/plugin/utc.js";
3
13
  import "dotenv/config";
4
14
  import * as u from "../../lib/utils/utils.js";
5
15
  import * as v from "ak-tools";
6
16
 
7
- const SEED = "harness-education";
8
17
  dayjs.extend(utc);
9
18
  const chance = u.initChance(SEED);
10
- const num_users = 5_000;
11
- const days = 100;
12
19
 
13
- /** @typedef {import("../types.d.ts").Dungeon} Config */
20
+ /** @typedef {import("../../types").Dungeon} Config */
14
21
 
15
22
  /**
16
23
  * ═══════════════════════════════════════════════════════════════════════════════
@@ -183,10 +190,10 @@ const problemIds = v.range(1, 601).map(n => `problem_${v.uid(6)}`);
183
190
 
184
191
  /** @type {Config} */
185
192
  const config = {
186
- token: "",
193
+ token,
187
194
  seed: SEED,
188
- numDays: days,
189
- numEvents: num_users * 120,
195
+ numDays: num_days,
196
+ numEvents: num_users * avg_events_per_user,
190
197
  numUsers: num_users,
191
198
  hasAnonIds: false,
192
199
  hasSessionIds: true,
@@ -203,7 +210,6 @@ const config = {
203
210
  hasAdSpend: false,
204
211
  percentUsersBornInDataset: 50,
205
212
  hasAvatar: true,
206
- batchSize: 2_500_000,
207
213
  concurrency: 1,
208
214
  writeToDisk: false,
209
215
 
@@ -437,10 +443,24 @@ const config = {
437
443
  ],
438
444
 
439
445
  superProps: {
440
- platform: ["Web", "iOS", "Android", "iPad"],
446
+ Platform: ["Web", "iOS", "Android", "iPad"],
441
447
  },
442
448
 
443
- scdProps: {},
449
+ scdProps: {
450
+ enrollment_status: {
451
+ values: ["enrolled", "active", "completed", "dropped"],
452
+ frequency: "month",
453
+ timing: "fuzzy",
454
+ max: 6
455
+ },
456
+ course_status: {
457
+ values: ["draft", "published", "archived", "deprecated"],
458
+ frequency: "month",
459
+ timing: "fixed",
460
+ max: 6,
461
+ type: "course_id"
462
+ }
463
+ },
444
464
 
445
465
  userProps: {
446
466
  "account_type": ["student", "student", "student", "student", "student", "student", "student", "student", "instructor"],
@@ -453,6 +473,7 @@ const config = {
453
473
  "instructor_rating": [0],
454
474
  "learning_goal": ["none"],
455
475
  "study_hours_per_week": [0],
476
+ "Platform": ["Web", "iOS", "Android", "iPad"],
456
477
  },
457
478
 
458
479
  groupKeys: [
@@ -492,7 +513,7 @@ const config = {
492
513
  */
493
514
  hook: function (record, type, meta) {
494
515
  const NOW = dayjs();
495
- const DATASET_START = NOW.subtract(days, 'days');
516
+ const DATASET_START = NOW.subtract(num_days, 'days');
496
517
 
497
518
  // ═══════════════════════════════════════════════════════════════════
498
519
  // Hook #1: STUDENT VS INSTRUCTOR PROFILES
@@ -608,8 +629,16 @@ const config = {
608
629
  // ═══════════════════════════════════════════════════════════════════
609
630
  if (type === "everything") {
610
631
  const userEvents = record;
632
+ const profile = meta.profile;
611
633
  const firstEventTime = userEvents.length > 0 ? dayjs(userEvents[0].time) : null;
612
634
 
635
+ // ── Stamp superProps from profile so they stay consistent per user ──
636
+ if (profile) {
637
+ userEvents.forEach((event) => {
638
+ if (profile.Platform !== undefined) event.Platform = profile.Platform;
639
+ });
640
+ }
641
+
613
642
  // ---------------------------------------------------------------
614
643
  // First pass: identify user patterns
615
644
  // ---------------------------------------------------------------
@@ -707,7 +736,7 @@ const config = {
707
736
  }
708
737
 
709
738
  // Hook #7: FREE VS PAID - reinforce the subscription effect on certificates
710
- const subStatus = meta && meta.profile ? meta.profile.subscription_status : "free";
739
+ const subStatus = profile ? profile.subscription_status : "free";
711
740
  if (subStatus === "free") {
712
741
  // Free users lose 55% of their certificates (simulating lower completion)
713
742
  for (let i = userEvents.length - 1; i >= 0; i--) {
@@ -765,17 +794,11 @@ const config = {
765
794
  // Hook #7: FREE VS PAID COURSES (funnel-pre)
766
795
  // ═══════════════════════════════════════════════════════════════════
767
796
  if (type === "funnel-pre") {
768
- // Target funnels containing course completion events
797
+ // Hook #7: FREE VS PAID — prop tagging only
798
+ // conversionRate manipulation removed; the everything hook handles
799
+ // the completion gap by dropping 55% of free-user certificates
769
800
  if (meta && meta.profile && meta.funnel) {
770
- const subscriptionStatus = meta.profile.subscription_status;
771
-
772
- if (subscriptionStatus === "free") {
773
- // Free users convert at 0.5x rate
774
- record.conversionRate = (record.conversionRate || 0.25) * 0.5;
775
- } else if (subscriptionStatus === "monthly" || subscriptionStatus === "annual") {
776
- // Paid subscribers convert at 1.5x rate
777
- record.conversionRate = (record.conversionRate || 0.25) * 1.5;
778
- }
801
+ // no-op: kept for future prop-setting if needed
779
802
  }
780
803
  }
781
804
 
@@ -5,8 +5,8 @@
5
5
  "isFirstEvent": true,
6
6
  "properties": {
7
7
  "account_type": [
8
- "business",
9
- "personal"
8
+ "personal",
9
+ "business"
10
10
  ],
11
11
  "signup_channel": [
12
12
  "app",
@@ -22,14 +22,14 @@
22
22
  "properties": {
23
23
  "session_duration_sec": {
24
24
  "$range": [
25
- 131,
26
- 471
25
+ 115,
26
+ 487
27
27
  ]
28
28
  },
29
29
  "pages_viewed": [
30
30
  5,
31
- 4,
32
- 6
31
+ 10,
32
+ 4
33
33
  ],
34
34
  "month_end_anxiety": [
35
35
  false
@@ -140,9 +140,10 @@
140
140
  2710
141
141
  ]
142
142
  },
143
- "auto_pay": {
144
- "$type": "array"
145
- },
143
+ "auto_pay": [
144
+ false,
145
+ true
146
+ ],
146
147
  "missed_payment": [
147
148
  false
148
149
  ],
@@ -235,7 +236,8 @@
235
236
  ]
236
237
  },
237
238
  "action": [
238
- "buy"
239
+ "buy",
240
+ "sell"
239
241
  ],
240
242
  "premium_returns": [
241
243
  false
@@ -316,13 +318,12 @@
316
318
  ]
317
319
  },
318
320
  "interest_rate": [
319
- 4,
320
- 14,
321
- 7,
322
321
  17,
323
322
  10,
324
323
  18,
325
- 8
324
+ 8,
325
+ 9,
326
+ 6
326
327
  ]
327
328
  }
328
329
  },
@@ -336,13 +337,13 @@
336
337
  "premium"
337
338
  ],
338
339
  "new_tier": [
339
- "premium",
340
- "plus"
340
+ "plus",
341
+ "premium"
341
342
  ],
342
343
  "monthly_fee": [
343
- 14.99,
344
344
  4.99,
345
- 9.99
345
+ 9.99,
346
+ 14.99
346
347
  ]
347
348
  }
348
349
  },
@@ -363,9 +364,10 @@
363
364
  "transfer",
364
365
  "technical"
365
366
  ],
366
- "resolved": {
367
- "$type": "array"
368
- },
367
+ "resolved": [
368
+ false,
369
+ true
370
+ ],
369
371
  "fraud_sequence": [
370
372
  false
371
373
  ]
@@ -383,9 +385,10 @@
383
385
  "security",
384
386
  "promo"
385
387
  ],
386
- "action_taken": {
387
- "$type": "array"
388
- }
388
+ "action_taken": [
389
+ false,
390
+ true
391
+ ]
389
392
  }
390
393
  },
391
394
  {
@@ -399,15 +402,15 @@
399
402
  "partner_offer"
400
403
  ],
401
404
  "value": [
405
+ 74,
406
+ 39,
402
407
  23,
403
- 22,
404
- 58,
405
- 67,
406
- 26,
407
- 28,
408
- 29,
409
- 47,
410
- 20
408
+ 30,
409
+ 60,
410
+ 73,
411
+ 46,
412
+ 25,
413
+ 27
411
414
  ],
412
415
  "premium_reward": [
413
416
  false
@@ -415,71 +418,6 @@
415
418
  }
416
419
  }
417
420
  ],
418
- "superProps": {
419
- "account_tier": [
420
- "plus",
421
- "basic",
422
- "premium"
423
- ],
424
- "platform": [
425
- "ios",
426
- "android",
427
- "web"
428
- ],
429
- "low_balance_churn": [
430
- false
431
- ]
432
- },
433
- "userProps": {
434
- "credit_score_range": [
435
- "300-579",
436
- "580-669",
437
- "670-739",
438
- "740-799",
439
- "800-850"
440
- ],
441
- "income_bracket": [
442
- "under_30k",
443
- "30k_50k",
444
- "50k_75k",
445
- "75k_100k",
446
- "100k_150k",
447
- "over_150k"
448
- ],
449
- "account_age_months": {
450
- "$range": [
451
- 17,
452
- 46
453
- ]
454
- },
455
- "total_balance": {
456
- "$range": [
457
- 16006,
458
- 83008
459
- ]
460
- },
461
- "has_direct_deposit": {
462
- "$type": "array"
463
- },
464
- "account_segment": [
465
- "personal"
466
- ],
467
- "employee_count": [
468
- 0
469
- ],
470
- "annual_revenue": [
471
- 0
472
- ],
473
- "industry": [
474
- ""
475
- ],
476
- "age_range": [
477
- ""
478
- ],
479
- "life_stage": [
480
- ""
481
- ]
482
- },
483
421
  "funnels": [
484
422
  {
485
423
  "sequence": [
@@ -559,5 +497,134 @@
559
497
  "conversionRate": 25,
560
498
  "timeToConvert": 10
561
499
  }
562
- ]
500
+ ],
501
+ "superProps": {
502
+ "account_tier": [
503
+ "basic",
504
+ "plus",
505
+ "premium"
506
+ ],
507
+ "Platform": [
508
+ "ios",
509
+ "android",
510
+ "web"
511
+ ],
512
+ "low_balance_churn": [
513
+ false
514
+ ]
515
+ },
516
+ "userProps": {
517
+ "credit_score_range": [
518
+ "300-579",
519
+ "580-669",
520
+ "670-739",
521
+ "740-799",
522
+ "800-850"
523
+ ],
524
+ "income_bracket": [
525
+ "under_30k",
526
+ "30k_50k",
527
+ "50k_75k",
528
+ "75k_100k",
529
+ "100k_150k",
530
+ "over_150k"
531
+ ],
532
+ "account_age_months": {
533
+ "$range": [
534
+ 15,
535
+ 44
536
+ ]
537
+ },
538
+ "total_balance": {
539
+ "$range": [
540
+ 16006,
541
+ 83008
542
+ ]
543
+ },
544
+ "has_direct_deposit": [
545
+ false,
546
+ true
547
+ ],
548
+ "account_segment": [
549
+ "personal"
550
+ ],
551
+ "employee_count": [
552
+ 0
553
+ ],
554
+ "annual_revenue": [
555
+ 0
556
+ ],
557
+ "industry": [
558
+ ""
559
+ ],
560
+ "age_range": [
561
+ ""
562
+ ],
563
+ "life_stage": [
564
+ ""
565
+ ]
566
+ },
567
+ "groupKeys": [
568
+ {
569
+ "key": "household_id",
570
+ "count": 500,
571
+ "affectsEvents": [
572
+ "transaction completed",
573
+ "transfer sent",
574
+ "bill paid",
575
+ "savings goal set"
576
+ ]
577
+ }
578
+ ],
579
+ "groupProps": {
580
+ "household_id": {
581
+ "household_size": {
582
+ "$range": [
583
+ 1,
584
+ 6
585
+ ]
586
+ },
587
+ "combined_income": {
588
+ "$range": [
589
+ 61633,
590
+ 263131
591
+ ]
592
+ },
593
+ "financial_health_score": {
594
+ "$range": [
595
+ 12,
596
+ 81
597
+ ]
598
+ },
599
+ "primary_bank": [
600
+ "NexBank_only",
601
+ "multi_bank"
602
+ ]
603
+ }
604
+ },
605
+ "scdProps": {
606
+ "account_tier": {
607
+ "type": "user",
608
+ "frequency": "month",
609
+ "timing": "fuzzy",
610
+ "max": 6,
611
+ "values": [
612
+ "basic",
613
+ "plus",
614
+ "premium"
615
+ ]
616
+ },
617
+ "risk_category": {
618
+ "type": "household_id",
619
+ "frequency": "month",
620
+ "timing": "fixed",
621
+ "max": 8,
622
+ "values": [
623
+ "low",
624
+ "medium",
625
+ "high",
626
+ "critical"
627
+ ]
628
+ }
629
+ }
563
630
  }
@@ -1,15 +1,22 @@
1
+ // ── TWEAK THESE ──
2
+ const SEED = "harness-fintech";
3
+ const num_days = 100;
4
+ const num_users = 5_000;
5
+ const avg_events_per_user = 120;
6
+ let token = "your-mixpanel-token";
7
+
8
+ // ── env overrides ──
9
+ if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
10
+
1
11
  import dayjs from "dayjs";
2
12
  import utc from "dayjs/plugin/utc.js";
3
13
  import "dotenv/config";
4
14
  import * as u from "../../lib/utils/utils.js";
5
15
 
6
- const SEED = "harness-fintech";
7
16
  dayjs.extend(utc);
8
17
  const chance = u.initChance(SEED);
9
- const num_users = 5_000;
10
- const days = 100;
11
18
 
12
- /** @typedef {import("../types.d.ts").Dungeon} Config */
19
+ /** @typedef {import("../../types").Dungeon} Config */
13
20
 
14
21
  /**
15
22
  * ===================================================================
@@ -129,10 +136,10 @@ const days = 100;
129
136
 
130
137
  /** @type {Config} */
131
138
  const config = {
132
- token: "",
139
+ token,
133
140
  seed: SEED,
134
- numDays: days,
135
- numEvents: num_users * 120,
141
+ numDays: num_days,
142
+ numEvents: num_users * avg_events_per_user,
136
143
  numUsers: num_users,
137
144
  hasAnonIds: false,
138
145
  hasSessionIds: true,
@@ -151,11 +158,24 @@ const config = {
151
158
 
152
159
  hasAvatar: true,
153
160
 
154
- batchSize: 2_500_000,
155
161
  concurrency: 1,
156
162
  writeToDisk: false,
157
163
 
158
- scdProps: {},
164
+ scdProps: {
165
+ account_tier: {
166
+ values: ["basic", "plus", "premium"],
167
+ frequency: "month",
168
+ timing: "fuzzy",
169
+ max: 6
170
+ },
171
+ risk_category: {
172
+ values: ["low", "medium", "high", "critical"],
173
+ frequency: "month",
174
+ timing: "fixed",
175
+ max: 8,
176
+ type: "household_id"
177
+ }
178
+ },
159
179
 
160
180
  funnels: [
161
181
  {
@@ -387,11 +407,14 @@ const config = {
387
407
 
388
408
  superProps: {
389
409
  account_tier: ["basic", "basic", "basic", "plus", "plus", "premium"],
390
- platform: ["ios", "android", "web"],
410
+ Platform: ["ios", "android", "web"],
391
411
  low_balance_churn: [false],
392
412
  },
393
413
 
394
414
  userProps: {
415
+ account_tier: ["basic", "basic", "basic", "plus", "plus", "premium"],
416
+ Platform: ["ios", "android", "web"],
417
+ low_balance_churn: [false],
395
418
  "credit_score_range": ["300-579", "580-669", "670-739", "740-799", "800-850"],
396
419
  "income_bracket": ["under_30k", "30k_50k", "50k_75k", "75k_100k", "100k_150k", "over_150k"],
397
420
  "account_age_months": u.weighNumRange(1, 60, 0.5, 12),
@@ -436,7 +459,7 @@ const config = {
436
459
  */
437
460
  hook: function (record, type, meta) {
438
461
  const NOW = dayjs();
439
- const DATASET_START = NOW.subtract(days, "days");
462
+ const DATASET_START = NOW.subtract(num_days, "days");
440
463
 
441
464
  // ===============================================================
442
465
  // Hook #1: PERSONAL VS BUSINESS ACCOUNTS (user)
@@ -568,6 +591,15 @@ const config = {
568
591
  // ===============================================================
569
592
  if (type === "everything") {
570
593
  const userEvents = record;
594
+
595
+ // Stamp superProps from profile for consistency
596
+ const profile = meta.profile;
597
+ userEvents.forEach(e => {
598
+ e.account_tier = profile.account_tier;
599
+ e.Platform = profile.Platform;
600
+ e.low_balance_churn = profile.low_balance_churn;
601
+ });
602
+
571
603
  const firstEventTime = userEvents.length > 0 ? dayjs(userEvents[0].time) : null;
572
604
 
573
605
  // -----------------------------------------------------------