@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.
- package/CHANGELOG.md +42 -0
- package/README.md +51 -13
- package/dungeons/technical/ad-spend.js +2 -2
- package/dungeons/technical/anonymous-users.js +2 -2
- package/dungeons/technical/array-of-object-lookup.js +2 -4
- package/dungeons/technical/experiments.js +2 -2
- package/dungeons/technical/foobar.js +2 -2
- package/dungeons/technical/group-analytics.js +2 -2
- package/dungeons/technical/mirror-strategies.js +2 -2
- package/dungeons/technical/nested-objects.js +2 -2
- package/dungeons/technical/retention-cadence.js +2 -3
- package/dungeons/technical/sanity.js +2 -2
- package/dungeons/technical/scale-test.js +2 -2
- package/dungeons/technical/scd.js +2 -2
- package/dungeons/technical/simple.js +5 -6
- package/dungeons/technical/simplest-schema.json +5 -0
- package/dungeons/technical/simplest.js +2 -2
- package/dungeons/technical/text-generation.js +3 -3
- package/dungeons/vertical/ai-platform.js +858 -0
- package/dungeons/vertical/community.js +84 -40
- package/dungeons/vertical/crypto.js +830 -0
- package/dungeons/vertical/dating.js +744 -0
- package/dungeons/vertical/devtools.js +175 -69
- package/dungeons/vertical/ecommerce.js +242 -94
- package/dungeons/vertical/education.js +330 -313
- package/dungeons/vertical/fintech.js +442 -313
- package/dungeons/vertical/fitness.js +143 -61
- package/dungeons/vertical/food-delivery.js +327 -353
- package/dungeons/vertical/gaming.js +912 -382
- package/dungeons/vertical/healthcare.js +142 -63
- package/dungeons/vertical/insurance-application.js +170 -76
- package/dungeons/vertical/logistics.js +115 -20
- package/dungeons/vertical/marketplace.js +152 -58
- package/dungeons/vertical/media.js +248 -384
- package/dungeons/vertical/real-estate.js +781 -0
- package/dungeons/vertical/sass.js +255 -266
- package/dungeons/vertical/social.js +264 -206
- package/dungeons/vertical/travel.js +117 -41
- package/index.js +17 -17
- package/lib/core/config-validator.js +159 -31
- package/lib/core/context.js +10 -24
- package/lib/core/storage.js +6 -1
- package/lib/generators/events.js +11 -14
- package/lib/generators/funnels.js +12 -4
- package/lib/generators/mirror.js +3 -2
- package/lib/generators/product-names.js +1 -1
- package/lib/generators/scd.js +2 -1
- package/lib/generators/text.js +1 -1
- package/lib/orchestrators/user-loop.js +81 -47
- package/lib/templates/macro-presets.js +111 -0
- package/lib/templates/soup-presets.js +19 -36
- package/lib/utils/utils.js +71 -39
- package/package.json +8 -2
- package/scripts/smoke-test-all.mjs +162 -0
- package/scripts/verify-runner.mjs +72 -24
- package/types.d.ts +251 -51
- package/dungeons/technical/ad-spend-schema.json +0 -128
- package/dungeons/technical/anonymous-users-schema.json +0 -92
- package/dungeons/technical/array-of-object-lookup-schema.json +0 -191
- package/dungeons/technical/experiments-schema.json +0 -203
- package/dungeons/technical/foobar-schema.json +0 -362
- package/dungeons/technical/group-analytics-schema.json +0 -241
- package/dungeons/technical/mirror-strategies-schema.json +0 -84
- package/dungeons/technical/nested-objects-schema.json +0 -145
- package/dungeons/technical/retention-cadence-schema.json +0 -37
- package/dungeons/technical/sanity-schema.json +0 -185
- package/dungeons/technical/scale-test-schema.json +0 -70
- package/dungeons/technical/scd-schema.json +0 -467
- package/dungeons/technical/simple-schema.json +0 -362
- package/dungeons/technical/text-generation-schema.json +0 -1062
- package/dungeons/user/.gitkeep +0 -0
- package/dungeons/vertical/community-schema.json +0 -579
- package/dungeons/vertical/devtools-schema.json +0 -601
- package/dungeons/vertical/ecommerce-schema.json +0 -604
- package/dungeons/vertical/education-schema.json +0 -5686
- package/dungeons/vertical/fintech-schema.json +0 -630
- package/dungeons/vertical/fitness-schema.json +0 -530
- package/dungeons/vertical/food-delivery-schema.json +0 -36728
- package/dungeons/vertical/gaming-schema.json +0 -438
- package/dungeons/vertical/healthcare-schema.json +0 -549
- package/dungeons/vertical/insurance-application-schema.json +0 -485
- package/dungeons/vertical/logistics-schema.json +0 -574
- package/dungeons/vertical/marketplace-schema.json +0 -533
- package/dungeons/vertical/media-schema.json +0 -4749
- package/dungeons/vertical/rpg-schema.json +0 -2491
- package/dungeons/vertical/rpg.js +0 -976
- package/dungeons/vertical/sass-schema.json +0 -3128
- package/dungeons/vertical/social-schema.json +0 -620
- 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
|
|
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 (
|
|
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:
|
|
77
|
-
* - Expected:
|
|
78
|
-
* (
|
|
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
|
-
|
|
262
|
-
|
|
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
|
-
//
|
|
699
|
-
//
|
|
700
|
-
// (
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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
|
-
//
|
|
797
|
-
//
|
|
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
|
|