@ak--47/dungeon-master 1.2.3 → 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 (89) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +51 -13
  3. package/dungeons/technical/ad-spend.js +2 -2
  4. package/dungeons/technical/anonymous-users.js +2 -2
  5. package/dungeons/technical/array-of-object-lookup.js +2 -4
  6. package/dungeons/technical/experiments.js +2 -2
  7. package/dungeons/technical/foobar.js +2 -2
  8. package/dungeons/technical/group-analytics.js +2 -2
  9. package/dungeons/technical/mirror-strategies.js +2 -2
  10. package/dungeons/technical/nested-objects.js +2 -2
  11. package/dungeons/technical/retention-cadence.js +2 -3
  12. package/dungeons/technical/sanity.js +2 -2
  13. package/dungeons/technical/scale-test.js +2 -2
  14. package/dungeons/technical/scd.js +2 -2
  15. package/dungeons/technical/simple.js +5 -6
  16. package/dungeons/technical/simplest-schema.json +5 -0
  17. package/dungeons/technical/simplest.js +2 -2
  18. package/dungeons/technical/text-generation.js +3 -3
  19. package/dungeons/vertical/ai-platform.js +858 -0
  20. package/dungeons/vertical/community.js +84 -40
  21. package/dungeons/vertical/crypto.js +830 -0
  22. package/dungeons/vertical/dating.js +744 -0
  23. package/dungeons/vertical/devtools.js +175 -69
  24. package/dungeons/vertical/ecommerce.js +242 -94
  25. package/dungeons/vertical/education.js +330 -313
  26. package/dungeons/vertical/fintech.js +442 -313
  27. package/dungeons/vertical/fitness.js +143 -61
  28. package/dungeons/vertical/food-delivery.js +327 -353
  29. package/dungeons/vertical/gaming.js +912 -382
  30. package/dungeons/vertical/healthcare.js +142 -63
  31. package/dungeons/vertical/insurance-application.js +170 -76
  32. package/dungeons/vertical/logistics.js +115 -20
  33. package/dungeons/vertical/marketplace.js +152 -58
  34. package/dungeons/vertical/media.js +248 -384
  35. package/dungeons/vertical/real-estate.js +781 -0
  36. package/dungeons/vertical/sass.js +255 -266
  37. package/dungeons/vertical/social.js +264 -206
  38. package/dungeons/vertical/travel.js +117 -41
  39. package/index.js +17 -17
  40. package/lib/core/config-validator.js +159 -31
  41. package/lib/core/context.js +10 -24
  42. package/lib/core/storage.js +6 -1
  43. package/lib/generators/events.js +11 -14
  44. package/lib/generators/funnels.js +12 -4
  45. package/lib/generators/mirror.js +3 -2
  46. package/lib/generators/product-names.js +1 -1
  47. package/lib/generators/scd.js +2 -1
  48. package/lib/generators/text.js +1 -1
  49. package/lib/orchestrators/user-loop.js +81 -47
  50. package/lib/templates/macro-presets.js +111 -0
  51. package/lib/templates/soup-presets.js +19 -36
  52. package/lib/utils/utils.js +71 -39
  53. package/package.json +8 -2
  54. package/scripts/smoke-test-all.mjs +162 -0
  55. package/scripts/verify-runner.mjs +72 -24
  56. package/types.d.ts +251 -51
  57. package/dungeons/technical/ad-spend-schema.json +0 -128
  58. package/dungeons/technical/anonymous-users-schema.json +0 -92
  59. package/dungeons/technical/array-of-object-lookup-schema.json +0 -191
  60. package/dungeons/technical/experiments-schema.json +0 -203
  61. package/dungeons/technical/foobar-schema.json +0 -362
  62. package/dungeons/technical/group-analytics-schema.json +0 -241
  63. package/dungeons/technical/mirror-strategies-schema.json +0 -84
  64. package/dungeons/technical/nested-objects-schema.json +0 -145
  65. package/dungeons/technical/retention-cadence-schema.json +0 -37
  66. package/dungeons/technical/sanity-schema.json +0 -185
  67. package/dungeons/technical/scale-test-schema.json +0 -70
  68. package/dungeons/technical/scd-schema.json +0 -467
  69. package/dungeons/technical/simple-schema.json +0 -362
  70. package/dungeons/technical/text-generation-schema.json +0 -1062
  71. package/dungeons/user/.gitkeep +0 -0
  72. package/dungeons/vertical/community-schema.json +0 -579
  73. package/dungeons/vertical/devtools-schema.json +0 -601
  74. package/dungeons/vertical/ecommerce-schema.json +0 -604
  75. package/dungeons/vertical/education-schema.json +0 -5686
  76. package/dungeons/vertical/fintech-schema.json +0 -630
  77. package/dungeons/vertical/fitness-schema.json +0 -530
  78. package/dungeons/vertical/food-delivery-schema.json +0 -36728
  79. package/dungeons/vertical/gaming-schema.json +0 -438
  80. package/dungeons/vertical/healthcare-schema.json +0 -549
  81. package/dungeons/vertical/insurance-application-schema.json +0 -485
  82. package/dungeons/vertical/logistics-schema.json +0 -574
  83. package/dungeons/vertical/marketplace-schema.json +0 -533
  84. package/dungeons/vertical/media-schema.json +0 -4749
  85. package/dungeons/vertical/rpg-schema.json +0 -2491
  86. package/dungeons/vertical/rpg.js +0 -976
  87. package/dungeons/vertical/sass-schema.json +0 -3128
  88. package/dungeons/vertical/social-schema.json +0 -620
  89. package/dungeons/vertical/travel-schema.json +0 -580
@@ -2,7 +2,7 @@
2
2
  const SEED = "dm4-community";
3
3
  const num_days = 100;
4
4
  const num_users = 5_000;
5
- const avg_events_per_user = 120;
5
+ const avg_events_per_user_per_day = 1.2;
6
6
  let token = "your-mixpanel-token";
7
7
 
8
8
  // ── env overrides ──
@@ -16,9 +16,6 @@ import * as v from "ak-tools";
16
16
 
17
17
  dayjs.extend(utc);
18
18
  const chance = u.initChance(SEED);
19
- const NOW = dayjs();
20
- const DATASET_START = NOW.subtract(num_days, "days");
21
-
22
19
  /** @typedef {import("../../types").Dungeon} Config */
23
20
 
24
21
  // Generate consistent wiki/article IDs at module level
@@ -56,7 +53,16 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
56
53
 
57
54
  /**
58
55
  * ===================================================================
59
- * ANALYTICS HOOKS (8 hooks)
56
+ * ANALYTICS HOOKS (10 hooks)
57
+ *
58
+ * NOTE: All cohort effects are HIDDEN — no flag stamping. Discoverable via
59
+ * raw-prop breakdowns (day, content_hub, subscription_tier) or behavioral cohorts.
60
+ *
61
+ * Adds 9. CONTENT CREATION TIME-TO-CONVERT (Pro 1.3x faster, Free 1.25x slower)
62
+ * [funnel-post: visible only in Mixpanel funnel median TTC; cross-event
63
+ * MIN→MIN SQL queries do NOT show this]
64
+ * and 10. ARTICLE-PUBLISHED MAGIC NUMBER (sweet 2-5 → +35% upvote_count;
65
+ * over 6+ → drop 25% upvote events).
60
66
  * ===================================================================
61
67
  *
62
68
  * -------------------------------------------------------------------
@@ -73,9 +79,9 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
73
79
  * - Report type: Insights
74
80
  * - Event: "article published"
75
81
  * - Measure: Average of "word_count"
76
- * - Breakdown: "is_weekend"
77
- * - Expected: is_weekend=true should show ~1.5x avg word_count vs false
78
- * (true ~ 2250, false ~ 1500)
82
+ * - Breakdown: Day of Week
83
+ * - Expected: Sat/Sun ~ 1.5x avg word_count vs weekdays
84
+ * (weekend ~ 3325, weekday ~ 2218)
79
85
  *
80
86
  * REAL-WORLD ANALOGUE: Community wikis see longer, more thoughtful
81
87
  * contributions on weekends when creators have uninterrupted time.
@@ -258,8 +264,10 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
258
264
  const config = {
259
265
  token,
260
266
  seed: SEED,
261
- numDays: num_days,
262
- numEvents: num_users * avg_events_per_user,
267
+ datasetStart: "2026-01-01T00:00:00Z",
268
+ datasetEnd: "2026-04-28T23:59:59Z",
269
+ // numDays: num_days,
270
+ avgEventsPerUserPerDay: avg_events_per_user_per_day,
263
271
  numUsers: num_users,
264
272
  hasAnonIds: false,
265
273
  hasSessionIds: true,
@@ -274,7 +282,6 @@ const config = {
274
282
  hasCampaigns: false,
275
283
  isAnonymous: false,
276
284
  hasAdSpend: false,
277
- percentUsersBornInDataset: 35,
278
285
  hasAvatar: true,
279
286
  concurrency: 1,
280
287
  writeToDisk: false,
@@ -307,7 +314,6 @@ const config = {
307
314
  content_hub: ["gaming", "anime", "movies", "tv", "comics", "music"],
308
315
  view_count: u.weighNumRange(1, 100, 0.4, 50),
309
316
  time_on_page_sec: u.weighNumRange(5, 600, 0.4, 45),
310
- is_weekend: [false],
311
317
  },
312
318
  },
313
319
  {
@@ -319,8 +325,6 @@ const config = {
319
325
  word_count: u.weighNumRange(200, 5000, 0.4, 1500),
320
326
  has_images: [true, true, true, false],
321
327
  category: ["lore", "character", "episode_guide", "review", "tutorial", "news"],
322
- is_weekend: [false],
323
- poll_enabled: [false],
324
328
  },
325
329
  },
326
330
  {
@@ -695,37 +699,30 @@ const config = {
695
699
  }
696
700
  }
697
701
 
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)
701
-
702
- // -- HOOK 1: WEEKEND CONTENT SURGE (event) --------------------
703
- // Articles published on weekends get 1.5x word_count.
704
- if (type === "event") {
705
- if (record.event === "article published" || record.event === "article viewed") {
706
- const dow = dayjs(record.time).day();
707
- if (dow === 0 || dow === 6) {
708
- record.is_weekend = true;
709
- if (record.word_count) {
710
- record.word_count = Math.floor(record.word_count * 1.5);
702
+ // HOOK 9 (T2C): CONTENT CREATION TIME-TO-CONVERT (funnel-post)
703
+ // Pro/supporter subscribers complete the Content Creation funnel
704
+ // 1.3x faster (factor 0.77); Free 1.25x slower (factor 1.25).
705
+ if (type === "funnel-post") {
706
+ const segment = meta?.profile?.subscription_tier;
707
+ if (Array.isArray(record) && record.length > 1) {
708
+ const factor = (
709
+ segment === "pro" || segment === "supporter" ? 0.77 :
710
+ segment === "free" ? 1.25 :
711
+ 1.0
712
+ );
713
+ if (factor !== 1.0) {
714
+ for (let i = 1; i < record.length; i++) {
715
+ const prev = dayjs(record[i - 1].time);
716
+ const newGap = Math.round(dayjs(record[i].time).diff(prev) * factor);
717
+ record[i].time = prev.add(newGap, "milliseconds").toISOString();
711
718
  }
712
719
  }
713
720
  }
714
-
715
- // -- HOOK 2: TRENDING TOPIC WINDOW (event) ----------------
716
- // Days 35-50: gaming hub articles get 2x view_count.
717
- const TREND_START = DATASET_START.add(35, "days");
718
- const TREND_END = DATASET_START.add(50, "days");
719
- const eventTime = dayjs(record.time);
720
- if (record.event === "article viewed" && eventTime.isAfter(TREND_START) && eventTime.isBefore(TREND_END)) {
721
- if (record.content_hub === "gaming") {
722
- record.view_count = Math.floor((record.view_count || 50) * 2);
723
- }
724
- }
725
721
  }
726
722
 
727
723
  // -- EVERYTHING HOOKS -----------------------------------------
728
724
  if (type === "everything") {
725
+ const datasetStart = dayjs.unix(meta.datasetStart);
729
726
  let events = record;
730
727
  if (!events.length) return record;
731
728
  const profile = meta && meta.profile ? meta.profile : {};
@@ -739,6 +736,34 @@ const config = {
739
736
  if (profile.content_hub) e.content_hub = profile.content_hub;
740
737
  });
741
738
 
739
+ // HOOK 1: WEEKEND CONTENT SURGE — articles on Sat/Sun get
740
+ // word_count 1.5x. Mutates raw prop. No flag.
741
+ for (const e of events) {
742
+ if (e.event === 'article published' || e.event === 'article viewed') {
743
+ const dow = new Date(e.time).getUTCDay();
744
+ if ((dow === 0 || dow === 6) && e.word_count) {
745
+ e.word_count = Math.floor(e.word_count * 1.5);
746
+ }
747
+ }
748
+ }
749
+
750
+ // -- HOOK 2: TRENDING TOPIC WINDOW -------------------------
751
+ // Days 35-50: gaming hub articles get 2x view_count.
752
+ // Runs after superProp stamping so content_hub is the
753
+ // profile's consistent value, not the random event-level one.
754
+ const TREND_START = datasetStart.add(35, "days");
755
+ const TREND_END = datasetStart.add(50, "days");
756
+ if (profile.content_hub === "gaming") {
757
+ events.forEach(e => {
758
+ if (e.event === "article viewed") {
759
+ const eventTime = dayjs(e.time);
760
+ if (eventTime.isAfter(TREND_START) && eventTime.isBefore(TREND_END)) {
761
+ e.view_count = Math.floor((e.view_count || 50) * 2);
762
+ }
763
+ }
764
+ });
765
+ }
766
+
742
767
  // -- HOOK 8: PRO SUBSCRIBER CONTENT CREATION LIFT ---------
743
768
  // Free-tier users drop 35% of final funnel step events to
744
769
  // create visible conversion gap vs paid subscribers.
@@ -793,8 +818,8 @@ const config = {
793
818
  });
794
819
  }
795
820
 
796
- // -- HOOK 6: LURKER CHURN ---------------------------------
797
- // Users with <5 total events lose 60% after day 10.
821
+ // HOOK 6: LURKER CHURN — users with <5 events lose 60% after
822
+ // day 10. No flag.
798
823
  if (events.length < 5 && events.length > 0) {
799
824
  const firstEventTime = dayjs(events[0].time);
800
825
  const cutoff = firstEventTime.add(10, "days");
@@ -805,6 +830,25 @@ const config = {
805
830
  }
806
831
  }
807
832
 
833
+ // HOOK 10: ARTICLE-PUBLISHED MAGIC NUMBER (no flags)
834
+ // Sweet 2-5 articles published → +35% on upvote_count for
835
+ // upvote-given events. Over 6+ → drop 25% of upvote-given events
836
+ // (over-publishing dilutes signal). No flag.
837
+ const articleCount = events.filter(e => e.event === "article published").length;
838
+ if (articleCount >= 2 && articleCount <= 5) {
839
+ events.forEach(e => {
840
+ if (e.event === "upvote given" && typeof e.upvote_count === "number") {
841
+ e.upvote_count = Math.round(e.upvote_count * 1.35);
842
+ }
843
+ });
844
+ } else if (articleCount >= 6) {
845
+ for (let i = events.length - 1; i >= 0; i--) {
846
+ if (events[i].event === "upvote given" && chance.bool({ likelihood: 25 })) {
847
+ events.splice(i, 1);
848
+ }
849
+ }
850
+ }
851
+
808
852
  return events;
809
853
  }
810
854