@ak--47/dungeon-master 1.3.0 → 1.4.0
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 +58 -0
- package/dungeons/technical/array-of-object-lookup.js +0 -2
- package/dungeons/technical/hook-helpers-verify.js +89 -0
- package/dungeons/technical/identity-model-verify.js +47 -0
- package/dungeons/technical/pattern-aggregate-by-bin.js +41 -0
- package/dungeons/technical/pattern-attributed-by-source.js +42 -0
- package/dungeons/technical/pattern-frequency-by-frequency.js +40 -0
- package/dungeons/technical/pattern-funnel-frequency.js +54 -0
- package/dungeons/technical/pattern-ttc-by-segment.js +45 -0
- package/dungeons/technical/simple.js +3 -4
- package/dungeons/technical/simplest-schema.json +5 -0
- package/dungeons/technical/text-generation.js +1 -1
- package/dungeons/vertical/ai-platform.js +216 -164
- package/dungeons/vertical/community.js +74 -41
- package/dungeons/vertical/crypto.js +343 -233
- package/dungeons/vertical/dating.js +246 -292
- package/dungeons/vertical/devtools.js +179 -70
- package/dungeons/vertical/ecommerce.js +275 -122
- package/dungeons/vertical/education.js +345 -312
- package/dungeons/vertical/fintech.js +445 -314
- package/dungeons/vertical/fitness.js +199 -165
- package/dungeons/vertical/food-delivery.js +309 -330
- package/dungeons/vertical/gaming.js +387 -241
- package/dungeons/vertical/healthcare.js +149 -66
- package/dungeons/vertical/insurance-application.js +173 -75
- package/dungeons/vertical/logistics.js +107 -12
- package/dungeons/vertical/marketplace.js +171 -76
- package/dungeons/vertical/media.js +259 -402
- package/dungeons/vertical/real-estate.js +336 -318
- package/dungeons/vertical/sass.js +294 -288
- package/dungeons/vertical/social.js +289 -234
- package/dungeons/vertical/travel.js +66 -20
- package/index.js +17 -17
- package/lib/core/config-validator.js +226 -175
- package/lib/core/context.js +10 -24
- package/lib/core/storage.js +6 -1
- package/lib/generators/events.js +57 -104
- package/lib/generators/funnels.js +212 -93
- 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/hook-helpers/_internal.js +23 -0
- package/lib/hook-helpers/cohort.js +124 -0
- package/lib/hook-helpers/identity.js +56 -0
- package/lib/hook-helpers/index.js +44 -0
- package/lib/hook-helpers/inject.js +99 -0
- package/lib/hook-helpers/mutate.js +151 -0
- package/lib/hook-helpers/timing.js +99 -0
- package/lib/hook-patterns/aggregate-per-user-by-bin.js +38 -0
- package/lib/hook-patterns/attributed-by-source.js +72 -0
- package/lib/hook-patterns/frequency-by-frequency.js +46 -0
- package/lib/hook-patterns/funnel-frequency-breakdown.js +73 -0
- package/lib/hook-patterns/index.js +14 -0
- package/lib/hook-patterns/time-to-convert-by-segment.js +41 -0
- package/lib/orchestrators/user-loop.js +143 -293
- package/lib/utils/utils.js +97 -52
- package/lib/verify/emulate-breakdown.js +281 -0
- package/lib/verify/index.js +12 -0
- package/lib/verify/verify-dungeon.js +61 -0
- package/package.json +6 -4
- package/scripts/smoke-test-all.mjs +162 -0
- package/scripts/verify-runner.mjs +72 -24
- package/types.d.ts +434 -225
- 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/vertical/ai-platform-schema.json +0 -617
- package/dungeons/vertical/community-schema.json +0 -579
- package/dungeons/vertical/crypto-schema.json +0 -546
- package/dungeons/vertical/dating-schema.json +0 -401
- 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 -2703
- 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/real-estate-schema.json +0 -527
- package/dungeons/vertical/sass-schema.json +0 -3128
- package/dungeons/vertical/social-schema.json +0 -620
- package/dungeons/vertical/travel-schema.json +0 -580
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ── TWEAK THESE ──
|
|
2
2
|
const SEED = "dm4-community";
|
|
3
|
-
const num_days =
|
|
4
|
-
const num_users =
|
|
3
|
+
const num_days = 120;
|
|
4
|
+
const num_users = 10_000;
|
|
5
5
|
const avg_events_per_user_per_day = 1.2;
|
|
6
6
|
let token = "your-mixpanel-token";
|
|
7
7
|
|
|
@@ -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
|
|
@@ -34,7 +31,7 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
|
|
|
34
31
|
* users create articles, discuss topics, moderate content, and
|
|
35
32
|
* build collaborative knowledge bases across fandoms.
|
|
36
33
|
*
|
|
37
|
-
* -
|
|
34
|
+
* - 10,000 users over 120 days
|
|
38
35
|
* - Multi-role system: power creators (5%), moderators (8%),
|
|
39
36
|
* active contributors (25%), readers (45%), lurkers (17%)
|
|
40
37
|
* - Core loop: sign up -> search -> read articles -> contribute -> discuss
|
|
@@ -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.
|
|
@@ -256,12 +262,16 @@ const communityIds = v.range(1, 30).map(() => `COMM_${v.uid(4)}`);
|
|
|
256
262
|
|
|
257
263
|
/** @type {Config} */
|
|
258
264
|
const config = {
|
|
265
|
+
version: 2,
|
|
259
266
|
token,
|
|
260
267
|
seed: SEED,
|
|
261
|
-
|
|
268
|
+
datasetStart: "2026-01-01T00:00:00Z",
|
|
269
|
+
datasetEnd: "2026-05-01T23:59:59Z",
|
|
270
|
+
// numDays: num_days,
|
|
262
271
|
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
263
272
|
numUsers: num_users,
|
|
264
|
-
hasAnonIds:
|
|
273
|
+
hasAnonIds: true,
|
|
274
|
+
avgDevicePerUser: 2,
|
|
265
275
|
hasSessionIds: true,
|
|
266
276
|
format: "json",
|
|
267
277
|
gzip: true,
|
|
@@ -294,6 +304,7 @@ const config = {
|
|
|
294
304
|
event: "account created",
|
|
295
305
|
weight: 1,
|
|
296
306
|
isFirstEvent: true,
|
|
307
|
+
isAuthEvent: true,
|
|
297
308
|
properties: {
|
|
298
309
|
referral_source: ["organic", "google_search", "reddit_referral", "youtube_link", "friend_invite"],
|
|
299
310
|
},
|
|
@@ -306,7 +317,6 @@ const config = {
|
|
|
306
317
|
content_hub: ["gaming", "anime", "movies", "tv", "comics", "music"],
|
|
307
318
|
view_count: u.weighNumRange(1, 100, 0.4, 50),
|
|
308
319
|
time_on_page_sec: u.weighNumRange(5, 600, 0.4, 45),
|
|
309
|
-
is_weekend: [false],
|
|
310
320
|
},
|
|
311
321
|
},
|
|
312
322
|
{
|
|
@@ -318,8 +328,6 @@ const config = {
|
|
|
318
328
|
word_count: u.weighNumRange(200, 5000, 0.4, 1500),
|
|
319
329
|
has_images: [true, true, true, false],
|
|
320
330
|
category: ["lore", "character", "episode_guide", "review", "tutorial", "news"],
|
|
321
|
-
is_weekend: [false],
|
|
322
|
-
poll_enabled: [false],
|
|
323
331
|
},
|
|
324
332
|
},
|
|
325
333
|
{
|
|
@@ -613,7 +621,7 @@ const config = {
|
|
|
613
621
|
name: "google_search",
|
|
614
622
|
source: "google",
|
|
615
623
|
medium: "organic",
|
|
616
|
-
activeDays: [0,
|
|
624
|
+
activeDays: [0, 120],
|
|
617
625
|
dailyBudget: [100, 400],
|
|
618
626
|
acquisitionRate: 0.03,
|
|
619
627
|
userPersonaBias: { reader: 0.5, lurker: 0.3 },
|
|
@@ -622,7 +630,7 @@ const config = {
|
|
|
622
630
|
name: "reddit_referral",
|
|
623
631
|
source: "reddit",
|
|
624
632
|
medium: "referral",
|
|
625
|
-
activeDays: [0,
|
|
633
|
+
activeDays: [0, 120],
|
|
626
634
|
dailyBudget: [50, 200],
|
|
627
635
|
acquisitionRate: 0.02,
|
|
628
636
|
userPersonaBias: { active_contributor: 0.5, moderator: 0.3 },
|
|
@@ -631,7 +639,7 @@ const config = {
|
|
|
631
639
|
name: "youtube_link",
|
|
632
640
|
source: "youtube",
|
|
633
641
|
medium: "referral",
|
|
634
|
-
activeDays: [0,
|
|
642
|
+
activeDays: [0, 120],
|
|
635
643
|
dailyBudget: [75, 250],
|
|
636
644
|
acquisitionRate: 0.02,
|
|
637
645
|
userPersonaBias: { lurker: 0.5, reader: 0.3 },
|
|
@@ -694,20 +702,30 @@ const config = {
|
|
|
694
702
|
}
|
|
695
703
|
}
|
|
696
704
|
|
|
697
|
-
//
|
|
698
|
-
//
|
|
699
|
-
// (
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
705
|
+
// HOOK 9 (T2C): CONTENT CREATION TIME-TO-CONVERT (funnel-post)
|
|
706
|
+
// Pro/supporter subscribers complete the Content Creation funnel
|
|
707
|
+
// 1.3x faster (factor 0.77); Free 1.25x slower (factor 1.25).
|
|
708
|
+
if (type === "funnel-post") {
|
|
709
|
+
const segment = meta?.profile?.subscription_tier;
|
|
710
|
+
if (Array.isArray(record) && record.length > 1) {
|
|
711
|
+
const factor = (
|
|
712
|
+
segment === "pro" || segment === "supporter" ? 0.77 :
|
|
713
|
+
segment === "free" ? 1.25 :
|
|
714
|
+
1.0
|
|
715
|
+
);
|
|
716
|
+
if (factor !== 1.0) {
|
|
717
|
+
for (let i = 1; i < record.length; i++) {
|
|
718
|
+
const prev = dayjs(record[i - 1].time);
|
|
719
|
+
const newGap = Math.round(dayjs(record[i].time).diff(prev) * factor);
|
|
720
|
+
record[i].time = prev.add(newGap, "milliseconds").toISOString();
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
708
725
|
|
|
709
726
|
// -- EVERYTHING HOOKS -----------------------------------------
|
|
710
727
|
if (type === "everything") {
|
|
728
|
+
const datasetStart = dayjs.unix(meta.datasetStart);
|
|
711
729
|
let events = record;
|
|
712
730
|
if (!events.length) return record;
|
|
713
731
|
const profile = meta && meta.profile ? meta.profile : {};
|
|
@@ -721,17 +739,13 @@ const config = {
|
|
|
721
739
|
if (profile.content_hub) e.content_hub = profile.content_hub;
|
|
722
740
|
});
|
|
723
741
|
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
// Runs after sessionization so DOW tags match final timestamps.
|
|
742
|
+
// HOOK 1: WEEKEND CONTENT SURGE — articles on Sat/Sun get
|
|
743
|
+
// word_count 1.5x. Mutates raw prop. No flag.
|
|
727
744
|
for (const e of events) {
|
|
728
745
|
if (e.event === 'article published' || e.event === 'article viewed') {
|
|
729
746
|
const dow = new Date(e.time).getUTCDay();
|
|
730
|
-
if (dow === 0 || dow === 6) {
|
|
731
|
-
e.
|
|
732
|
-
if (e.word_count) {
|
|
733
|
-
e.word_count = Math.floor(e.word_count * 1.5);
|
|
734
|
-
}
|
|
747
|
+
if ((dow === 0 || dow === 6) && e.word_count) {
|
|
748
|
+
e.word_count = Math.floor(e.word_count * 1.5);
|
|
735
749
|
}
|
|
736
750
|
}
|
|
737
751
|
}
|
|
@@ -740,8 +754,8 @@ const config = {
|
|
|
740
754
|
// Days 35-50: gaming hub articles get 2x view_count.
|
|
741
755
|
// Runs after superProp stamping so content_hub is the
|
|
742
756
|
// profile's consistent value, not the random event-level one.
|
|
743
|
-
const TREND_START =
|
|
744
|
-
const TREND_END =
|
|
757
|
+
const TREND_START = datasetStart.add(35, "days");
|
|
758
|
+
const TREND_END = datasetStart.add(50, "days");
|
|
745
759
|
if (profile.content_hub === "gaming") {
|
|
746
760
|
events.forEach(e => {
|
|
747
761
|
if (e.event === "article viewed") {
|
|
@@ -807,8 +821,8 @@ const config = {
|
|
|
807
821
|
});
|
|
808
822
|
}
|
|
809
823
|
|
|
810
|
-
//
|
|
811
|
-
//
|
|
824
|
+
// HOOK 6: LURKER CHURN — users with <5 events lose 60% after
|
|
825
|
+
// day 10. No flag.
|
|
812
826
|
if (events.length < 5 && events.length > 0) {
|
|
813
827
|
const firstEventTime = dayjs(events[0].time);
|
|
814
828
|
const cutoff = firstEventTime.add(10, "days");
|
|
@@ -819,6 +833,25 @@ const config = {
|
|
|
819
833
|
}
|
|
820
834
|
}
|
|
821
835
|
|
|
836
|
+
// HOOK 10: ARTICLE-PUBLISHED MAGIC NUMBER (no flags)
|
|
837
|
+
// Sweet 2-5 articles published → +35% on upvote_count for
|
|
838
|
+
// upvote-given events. Over 6+ → drop 25% of upvote-given events
|
|
839
|
+
// (over-publishing dilutes signal). No flag.
|
|
840
|
+
const articleCount = events.filter(e => e.event === "article published").length;
|
|
841
|
+
if (articleCount >= 2 && articleCount <= 5) {
|
|
842
|
+
events.forEach(e => {
|
|
843
|
+
if (e.event === "upvote given" && typeof e.upvote_count === "number") {
|
|
844
|
+
e.upvote_count = Math.round(e.upvote_count * 1.35);
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
} else if (articleCount >= 6) {
|
|
848
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
849
|
+
if (events[i].event === "upvote given" && chance.bool({ likelihood: 25 })) {
|
|
850
|
+
events.splice(i, 1);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
822
855
|
return events;
|
|
823
856
|
}
|
|
824
857
|
|