@ak--47/dungeon-master 1.3.0 → 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/dungeons/technical/array-of-object-lookup.js +0 -2
- 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 +192 -133
- package/dungeons/vertical/community.js +64 -34
- package/dungeons/vertical/crypto.js +333 -224
- package/dungeons/vertical/dating.js +228 -282
- package/dungeons/vertical/devtools.js +164 -62
- package/dungeons/vertical/ecommerce.js +240 -91
- package/dungeons/vertical/education.js +328 -310
- package/dungeons/vertical/fintech.js +437 -311
- package/dungeons/vertical/fitness.js +141 -58
- package/dungeons/vertical/food-delivery.js +298 -318
- package/dungeons/vertical/gaming.js +378 -231
- package/dungeons/vertical/healthcare.js +140 -60
- package/dungeons/vertical/insurance-application.js +168 -73
- package/dungeons/vertical/logistics.js +95 -6
- package/dungeons/vertical/marketplace.js +137 -51
- package/dungeons/vertical/media.js +241 -386
- package/dungeons/vertical/real-estate.js +322 -315
- package/dungeons/vertical/sass.js +253 -263
- package/dungeons/vertical/social.js +262 -206
- package/dungeons/vertical/travel.js +59 -16
- package/index.js +17 -17
- package/lib/core/config-validator.js +93 -21
- 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 +47 -47
- package/lib/utils/utils.js +71 -39
- package/package.json +1 -1
- package/scripts/smoke-test-all.mjs +162 -0
- package/scripts/verify-runner.mjs +72 -24
- package/types.d.ts +38 -15
- 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
|
@@ -15,9 +15,6 @@ import * as u from "../../lib/utils/utils.js";
|
|
|
15
15
|
|
|
16
16
|
dayjs.extend(utc);
|
|
17
17
|
const chance = u.initChance(SEED);
|
|
18
|
-
const NOW = dayjs();
|
|
19
|
-
const DATASET_START = NOW.subtract(num_days, "days");
|
|
20
|
-
|
|
21
18
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
22
19
|
|
|
23
20
|
/**
|
|
@@ -50,29 +47,28 @@ const DATASET_START = NOW.subtract(num_days, "days");
|
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
49
|
* ═══════════════════════════════════════════════════════════════
|
|
53
|
-
* ANALYTICS HOOKS (
|
|
50
|
+
* ANALYTICS HOOKS (10 hooks)
|
|
54
51
|
* ═══════════════════════════════════════════════════════════════
|
|
55
52
|
*
|
|
53
|
+
* NOTE: All cohort effects are HIDDEN — no flag stamping. Discoverable
|
|
54
|
+
* via raw-prop breakdowns (HOD, day, segment) or behavioral cohorts.
|
|
55
|
+
*
|
|
56
56
|
* ───────────────────────────────────────────────────────────────
|
|
57
|
-
* 1. MORNING WORKOUT BOOST (
|
|
57
|
+
* 1. MORNING WORKOUT BOOST (everything)
|
|
58
58
|
* ───────────────────────────────────────────────────────────────
|
|
59
59
|
*
|
|
60
|
-
* PATTERN: Workouts
|
|
61
|
-
*
|
|
62
|
-
* morning exercise.
|
|
60
|
+
* PATTERN: Workouts in 5-9 UTC get calories_burned 1.3x. Mutates
|
|
61
|
+
* raw prop. No flag.
|
|
63
62
|
*
|
|
64
63
|
* HOW TO FIND IT IN MIXPANEL:
|
|
65
64
|
*
|
|
66
|
-
* Report 1:
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* • Expected: is_morning_workout=true should show ~1.3x avg
|
|
72
|
-
* calories vs false (true ≈ 390, false ≈ 300)
|
|
65
|
+
* Report 1: Avg Calories Burned by Hour of Day
|
|
66
|
+
* - Event: "workout completed"
|
|
67
|
+
* - Measure: Average of "calories_burned"
|
|
68
|
+
* - Breakdown: hour of day
|
|
69
|
+
* - Expected: 5-9 hours show ~ 1.3x baseline
|
|
73
70
|
*
|
|
74
|
-
* REAL-WORLD ANALOGUE:
|
|
75
|
-
* as more effective for fat loss, driving engagement.
|
|
71
|
+
* REAL-WORLD ANALOGUE: Morning workouts get a metabolic boost.
|
|
76
72
|
*
|
|
77
73
|
* ───────────────────────────────────────────────────────────────
|
|
78
74
|
* 2. POST-LAUNCH AI COACHING LIFT (event hook)
|
|
@@ -244,27 +240,79 @@ const DATASET_START = NOW.subtract(num_days, "days");
|
|
|
244
240
|
* REAL-WORLD ANALOGUE: Annual gym memberships have higher
|
|
245
241
|
* utilization — sunk cost + commitment drives consistency.
|
|
246
242
|
*
|
|
243
|
+
* ───────────────────────────────────────────────────────────────
|
|
244
|
+
* 9. WORKOUT LOOP TIME-TO-CONVERT (funnel-post)
|
|
245
|
+
* ───────────────────────────────────────────────────────────────
|
|
246
|
+
*
|
|
247
|
+
* PATTERN: Annual + family subscribers complete the Workout Loop
|
|
248
|
+
* funnel 1.3x faster (factor 0.77); Free users 1.25x slower (factor 1.25).
|
|
249
|
+
*
|
|
250
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
251
|
+
*
|
|
252
|
+
* Report 1: Workout Loop Median Time-to-Convert by Subscription
|
|
253
|
+
* - Funnels > "workout planned" -> "workout completed" -> "progress checked"
|
|
254
|
+
* - Measure: Median time to convert
|
|
255
|
+
* - Breakdown: subscription_plan
|
|
256
|
+
* - Expected: annual ~ 0.77x; free ~ 1.25x
|
|
257
|
+
*
|
|
258
|
+
* NOTE (funnel-post measurement): visible only via Mixpanel funnel
|
|
259
|
+
* median TTC. Cross-event MIN→MIN SQL queries on raw events do NOT
|
|
260
|
+
* show this — funnel-post adjusts gaps within funnel instances, not
|
|
261
|
+
* across the user's full event history.
|
|
262
|
+
*
|
|
263
|
+
* ───────────────────────────────────────────────────────────────
|
|
264
|
+
* 10. WORKOUT-COUNT MAGIC NUMBER (everything)
|
|
265
|
+
* ───────────────────────────────────────────────────────────────
|
|
266
|
+
*
|
|
267
|
+
* PATTERN: Sweet 12-20 workouts/user → +35% on workout
|
|
268
|
+
* duration_minutes (peak progression). Over 21+ → drop 30% of
|
|
269
|
+
* post-day-30 events (overtraining churn). No flag.
|
|
270
|
+
*
|
|
271
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
272
|
+
*
|
|
273
|
+
* Report 1: Avg Workout Duration by Workout-Count Bucket
|
|
274
|
+
* - Cohort A: users with 12-20 "workout completed"
|
|
275
|
+
* - Cohort B: users with 0-11
|
|
276
|
+
* - Event: "workout completed"
|
|
277
|
+
* - Measure: Average of "duration_minutes"
|
|
278
|
+
* - Expected: A ~ 1.35x B
|
|
279
|
+
*
|
|
280
|
+
* Report 2: D30+ Activity on Heavy Workout Cohort
|
|
281
|
+
* - Cohort C: users with >= 21 "workout completed"
|
|
282
|
+
* - Cohort A: users with 12-20
|
|
283
|
+
* - Event: any event
|
|
284
|
+
* - Measure: Total per user, post-day-30
|
|
285
|
+
* - Expected: C ~ 30% fewer post-day-30 events per user
|
|
286
|
+
*
|
|
287
|
+
* REAL-WORLD ANALOGUE: Sweet-spot training drives progression;
|
|
288
|
+
* over-training causes injury and burnout.
|
|
289
|
+
*
|
|
247
290
|
* ═══════════════════════════════════════════════════════════════
|
|
248
291
|
* EXPECTED METRICS SUMMARY
|
|
249
292
|
* ═══════════════════════════════════════════════════════════════
|
|
250
293
|
*
|
|
251
|
-
* Hook | Metric | Baseline | Effect
|
|
252
|
-
*
|
|
253
|
-
* Morning Workout Boost | calories_burned
|
|
254
|
-
* AI Coaching Lift | duration_minutes |
|
|
255
|
-
* Streak Retention | achievements/user |
|
|
256
|
-
* Social Challenge Completion | challenges/user |
|
|
257
|
-
* Resolver Churn Cliff | events after day 14 |
|
|
258
|
-
* Coach Session Quality | satisfaction_score
|
|
259
|
-
* Coach Profile Enrichment | total_workouts | 0 | 350
|
|
260
|
-
* Annual Funnel Lift | funnel conversion | 45% | 63%
|
|
294
|
+
* Hook | Metric | Baseline | Effect | Ratio
|
|
295
|
+
* ----------------------------|---------------------|----------|-----------|------
|
|
296
|
+
* Morning Workout Boost | calories_burned 5-9 | 1x | 1.3x | 1.3x
|
|
297
|
+
* AI Coaching Lift | duration_minutes | 1x | 1.2x | 1.2x
|
|
298
|
+
* Streak Retention | achievements/user | 1x | 2-3x | 2-3x
|
|
299
|
+
* Social Challenge Completion | challenges/user | 1x | 1.5x | 1.5x
|
|
300
|
+
* Resolver Churn Cliff | events after day 14 | 1x | 0.3x | -70%
|
|
301
|
+
* Coach Session Quality | satisfaction_score | 3.0 | 4.3 | 1.4x
|
|
302
|
+
* Coach Profile Enrichment | total_workouts | 0 | 350 | n/a
|
|
303
|
+
* Annual Funnel Lift | funnel conversion | 45% | 63% | 1.4x
|
|
304
|
+
* Workout Loop T2C | median min by tier | 1x | 0.77/1.25x| ~ 1.6x range
|
|
305
|
+
* Workout Magic Number | sweet duration_min | 1x | 1.35x | 1.35x
|
|
306
|
+
* Workout Magic Number | over D30+ activity | 1x | 0.7x | -30%
|
|
261
307
|
*/
|
|
262
308
|
|
|
263
309
|
/** @type {Config} */
|
|
264
310
|
const config = {
|
|
265
311
|
token,
|
|
266
312
|
seed: SEED,
|
|
267
|
-
|
|
313
|
+
datasetStart: "2026-01-01T00:00:00Z",
|
|
314
|
+
datasetEnd: "2026-04-28T23:59:59Z",
|
|
315
|
+
// numDays: num_days,
|
|
268
316
|
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
269
317
|
numUsers: num_users,
|
|
270
318
|
hasAnonIds: false,
|
|
@@ -311,7 +359,6 @@ const config = {
|
|
|
311
359
|
duration_minutes: u.weighNumRange(10, 90, 0.5, 40),
|
|
312
360
|
calories_burned: u.weighNumRange(50, 800, 0.4, 300),
|
|
313
361
|
heart_rate_avg: u.weighNumRange(80, 185, 0.5, 130),
|
|
314
|
-
is_morning_workout: [false],
|
|
315
362
|
satisfaction_score: u.weighNumRange(1, 5, 0.7, 3),
|
|
316
363
|
coaching_mode: ["self_guided"],
|
|
317
364
|
challenge_mode: ["solo"],
|
|
@@ -591,8 +638,8 @@ const config = {
|
|
|
591
638
|
{ name: "family", price: 149.99 },
|
|
592
639
|
],
|
|
593
640
|
lifecycle: {
|
|
594
|
-
trialToPayRate: 0.
|
|
595
|
-
upgradeRate: 0.
|
|
641
|
+
trialToPayRate: 0.65,
|
|
642
|
+
upgradeRate: 0.65,
|
|
596
643
|
downgradeRate: 0.03,
|
|
597
644
|
churnRate: 0.05,
|
|
598
645
|
winBackRate: 0.10,
|
|
@@ -677,8 +724,8 @@ const config = {
|
|
|
677
724
|
|
|
678
725
|
// ── Hook Function ──────────────────────────────────────
|
|
679
726
|
hook: function (record, type, meta) {
|
|
680
|
-
//
|
|
681
|
-
//
|
|
727
|
+
// HOOK 7: COACH PROFILE ENRICHMENT (user) — coach segment users
|
|
728
|
+
// get high total_workouts + streak_days.
|
|
682
729
|
if (type === "user") {
|
|
683
730
|
if (record.segment === "coach") {
|
|
684
731
|
record.total_workouts = chance.integer({ min: 200, max: 500 });
|
|
@@ -686,29 +733,35 @@ const config = {
|
|
|
686
733
|
}
|
|
687
734
|
}
|
|
688
735
|
|
|
689
|
-
//
|
|
690
|
-
//
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
if (
|
|
701
|
-
record.
|
|
702
|
-
|
|
703
|
-
|
|
736
|
+
// HOOK 9 (T2C): WORKOUT LOOP TIME-TO-CONVERT (funnel-post)
|
|
737
|
+
// Annual subscribers complete the Workout Loop funnel 1.3x faster
|
|
738
|
+
// (factor 0.77); Free users 1.25x slower (factor 1.25).
|
|
739
|
+
if (type === "funnel-post") {
|
|
740
|
+
const segment = meta?.profile?.subscription_plan;
|
|
741
|
+
if (Array.isArray(record) && record.length > 1) {
|
|
742
|
+
const factor = (
|
|
743
|
+
segment === "annual" || segment === "family" ? 0.77 :
|
|
744
|
+
segment === "free" ? 1.25 :
|
|
745
|
+
1.0
|
|
746
|
+
);
|
|
747
|
+
if (factor !== 1.0) {
|
|
748
|
+
for (let i = 1; i < record.length; i++) {
|
|
749
|
+
const prev = dayjs(record[i - 1].time);
|
|
750
|
+
const newGap = Math.round(dayjs(record[i].time).diff(prev) * factor);
|
|
751
|
+
record[i].time = prev.add(newGap, "milliseconds").toISOString();
|
|
704
752
|
}
|
|
705
753
|
}
|
|
706
754
|
}
|
|
755
|
+
}
|
|
707
756
|
|
|
757
|
+
// (HOOK 1: MORNING WORKOUT BOOST moved to everything hook — hour checks
|
|
758
|
+
// must run after bunchIntoSessions redistributes timestamps)
|
|
759
|
+
if (type === "event") {
|
|
760
|
+
const datasetStart = dayjs.unix(meta.datasetStart);
|
|
708
761
|
// ── HOOK 2: POST-LAUNCH AI COACHING LIFT (event) ────
|
|
709
762
|
// After day 35, ai_assisted workouts get 1.2x duration.
|
|
710
763
|
if (record.event === "workout completed" || record.event === "workout planned") {
|
|
711
|
-
const AI_LAUNCH =
|
|
764
|
+
const AI_LAUNCH = datasetStart.add(35, "days");
|
|
712
765
|
const eventTime = dayjs(record.time);
|
|
713
766
|
if (eventTime.isAfter(AI_LAUNCH) && record.coaching_mode === "ai_assisted") {
|
|
714
767
|
if (record.duration_minutes) {
|
|
@@ -723,6 +776,7 @@ const config = {
|
|
|
723
776
|
|
|
724
777
|
// ── EVERYTHING HOOKS ─────────────────────────────────
|
|
725
778
|
if (type === "everything") {
|
|
779
|
+
const datasetStart = dayjs.unix(meta.datasetStart);
|
|
726
780
|
let events = record;
|
|
727
781
|
if (!events.length) return record;
|
|
728
782
|
|
|
@@ -736,16 +790,26 @@ const config = {
|
|
|
736
790
|
});
|
|
737
791
|
}
|
|
738
792
|
|
|
793
|
+
// HOOK 1: MORNING WORKOUT BOOST — 5AM-9AM UTC workouts get
|
|
794
|
+
// calories_burned 1.3x. No flag — analyst breaks down by HOD.
|
|
795
|
+
events.forEach(e => {
|
|
796
|
+
if (e.event === "workout completed") {
|
|
797
|
+
const hour = new Date(e.time).getUTCHours();
|
|
798
|
+
if (hour >= 5 && hour < 9 && e.calories_burned) {
|
|
799
|
+
e.calories_burned = Math.floor(e.calories_burned * 1.3);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
|
|
739
804
|
// ── HOOK 8: ANNUAL SUBSCRIBER CONVERSION FILTER ─
|
|
740
805
|
// Free/monthly-tier users drop ~30% of "progress checked"
|
|
741
806
|
// (last step of Workout Loop funnel) to simulate lower conversion.
|
|
807
|
+
// NOTE: subscription field is named `subscription_plan` (set by the
|
|
808
|
+
// subscription feature in user-loop.js), NOT `subscription_tier`.
|
|
742
809
|
if (meta && meta.profile) {
|
|
743
|
-
const
|
|
744
|
-
if (
|
|
745
|
-
record = record.filter(e =>
|
|
746
|
-
if (e.event === "progress checked" && chance.bool({ likelihood: 30 })) return false;
|
|
747
|
-
return true;
|
|
748
|
-
});
|
|
810
|
+
const plan = meta.profile.subscription_plan;
|
|
811
|
+
if (plan !== "annual" && plan !== "family" && chance.bool({ likelihood: 30 })) {
|
|
812
|
+
record = record.filter(e => e.event !== "progress checked");
|
|
749
813
|
events = record;
|
|
750
814
|
}
|
|
751
815
|
}
|
|
@@ -803,7 +867,7 @@ const config = {
|
|
|
803
867
|
// ── HOOK 5: RESOLVER CHURN CLIFF ─────────────────
|
|
804
868
|
// Resolver segment users with <8 events lose 70% after day 14.
|
|
805
869
|
if (meta && meta.profile && meta.profile.segment === "resolver" && events.length < 8) {
|
|
806
|
-
const CHURN_CLIFF =
|
|
870
|
+
const CHURN_CLIFF = datasetStart.add(14, "days");
|
|
807
871
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
808
872
|
const eventTime = dayjs(events[i].time);
|
|
809
873
|
if (eventTime.isAfter(CHURN_CLIFF) && chance.bool({ likelihood: 70 })) {
|
|
@@ -812,8 +876,7 @@ const config = {
|
|
|
812
876
|
}
|
|
813
877
|
}
|
|
814
878
|
|
|
815
|
-
//
|
|
816
|
-
// Users with coach_session events get higher satisfaction.
|
|
879
|
+
// HOOK 6: COACH SESSION QUALITY — coach-session satisfaction 4-5.
|
|
817
880
|
const hasCoachSessions = events.some(e => e.event === "coach session");
|
|
818
881
|
if (hasCoachSessions) {
|
|
819
882
|
events.forEach(e => {
|
|
@@ -823,6 +886,26 @@ const config = {
|
|
|
823
886
|
});
|
|
824
887
|
}
|
|
825
888
|
|
|
889
|
+
// HOOK 10: WORKOUT-COUNT MAGIC NUMBER (no flags)
|
|
890
|
+
// Sweet 12-20 workouts → +35% on workout duration_minutes (peak
|
|
891
|
+
// progression). Over 21+ → drop 30% of post-day-30 events
|
|
892
|
+
// (overtraining → churn).
|
|
893
|
+
const workoutCount = events.filter(e => e.event === "workout completed").length;
|
|
894
|
+
if (workoutCount >= 12 && workoutCount <= 20) {
|
|
895
|
+
events.forEach(e => {
|
|
896
|
+
if (e.event === "workout completed" && typeof e.duration_minutes === "number") {
|
|
897
|
+
e.duration_minutes = Math.round(e.duration_minutes * 1.35);
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
} else if (workoutCount >= 21) {
|
|
901
|
+
const day30 = datasetStart.add(30, "days");
|
|
902
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
903
|
+
if (dayjs(events[i].time).isAfter(day30) && chance.bool({ likelihood: 30 })) {
|
|
904
|
+
events.splice(i, 1);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
826
909
|
return record;
|
|
827
910
|
}
|
|
828
911
|
|