@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-sass";
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-sass";
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.js").Dungeon} Config */
20
+ /** @typedef {import("../../types").Dungeon} Config */
14
21
 
15
22
  /*
16
23
  * ═══════════════════════════════════════════════════════════════════════════════
@@ -248,10 +255,10 @@ const failedDeployUsers = new Map();
248
255
 
249
256
  /** @type {Config} */
250
257
  const config = {
251
- token: "",
258
+ token,
252
259
  seed: SEED,
253
- numDays: days,
254
- numEvents: num_users * 120,
260
+ numDays: num_days,
261
+ numEvents: num_users * avg_events_per_user,
255
262
  numUsers: num_users,
256
263
  hasAnonIds: false,
257
264
  hasSessionIds: true,
@@ -268,10 +275,23 @@ const config = {
268
275
  hasAdSpend: false,
269
276
  percentUsersBornInDataset: 50,
270
277
  hasAvatar: true,
271
- batchSize: 2_500_000,
272
278
  concurrency: 1,
273
279
  writeToDisk: false,
274
- scdProps: {},
280
+ scdProps: {
281
+ primary_role: {
282
+ values: ["viewer", "editor", "admin", "owner"],
283
+ frequency: "month",
284
+ timing: "fuzzy",
285
+ max: 6
286
+ },
287
+ plan_tier: {
288
+ values: ["starter", "growth", "enterprise", "scale"],
289
+ frequency: "month",
290
+ timing: "fixed",
291
+ max: 6,
292
+ type: "company_id"
293
+ }
294
+ },
275
295
 
276
296
  funnels: [
277
297
  {
@@ -534,6 +554,8 @@ const config = {
534
554
  annual_contract_value: [0],
535
555
  customer_success_manager: [false],
536
556
  customer_health_score: u.weighNumRange(1, 100),
557
+ plan_tier: ["free", "free", "team", "team", "business", "enterprise"],
558
+ cloud_provider: ["aws", "gcp", "azure", "multi_cloud"],
537
559
  },
538
560
 
539
561
  groupKeys: [
@@ -567,7 +589,7 @@ const config = {
567
589
  */
568
590
  hook: function (record, type, meta) {
569
591
  const NOW = dayjs();
570
- const DATASET_START = NOW.subtract(days, "days");
592
+ const DATASET_START = NOW.subtract(num_days, "days");
571
593
 
572
594
  // ─────────────────────────────────────────────────────────────
573
595
  // Hook #1: END-OF-QUARTER SPIKE (event)
@@ -685,6 +707,14 @@ const config = {
685
707
  // ─────────────────────────────────────────────────────────────
686
708
  if (type === "everything") {
687
709
  const userEvents = record;
710
+ const profile = meta.profile;
711
+
712
+ // Stamp superProps from profile for consistency
713
+ userEvents.forEach(e => {
714
+ e.plan_tier = profile.plan_tier;
715
+ e.cloud_provider = profile.cloud_provider;
716
+ });
717
+
688
718
  if (userEvents && userEvents.length > 0) {
689
719
  const firstEvent = userEvents[0];
690
720
  const idHash = String(firstEvent.user_id || firstEvent.device_id).split("").reduce((acc, char) => acc + char.charCodeAt(0), 0);
@@ -38,9 +38,10 @@
38
38
  241
39
39
  ]
40
40
  },
41
- "has_media": {
42
- "$type": "array"
43
- },
41
+ "has_media": [
42
+ false,
43
+ true
44
+ ],
44
45
  "hashtag_count": {
45
46
  "$range": [
46
47
  1,
@@ -206,14 +207,15 @@
206
207
  "text"
207
208
  ],
208
209
  "view_duration_sec": [
209
- 11,
210
- 20,
211
- 23,
212
- 13
210
+ 14,
211
+ 9,
212
+ 25,
213
+ 20
214
+ ],
215
+ "completed": [
216
+ false,
217
+ true
213
218
  ],
214
- "completed": {
215
- "$type": "array"
216
- },
217
219
  "toxic_user": [
218
220
  false
219
221
  ]
@@ -228,12 +230,14 @@
228
230
  "video",
229
231
  "text"
230
232
  ],
231
- "has_filter": {
232
- "$type": "array"
233
- },
234
- "has_sticker": {
235
- "$type": "array"
236
- },
233
+ "has_filter": [
234
+ true,
235
+ false
236
+ ],
237
+ "has_sticker": [
238
+ false,
239
+ true
240
+ ],
237
241
  "weekend_surge": [
238
242
  false
239
243
  ],
@@ -258,16 +262,15 @@
258
262
  "posts"
259
263
  ],
260
264
  "results_count": [
261
- 33,
262
- 40,
263
- 35,
264
- 28,
265
- 17,
266
- 36,
267
265
  37,
268
- 16,
266
+ 14,
267
+ 11,
268
+ 23,
269
+ 9,
270
+ 8,
269
271
  15,
270
- 34
272
+ 36,
273
+ 17
271
274
  ],
272
275
  "toxic_user": [
273
276
  false
@@ -285,9 +288,10 @@
285
288
  "mention",
286
289
  "trending"
287
290
  ],
288
- "clicked": {
289
- "$type": "array"
290
- },
291
+ "clicked": [
292
+ false,
293
+ true
294
+ ],
291
295
  "toxic_user": [
292
296
  false
293
297
  ]
@@ -305,8 +309,8 @@
305
309
  ],
306
310
  "conversation_length": {
307
311
  "$range": [
308
- 3,
309
- 98
312
+ 4,
313
+ 93
310
314
  ]
311
315
  },
312
316
  "toxic_user": [
@@ -411,8 +415,8 @@
411
415
  "vip"
412
416
  ],
413
417
  "price_usd": [
414
- 9.99,
415
418
  4.99,
419
+ 9.99,
416
420
  19.99
417
421
  ],
418
422
  "toxic_user": [
@@ -421,53 +425,6 @@
421
425
  }
422
426
  }
423
427
  ],
424
- "superProps": {
425
- "app_version": [
426
- "4.0",
427
- "4.1",
428
- "4.2",
429
- "4.3",
430
- "5.0"
431
- ],
432
- "account_type": [
433
- "personal",
434
- "creator",
435
- "business"
436
- ]
437
- },
438
- "userProps": {
439
- "follower_count": {
440
- "$range": [
441
- 2283,
442
- 7639
443
- ]
444
- },
445
- "following_count": {
446
- "$range": [
447
- 869,
448
- 3942
449
- ]
450
- },
451
- "bio_length": {
452
- "$range": [
453
- 2,
454
- 132
455
- ]
456
- },
457
- "verified": {
458
- "$type": "array"
459
- },
460
- "content_niche": [
461
- "lifestyle",
462
- "tech",
463
- "food",
464
- "fitness",
465
- "travel",
466
- "comedy",
467
- "news",
468
- "art"
469
- ]
470
- },
471
428
  "funnels": [
472
429
  {
473
430
  "sequence": [
@@ -548,5 +505,116 @@
548
505
  "conversionRate": 20,
549
506
  "timeToConvert": 2
550
507
  }
551
- ]
508
+ ],
509
+ "superProps": {
510
+ "app_version": [
511
+ "4.0",
512
+ "4.1",
513
+ "4.2",
514
+ "4.3",
515
+ "5.0"
516
+ ],
517
+ "account_type": [
518
+ "personal",
519
+ "creator",
520
+ "business"
521
+ ]
522
+ },
523
+ "userProps": {
524
+ "follower_count": {
525
+ "$range": [
526
+ 2075,
527
+ 7782
528
+ ]
529
+ },
530
+ "following_count": {
531
+ "$range": [
532
+ 967,
533
+ 4229
534
+ ]
535
+ },
536
+ "bio_length": {
537
+ "$range": [
538
+ 10,
539
+ 149
540
+ ]
541
+ },
542
+ "verified": [
543
+ false,
544
+ true
545
+ ],
546
+ "content_niche": [
547
+ "lifestyle",
548
+ "tech",
549
+ "food",
550
+ "fitness",
551
+ "travel",
552
+ "comedy",
553
+ "news",
554
+ "art"
555
+ ]
556
+ },
557
+ "groupKeys": [
558
+ {
559
+ "key": "community_id",
560
+ "count": 100,
561
+ "affectsEvents": [
562
+ "post created",
563
+ "comment posted",
564
+ "post liked",
565
+ "post shared"
566
+ ]
567
+ }
568
+ ],
569
+ "groupProps": {
570
+ "community_id": {
571
+ "name": {
572
+ "$type": "string"
573
+ },
574
+ "member_count": {
575
+ "$range": [
576
+ 850,
577
+ 4126
578
+ ]
579
+ },
580
+ "category": [
581
+ "technology",
582
+ "entertainment",
583
+ "sports",
584
+ "politics",
585
+ "art",
586
+ "science"
587
+ ],
588
+ "is_moderated": [
589
+ false,
590
+ true
591
+ ]
592
+ }
593
+ },
594
+ "scdProps": {
595
+ "account_type": {
596
+ "type": "user",
597
+ "frequency": "month",
598
+ "timing": "fuzzy",
599
+ "max": 6,
600
+ "values": [
601
+ "personal",
602
+ "creator",
603
+ "business",
604
+ "verified"
605
+ ]
606
+ },
607
+ "community_status": {
608
+ "type": "community_id",
609
+ "frequency": "month",
610
+ "timing": "fixed",
611
+ "max": 6,
612
+ "values": [
613
+ "new",
614
+ "growing",
615
+ "established",
616
+ "featured"
617
+ ]
618
+ }
619
+ }
552
620
  }
@@ -1,16 +1,23 @@
1
+ // ── TWEAK THESE ──
2
+ const SEED = "harness-social";
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-social";
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.js").Dungeon} Config */
20
+ /** @typedef {import("../../types").Dungeon} Config */
14
21
 
15
22
  /*
16
23
  * =====================================================================================
@@ -162,10 +169,10 @@ const postIds = v.range(1, 1001).map(n => `post_${v.uid(8)}`);
162
169
 
163
170
  /** @type {Config} */
164
171
  const config = {
165
- token: "",
172
+ token,
166
173
  seed: SEED,
167
- numDays: days,
168
- numEvents: num_users * 120,
174
+ numDays: num_days,
175
+ numEvents: num_users * avg_events_per_user,
169
176
  numUsers: num_users,
170
177
  hasAnonIds: false,
171
178
  hasSessionIds: true,
@@ -182,10 +189,23 @@ const config = {
182
189
  hasAdSpend: false,
183
190
  percentUsersBornInDataset: 50,
184
191
  hasAvatar: true,
185
- batchSize: 2_500_000,
186
192
  concurrency: 1,
187
193
  writeToDisk: false,
188
- scdProps: {},
194
+ scdProps: {
195
+ account_type: {
196
+ values: ["personal", "creator", "business", "verified"],
197
+ frequency: "month",
198
+ timing: "fuzzy",
199
+ max: 6
200
+ },
201
+ community_status: {
202
+ values: ["new", "growing", "established", "featured"],
203
+ frequency: "month",
204
+ timing: "fixed",
205
+ max: 6,
206
+ type: "community_id"
207
+ }
208
+ },
189
209
 
190
210
  funnels: [
191
211
  {
@@ -432,6 +452,8 @@ const config = {
432
452
  },
433
453
 
434
454
  userProps: {
455
+ app_version: ["4.0", "4.1", "4.2", "4.3", "5.0"],
456
+ account_type: ["personal", "creator", "business"],
435
457
  "follower_count": u.weighNumRange(0, 10000, 0.2, 50),
436
458
  "following_count": u.weighNumRange(0, 5000, 0.3, 100),
437
459
  "bio_length": u.weighNumRange(0, 160),
@@ -456,7 +478,7 @@ const config = {
456
478
 
457
479
  hook: function (record, type, meta) {
458
480
  const NOW = dayjs();
459
- const DATASET_START = NOW.subtract(days, 'days');
481
+ const DATASET_START = NOW.subtract(num_days, 'days');
460
482
  const ALGORITHM_CHANGE_DAY = DATASET_START.add(45, 'days');
461
483
  const REENGAGEMENT_START = DATASET_START.add(30, 'days');
462
484
 
@@ -516,6 +538,13 @@ const config = {
516
538
  const userEvents = record;
517
539
  if (!userEvents || userEvents.length === 0) return record;
518
540
 
541
+ // Stamp superProps from profile for consistency
542
+ const profile = meta.profile;
543
+ userEvents.forEach(e => {
544
+ e.app_version = profile.app_version;
545
+ e.account_type = profile.account_type;
546
+ });
547
+
519
548
  // Tracking variables for user patterns
520
549
  let postCreatedCount = 0;
521
550
  let followReceivedCount = 0;
@@ -454,6 +454,9 @@
454
454
  },
455
455
  {
456
456
  "event": "account deactivated",
457
+ "isChurnEvent": true,
458
+ "returnLikelihood": 0.2,
459
+ "isStrictEvent": true,
457
460
  "properties": {
458
461
  "reason": [
459
462
  "found_alternative",
@@ -465,40 +468,6 @@
465
468
  }
466
469
  }
467
470
  ],
468
- "superProps": {
469
- "platform": [
470
- "ios",
471
- "android",
472
- "web"
473
- ],
474
- "membership_tier": [
475
- "standard",
476
- "gold",
477
- "platinum"
478
- ]
479
- },
480
- "userProps": {
481
- "customer_segment": [
482
- "leisure_family"
483
- ],
484
- "travel_frequency": [
485
- "occasional",
486
- "monthly",
487
- "weekly"
488
- ],
489
- "company_name": [
490
- "none"
491
- ],
492
- "preferred_destination": {
493
- "$type": "string"
494
- },
495
- "avg_budget_per_night": {
496
- "$range": [
497
- 98,
498
- 339
499
- ]
500
- }
501
- },
502
471
  "funnels": [
503
472
  {
504
473
  "sequence": [
@@ -507,6 +476,7 @@
507
476
  "hotel viewed",
508
477
  "booking completed"
509
478
  ],
479
+ "name": "Onboarding to First Booking",
510
480
  "isFirstFunnel": true,
511
481
  "conversionRate": 35,
512
482
  "timeToConvert": 72,
@@ -519,6 +489,7 @@
519
489
  "price compared",
520
490
  "booking completed"
521
491
  ],
492
+ "name": "Search to Book",
522
493
  "conversionRate": 25,
523
494
  "timeToConvert": 48,
524
495
  "weight": 5
@@ -530,6 +501,7 @@
530
501
  "amenity used",
531
502
  "review submitted"
532
503
  ],
504
+ "name": "Full Stay Journey",
533
505
  "conversionRate": 30,
534
506
  "timeToConvert": 336,
535
507
  "weight": 3
@@ -540,6 +512,7 @@
540
512
  "loyalty points redeemed",
541
513
  "review submitted"
542
514
  ],
515
+ "name": "Loyalty Engagement",
543
516
  "conversionRate": 15,
544
517
  "timeToConvert": 720,
545
518
  "weight": 2
@@ -550,9 +523,58 @@
550
523
  "booking completed",
551
524
  "room upgrade selected"
552
525
  ],
526
+ "name": "Upsell Path",
553
527
  "conversionRate": 20,
554
528
  "timeToConvert": 24,
555
529
  "weight": 2
556
530
  }
557
- ]
531
+ ],
532
+ "superProps": {
533
+ "Platform": [
534
+ "ios",
535
+ "android",
536
+ "web"
537
+ ],
538
+ "membership_tier": [
539
+ "standard",
540
+ "gold",
541
+ "platinum"
542
+ ]
543
+ },
544
+ "userProps": {
545
+ "customer_segment": [
546
+ "leisure_family"
547
+ ],
548
+ "travel_frequency": [
549
+ "occasional",
550
+ "monthly",
551
+ "weekly"
552
+ ],
553
+ "company_name": [
554
+ "none"
555
+ ],
556
+ "preferred_destination": {
557
+ "$type": "string"
558
+ },
559
+ "avg_budget_per_night": {
560
+ "$range": [
561
+ 98,
562
+ 339
563
+ ]
564
+ }
565
+ },
566
+ "scdProps": {
567
+ "membership_tier": {
568
+ "type": "user",
569
+ "frequency": "month",
570
+ "timing": "fuzzy",
571
+ "max": 8,
572
+ "values": [
573
+ "member",
574
+ "silver",
575
+ "gold",
576
+ "platinum"
577
+ ]
578
+ }
579
+ }
558
580
  }