@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
@@ -441,6 +441,9 @@
441
441
  },
442
442
  {
443
443
  "event": "account deactivated",
444
+ "isChurnEvent": true,
445
+ "returnLikelihood": 0.15,
446
+ "isStrictEvent": true,
444
447
  "properties": {
445
448
  "reason": [
446
449
  "lost_interest",
@@ -452,54 +455,6 @@
452
455
  }
453
456
  }
454
457
  ],
455
- "superProps": {
456
- "subscription_tier": [
457
- "free",
458
- "supporter",
459
- "pro"
460
- ],
461
- "platform": [
462
- "ios",
463
- "android",
464
- "web"
465
- ],
466
- "content_hub": [
467
- "gaming",
468
- "anime",
469
- "movies",
470
- "tv",
471
- "comics",
472
- "music"
473
- ]
474
- },
475
- "userProps": {
476
- "role": [
477
- "reader",
478
- "contributor",
479
- "moderator",
480
- "creator"
481
- ],
482
- "contributor_level": [
483
- "newcomer"
484
- ],
485
- "articles_created": [
486
- 0
487
- ],
488
- "reputation_score": {
489
- "$range": [
490
- 20,
491
- 76
492
- ]
493
- },
494
- "preferred_hub": [
495
- "gaming",
496
- "anime",
497
- "movies",
498
- "tv",
499
- "comics",
500
- "music"
501
- ]
502
- },
503
458
  "funnels": [
504
459
  {
505
460
  "sequence": [
@@ -508,6 +463,7 @@
508
463
  "article viewed",
509
464
  "discussion posted"
510
465
  ],
466
+ "name": "Onboarding Flow",
511
467
  "isFirstFunnel": true,
512
468
  "conversionRate": 40,
513
469
  "timeToConvert": 72,
@@ -519,6 +475,7 @@
519
475
  "article published",
520
476
  "comment posted"
521
477
  ],
478
+ "name": "Content Creation",
522
479
  "conversionRate": 35,
523
480
  "timeToConvert": 48,
524
481
  "weight": 5
@@ -530,6 +487,7 @@
530
487
  "comment posted",
531
488
  "discussion posted"
532
489
  ],
490
+ "name": "Engagement Loop",
533
491
  "conversionRate": 30,
534
492
  "timeToConvert": 96,
535
493
  "weight": 4
@@ -540,6 +498,7 @@
540
498
  "profile updated",
541
499
  "notification received"
542
500
  ],
501
+ "name": "Creator to Supporter",
543
502
  "conversionRate": 45,
544
503
  "timeToConvert": 168,
545
504
  "weight": 2
@@ -549,9 +508,72 @@
549
508
  "report submitted",
550
509
  "moderation action"
551
510
  ],
511
+ "name": "Moderation Pipeline",
552
512
  "conversionRate": 60,
553
513
  "timeToConvert": 48,
554
514
  "weight": 2
555
515
  }
556
- ]
516
+ ],
517
+ "superProps": {
518
+ "subscription_tier": [
519
+ "free",
520
+ "supporter",
521
+ "pro"
522
+ ],
523
+ "Platform": [
524
+ "ios",
525
+ "android",
526
+ "web"
527
+ ],
528
+ "content_hub": [
529
+ "gaming",
530
+ "anime",
531
+ "movies",
532
+ "tv",
533
+ "comics",
534
+ "music"
535
+ ]
536
+ },
537
+ "userProps": {
538
+ "role": [
539
+ "reader",
540
+ "contributor",
541
+ "moderator",
542
+ "creator"
543
+ ],
544
+ "contributor_level": [
545
+ "newcomer"
546
+ ],
547
+ "articles_created": [
548
+ 0
549
+ ],
550
+ "reputation_score": {
551
+ "$range": [
552
+ 20,
553
+ 76
554
+ ]
555
+ },
556
+ "preferred_hub": [
557
+ "gaming",
558
+ "anime",
559
+ "movies",
560
+ "tv",
561
+ "comics",
562
+ "music"
563
+ ]
564
+ },
565
+ "scdProps": {
566
+ "contributor_level": {
567
+ "type": "user",
568
+ "frequency": "month",
569
+ "timing": "fuzzy",
570
+ "max": 8,
571
+ "values": [
572
+ "newcomer",
573
+ "regular",
574
+ "trusted",
575
+ "admin"
576
+ ]
577
+ }
578
+ }
557
579
  }
@@ -1,16 +1,23 @@
1
+ // ── TWEAK THESE ──
2
+ const SEED = "dm4-community";
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 = "dm4-community";
8
17
  dayjs.extend(utc);
9
18
  const chance = u.initChance(SEED);
10
- const num_users = 5_000;
11
- const days = 100;
12
19
  const NOW = dayjs();
13
- const DATASET_START = NOW.subtract(days, "days");
20
+ const DATASET_START = NOW.subtract(num_days, "days");
14
21
 
15
22
  /** @typedef {import("../../types").Dungeon} Config */
16
23
 
@@ -213,12 +220,12 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
213
220
  * articles and high community reputation scores.
214
221
  *
215
222
  * -------------------------------------------------------------------
216
- * 8. PRO SUBSCRIBER CONTENT CREATION LIFT (funnel-pre hook)
223
+ * 8. PRO SUBSCRIBER CONTENT CREATION LIFT (everything hook)
217
224
  * -------------------------------------------------------------------
218
225
  *
219
- * PATTERN: Users with subscription_tier "pro" get 1.5x conversion
220
- * rate on the Content Creation funnel. Pro users have analytics and
221
- * tools that help them publish more effectively.
226
+ * PATTERN: Free-tier users drop 35% of final funnel step events
227
+ * ("comment posted"), creating a visible conversion gap between
228
+ * paid and free users. Pro/supporter users keep all their events.
222
229
  *
223
230
  * HOW TO FIND IT IN MIXPANEL:
224
231
  *
@@ -244,15 +251,15 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
244
251
  * Edit War Detection | edit_quality | 3.0 | 1.5 | 0.5x
245
252
  * Lurker Churn | events after day 10 | 100% | 40% | 0.4x
246
253
  * Creator Profiles | reputation_score | 25 | 90 | 3.6x
247
- * Pro Content Creation Lift | funnel conversion | 35% | 52% | 1.5x
254
+ * Pro Content Creation Lift | funnel conversion | 35% | 52% | ~1.5x
248
255
  */
249
256
 
250
257
  /** @type {Config} */
251
258
  const config = {
252
- token: "",
259
+ token,
253
260
  seed: SEED,
254
- numDays: days,
255
- numEvents: num_users * 120,
261
+ numDays: num_days,
262
+ numEvents: num_users * avg_events_per_user,
256
263
  numUsers: num_users,
257
264
  hasAnonIds: false,
258
265
  hasSessionIds: true,
@@ -269,10 +276,16 @@ const config = {
269
276
  hasAdSpend: false,
270
277
  percentUsersBornInDataset: 35,
271
278
  hasAvatar: true,
272
- batchSize: 2_500_000,
273
279
  concurrency: 1,
274
280
  writeToDisk: false,
275
- scdProps: {},
281
+ scdProps: {
282
+ contributor_level: {
283
+ values: ["newcomer", "regular", "trusted", "admin"],
284
+ frequency: "month",
285
+ timing: "fuzzy",
286
+ max: 8
287
+ }
288
+ },
276
289
  mirrorProps: {},
277
290
  lookupTables: [],
278
291
 
@@ -498,7 +511,7 @@ const config = {
498
511
  // -- SuperProps ----------------------------------------------------
499
512
  superProps: {
500
513
  subscription_tier: ["free", "free", "free", "free", "supporter", "pro"],
501
- platform: ["ios", "android", "web"],
514
+ Platform: ["ios", "android", "web"],
502
515
  content_hub: ["gaming", "anime", "movies", "tv", "comics", "music"],
503
516
  },
504
517
 
@@ -509,6 +522,9 @@ const config = {
509
522
  articles_created: [0],
510
523
  reputation_score: u.weighNumRange(0, 100, 0.3, 25),
511
524
  preferred_hub: ["gaming", "anime", "movies", "tv", "comics", "music"],
525
+ subscription_tier: ["free", "free", "free", "free", "supporter", "pro"],
526
+ Platform: ["ios", "android", "web"],
527
+ content_hub: ["gaming", "anime", "movies", "tv", "comics", "music"],
512
528
  },
513
529
 
514
530
  // -- Phase 2: Personas --------------------------------------------
@@ -679,18 +695,9 @@ const config = {
679
695
  }
680
696
  }
681
697
 
682
- // -- HOOK 8: PRO SUBSCRIBER CONTENT CREATION LIFT (funnel-pre)
683
- // Pro subscribers convert 1.5x better through content creation.
684
- if (type === "funnel-pre") {
685
- if (meta && meta.profile) {
686
- const tier = meta.profile.subscription_tier;
687
- if (tier === "pro") {
688
- record.conversionRate = Math.min(record.conversionRate * 1.5, 95);
689
- } else if (tier === "supporter") {
690
- record.conversionRate = Math.min(record.conversionRate * 1.2, 90);
691
- }
692
- }
693
- }
698
+ // -- HOOK 8: PRO SUBSCRIBER CONTENT CREATION LIFT
699
+ // Conversion differences handled in everything hook via event filtering.
700
+ // (funnel-pre conversionRate modifications are diluted by organic events)
694
701
 
695
702
  // -- HOOK 1: WEEKEND CONTENT SURGE (event) --------------------
696
703
  // Articles published on weekends get 1.5x word_count.
@@ -719,8 +726,28 @@ const config = {
719
726
 
720
727
  // -- EVERYTHING HOOKS -----------------------------------------
721
728
  if (type === "everything") {
722
- const events = record;
729
+ let events = record;
723
730
  if (!events.length) return record;
731
+ const profile = meta && meta.profile ? meta.profile : {};
732
+
733
+ // -- SUPERPROP STAMPING -----------------------------------
734
+ // Stamp superProp values from profile onto every event so
735
+ // they stay consistent per-user instead of randomizing per-event.
736
+ events.forEach(e => {
737
+ if (profile.subscription_tier) e.subscription_tier = profile.subscription_tier;
738
+ if (profile.Platform) e.Platform = profile.Platform;
739
+ if (profile.content_hub) e.content_hub = profile.content_hub;
740
+ });
741
+
742
+ // -- HOOK 8: PRO SUBSCRIBER CONTENT CREATION LIFT ---------
743
+ // Free-tier users drop 35% of final funnel step events to
744
+ // create visible conversion gap vs paid subscribers.
745
+ if (profile.subscription_tier !== "pro" && profile.subscription_tier !== "supporter") {
746
+ events = events.filter(e => {
747
+ if (e.event === "comment posted" && chance.bool({ likelihood: 35 })) return false;
748
+ return true;
749
+ });
750
+ }
724
751
 
725
752
  // -- HOOK 3: POWER CREATOR ENGAGEMENT LIFT ----------------
726
753
  // Users with >20 article_published events get 3x upvote_count.
@@ -739,7 +766,7 @@ const config = {
739
766
 
740
767
  // -- HOOK 4: DISCUSSION DEPTH BY CONTRIBUTOR TYPE ---------
741
768
  // Active contributors get cloned comment_posted events.
742
- if (meta && meta.profile && meta.profile.segment === "active_contributor") {
769
+ if (profile.segment === "active_contributor") {
743
770
  const templateComment = events.find(e => e.event === "comment posted");
744
771
  if (templateComment) {
745
772
  const existingComments = events.filter(e => e.event === "comment posted");
@@ -778,7 +805,7 @@ const config = {
778
805
  }
779
806
  }
780
807
 
781
- return record;
808
+ return events;
782
809
  }
783
810
 
784
811
  return record;
@@ -463,6 +463,9 @@
463
463
  },
464
464
  {
465
465
  "event": "account deactivated",
466
+ "isChurnEvent": true,
467
+ "returnLikelihood": 0.15,
468
+ "isStrictEvent": true,
466
469
  "properties": {
467
470
  "reason": [
468
471
  "switched_provider",
@@ -475,53 +478,6 @@
475
478
  }
476
479
  }
477
480
  ],
478
- "superProps": {
479
- "subscription_tier": [
480
- "free",
481
- "team",
482
- "business",
483
- "enterprise"
484
- ],
485
- "platform": [
486
- "web",
487
- "desktop_app",
488
- "cli"
489
- ],
490
- "language": [
491
- "javascript",
492
- "python",
493
- "go",
494
- "rust",
495
- "java",
496
- "typescript"
497
- ]
498
- },
499
- "userProps": {
500
- "dev_role": [
501
- "full_stack"
502
- ],
503
- "segment": [
504
- "full_stack"
505
- ],
506
- "team_size": [
507
- 41,
508
- 35,
509
- 9,
510
- 13,
511
- 21
512
- ],
513
- "repos_connected": [
514
- 0
515
- ],
516
- "org_name": [
517
- "personal"
518
- ],
519
- "experience_level": [
520
- "junior",
521
- "mid",
522
- "senior"
523
- ]
524
- },
525
481
  "funnels": [
526
482
  {
527
483
  "sequence": [
@@ -530,6 +486,7 @@
530
486
  "pipeline configured",
531
487
  "build completed"
532
488
  ],
489
+ "name": "Onboarding",
533
490
  "isFirstFunnel": true,
534
491
  "conversionRate": 45,
535
492
  "timeToConvert": 72,
@@ -541,6 +498,7 @@
541
498
  "deployment completed",
542
499
  "monitoring dashboard viewed"
543
500
  ],
501
+ "name": "Build-Deploy Pipeline",
544
502
  "conversionRate": 40,
545
503
  "timeToConvert": 48,
546
504
  "weight": 5
@@ -552,6 +510,7 @@
552
510
  "build completed",
553
511
  "deployment completed"
554
512
  ],
513
+ "name": "PR Review Flow",
555
514
  "conversionRate": 35,
556
515
  "timeToConvert": 72,
557
516
  "weight": 4
@@ -562,6 +521,7 @@
562
521
  "incident created",
563
522
  "incident resolved"
564
523
  ],
524
+ "name": "Incident Response",
565
525
  "conversionRate": 50,
566
526
  "timeToConvert": 24,
567
527
  "weight": 3
@@ -572,9 +532,70 @@
572
532
  "billing updated",
573
533
  "collaboration invited"
574
534
  ],
535
+ "name": "Upgrade Path",
575
536
  "conversionRate": 20,
576
537
  "timeToConvert": 168,
577
538
  "weight": 2
578
539
  }
579
- ]
540
+ ],
541
+ "superProps": {
542
+ "subscription_tier": [
543
+ "free",
544
+ "team",
545
+ "business",
546
+ "enterprise"
547
+ ],
548
+ "Platform": [
549
+ "web",
550
+ "desktop_app",
551
+ "cli"
552
+ ],
553
+ "language": [
554
+ "javascript",
555
+ "python",
556
+ "go",
557
+ "rust",
558
+ "java",
559
+ "typescript"
560
+ ]
561
+ },
562
+ "userProps": {
563
+ "dev_role": [
564
+ "full_stack"
565
+ ],
566
+ "segment": [
567
+ "full_stack"
568
+ ],
569
+ "team_size": [
570
+ 41,
571
+ 35,
572
+ 9,
573
+ 13,
574
+ 21
575
+ ],
576
+ "repos_connected": [
577
+ 0
578
+ ],
579
+ "org_name": [
580
+ "personal"
581
+ ],
582
+ "experience_level": [
583
+ "junior",
584
+ "mid",
585
+ "senior"
586
+ ]
587
+ },
588
+ "scdProps": {
589
+ "subscription_tier": {
590
+ "type": "user",
591
+ "frequency": "month",
592
+ "timing": "fuzzy",
593
+ "max": 6,
594
+ "values": [
595
+ "free",
596
+ "pro",
597
+ "enterprise"
598
+ ]
599
+ }
600
+ }
580
601
  }
@@ -1,16 +1,23 @@
1
+ // ── TWEAK THESE ──
2
+ const SEED = "dm4-devtools";
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 = "dm4-devtools";
8
17
  dayjs.extend(utc);
9
18
  const chance = u.initChance(SEED);
10
- const num_users = 5_000;
11
- const days = 100;
12
19
  const NOW = dayjs();
13
- const DATASET_START = NOW.subtract(days, "days");
20
+ const DATASET_START = NOW.subtract(num_days, "days");
14
21
 
15
22
  /** @typedef {import("../../types").Dungeon} Config */
16
23
 
@@ -208,12 +215,13 @@ const repoIds = v.range(1, 150).map(() => `REPO_${v.uid(6)}`);
208
215
  * manage organization-wide CI/CD infrastructure.
209
216
  *
210
217
  * ---------------------------------------------------------------
211
- * 8. ENTERPRISE BUILD-DEPLOY FUNNEL LIFT (funnel-pre hook)
218
+ * 8. ENTERPRISE BUILD-DEPLOY FUNNEL LIFT (everything hook)
212
219
  * ---------------------------------------------------------------
213
220
  *
214
- * PATTERN: Users with subscription_tier "enterprise" get 1.5x
215
- * conversion rate on the build-deploy pipeline funnel. Enterprise
216
- * customers have dedicated support and optimized pipelines.
221
+ * PATTERN: Free-tier users drop 35% of final funnel step events
222
+ * ("monitoring dashboard viewed"), creating a visible conversion
223
+ * gap between paid and free users. Enterprise/business users keep
224
+ * all their events.
217
225
  *
218
226
  * HOW TO FIND IT IN MIXPANEL:
219
227
  *
@@ -240,15 +248,15 @@ const repoIds = v.range(1, 150).map(() => `REPO_${v.uid(6)}`);
240
248
  * OSS -> Paid Conversion | team tier events | 0% | 30% | -
241
249
  * Post-Outage Recovery | deploys/day | 50 | 100+ | 2x+
242
250
  * DevOps Lead Profiles | team_size | 10 | 30 | 3x
243
- * Enterprise Funnel Lift | funnel conversion | 40% | 60% | 1.5x
251
+ * Enterprise Funnel Lift | funnel conversion | 40% | 60% | ~1.5x
244
252
  */
245
253
 
246
254
  /** @type {Config} */
247
255
  const config = {
248
- token: "",
256
+ token,
249
257
  seed: SEED,
250
- numDays: days,
251
- numEvents: num_users * 120,
258
+ numDays: num_days,
259
+ numEvents: num_users * avg_events_per_user,
252
260
  numUsers: num_users,
253
261
  hasAnonIds: false,
254
262
  hasSessionIds: true,
@@ -265,10 +273,16 @@ const config = {
265
273
  hasAdSpend: false,
266
274
  percentUsersBornInDataset: 35,
267
275
  hasAvatar: true,
268
- batchSize: 2_500_000,
269
276
  concurrency: 1,
270
277
  writeToDisk: false,
271
- scdProps: {},
278
+ scdProps: {
279
+ subscription_tier: {
280
+ values: ["free", "pro", "enterprise"],
281
+ frequency: "month",
282
+ timing: "fuzzy",
283
+ max: 6
284
+ }
285
+ },
272
286
  mirrorProps: {},
273
287
  lookupTables: [],
274
288
 
@@ -501,7 +515,7 @@ const config = {
501
515
  // -- SuperProps --------------------------------------------
502
516
  superProps: {
503
517
  subscription_tier: ["free", "free", "free", "team", "team", "business", "enterprise"],
504
- platform: ["web", "web", "desktop_app", "cli"],
518
+ Platform: ["web", "web", "desktop_app", "cli"],
505
519
  language: ["javascript", "python", "go", "rust", "java", "typescript"],
506
520
  },
507
521
 
@@ -513,6 +527,9 @@ const config = {
513
527
  repos_connected: [0],
514
528
  org_name: ["personal"],
515
529
  experience_level: ["junior", "junior", "mid", "mid", "mid", "senior", "senior"],
530
+ subscription_tier: ["free", "free", "free", "team", "team", "business", "enterprise"],
531
+ Platform: ["web", "web", "desktop_app", "cli"],
532
+ language: ["javascript", "python", "go", "rust", "java", "typescript"],
516
533
  },
517
534
 
518
535
  // -- Phase 2: Personas ------------------------------------
@@ -720,19 +737,9 @@ const config = {
720
737
  }
721
738
  }
722
739
 
723
- // -- HOOK 8: ENTERPRISE BUILD-DEPLOY FUNNEL LIFT (funnel-pre)
724
- // Enterprise subscribers convert 1.5x through build-deploy pipeline.
725
- // Business subscribers get a smaller lift.
726
- if (type === "funnel-pre") {
727
- if (meta && meta.profile) {
728
- const tier = meta.profile.subscription_tier;
729
- if (tier === "enterprise") {
730
- record.conversionRate = Math.min(record.conversionRate * 1.5, 95);
731
- } else if (tier === "business") {
732
- record.conversionRate = Math.min(record.conversionRate * 1.2, 90);
733
- }
734
- }
735
- }
740
+ // -- HOOK 8: ENTERPRISE BUILD-DEPLOY FUNNEL LIFT
741
+ // Conversion differences handled in everything hook via event filtering.
742
+ // (funnel-pre conversionRate modifications are diluted by organic events)
736
743
 
737
744
  // -- HOOK 1: BUILD FAILURE CASCADE (event) ----------------
738
745
  // Failed builds get 2x duration (retries take longer).
@@ -756,8 +763,28 @@ const config = {
756
763
 
757
764
  // -- EVERYTHING HOOKS -------------------------------------
758
765
  if (type === "everything") {
759
- const events = record;
766
+ let events = record;
760
767
  if (!events.length) return record;
768
+ const profile = meta && meta.profile ? meta.profile : {};
769
+
770
+ // -- SUPERPROP STAMPING -------------------------------
771
+ // Stamp superProp values from profile onto every event so
772
+ // they stay consistent per-user instead of randomizing per-event.
773
+ events.forEach(e => {
774
+ if (profile.subscription_tier) e.subscription_tier = profile.subscription_tier;
775
+ if (profile.Platform) e.Platform = profile.Platform;
776
+ if (profile.language) e.language = profile.language;
777
+ });
778
+
779
+ // -- HOOK 8: ENTERPRISE BUILD-DEPLOY FUNNEL LIFT ------
780
+ // Free-tier users drop 35% of final funnel step events to
781
+ // create visible conversion gap vs paid subscribers.
782
+ if (profile.subscription_tier !== "enterprise" && profile.subscription_tier !== "business") {
783
+ events = events.filter(e => {
784
+ if (e.event === "monitoring dashboard viewed" && chance.bool({ likelihood: 35 })) return false;
785
+ return true;
786
+ });
787
+ }
761
788
 
762
789
  // -- HOOK 3: COPILOT PR VELOCITY ----------------------
763
790
  // Users with ai_assist="copilot" on any PR get 1.5x more PRs.
@@ -799,7 +826,7 @@ const config = {
799
826
 
800
827
  // -- HOOK 5: OPEN SOURCE -> PAID CONVERSION -----------
801
828
  // OSS users with >15 events get 30% of events converted to "team" tier.
802
- if (meta && meta.profile && meta.profile.segment === "oss_user" && events.length > 15) {
829
+ if (profile.segment === "oss_user" && events.length > 15) {
803
830
  const conversionPoint = Math.floor(events.length * 0.7);
804
831
  for (let i = conversionPoint; i < events.length; i++) {
805
832
  events[i].subscription_tier = "team";
@@ -827,7 +854,7 @@ const config = {
827
854
  }
828
855
  });
829
856
 
830
- return record;
857
+ return events;
831
858
  }
832
859
 
833
860
  return record;