@ak--47/dungeon-master 1.2.2 → 1.3.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 +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 -2
- 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 +2 -2
- package/dungeons/technical/simplest.js +2 -2
- package/dungeons/technical/text-generation.js +2 -2
- package/dungeons/vertical/ai-platform-schema.json +617 -0
- package/dungeons/vertical/ai-platform.js +799 -0
- package/dungeons/vertical/community.js +40 -26
- package/dungeons/vertical/crypto-schema.json +546 -0
- package/dungeons/vertical/crypto.js +721 -0
- package/dungeons/vertical/dating-schema.json +401 -0
- package/dungeons/vertical/dating.js +798 -0
- package/dungeons/vertical/devtools.js +13 -9
- package/dungeons/vertical/ecommerce.js +2 -3
- package/dungeons/vertical/education.js +4 -5
- package/dungeons/vertical/fintech.js +32 -29
- package/dungeons/vertical/fitness.js +2 -3
- package/dungeons/vertical/food-delivery.js +37 -43
- package/dungeons/vertical/gaming-schema.json +2495 -230
- package/dungeons/vertical/gaming.js +771 -388
- package/dungeons/vertical/healthcare.js +2 -3
- package/dungeons/vertical/insurance-application.js +2 -3
- package/dungeons/vertical/logistics.js +20 -14
- package/dungeons/vertical/marketplace.js +22 -14
- package/dungeons/vertical/media.js +39 -30
- package/dungeons/vertical/real-estate-schema.json +527 -0
- package/dungeons/vertical/real-estate.js +774 -0
- package/dungeons/vertical/sass.js +2 -3
- package/dungeons/vertical/social.js +15 -13
- package/dungeons/vertical/travel.js +59 -26
- package/lib/core/config-validator.js +71 -15
- package/lib/core/storage.js +14 -4
- package/lib/orchestrators/user-loop.js +39 -5
- package/lib/templates/macro-presets.js +111 -0
- package/lib/templates/soup-presets.js +19 -36
- package/package.json +8 -2
- package/types.d.ts +219 -42
- package/dungeons/user/.gitkeep +0 -0
- package/dungeons/vertical/rpg-schema.json +0 -2491
- package/dungeons/vertical/rpg.js +0 -976
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const SEED = "dm4-healthcare";
|
|
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 ──
|
|
@@ -247,7 +247,7 @@ const config = {
|
|
|
247
247
|
token,
|
|
248
248
|
seed: SEED,
|
|
249
249
|
numDays: num_days,
|
|
250
|
-
|
|
250
|
+
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
251
251
|
numUsers: num_users,
|
|
252
252
|
hasAnonIds: false,
|
|
253
253
|
hasSessionIds: true,
|
|
@@ -262,7 +262,6 @@ const config = {
|
|
|
262
262
|
hasCampaigns: false,
|
|
263
263
|
isAnonymous: false,
|
|
264
264
|
hasAdSpend: false,
|
|
265
|
-
percentUsersBornInDataset: 35,
|
|
266
265
|
hasAvatar: true,
|
|
267
266
|
concurrency: 1,
|
|
268
267
|
writeToDisk: false,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const SEED = "dm4-insurance";
|
|
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 ──
|
|
@@ -143,7 +143,7 @@ const config = {
|
|
|
143
143
|
token,
|
|
144
144
|
seed: SEED,
|
|
145
145
|
numDays: num_days,
|
|
146
|
-
|
|
146
|
+
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
147
147
|
numUsers: num_users,
|
|
148
148
|
hasAnonIds: false,
|
|
149
149
|
hasSessionIds: true,
|
|
@@ -158,7 +158,6 @@ const config = {
|
|
|
158
158
|
hasCampaigns: false,
|
|
159
159
|
isAnonymous: false,
|
|
160
160
|
hasAdSpend: false,
|
|
161
|
-
percentUsersBornInDataset: 35,
|
|
162
161
|
hasAvatar: true,
|
|
163
162
|
concurrency: 1,
|
|
164
163
|
writeToDisk: false,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const SEED = "dm4-logistics";
|
|
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 ──
|
|
@@ -264,7 +264,7 @@ const config = {
|
|
|
264
264
|
token,
|
|
265
265
|
seed: SEED,
|
|
266
266
|
numDays: num_days,
|
|
267
|
-
|
|
267
|
+
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
268
268
|
numUsers: num_users,
|
|
269
269
|
hasAnonIds: false,
|
|
270
270
|
hasSessionIds: true,
|
|
@@ -279,7 +279,6 @@ const config = {
|
|
|
279
279
|
hasCampaigns: false,
|
|
280
280
|
isAnonymous: false,
|
|
281
281
|
hasAdSpend: false,
|
|
282
|
-
percentUsersBornInDataset: 35,
|
|
283
282
|
hasAvatar: true,
|
|
284
283
|
concurrency: 1,
|
|
285
284
|
writeToDisk: false,
|
|
@@ -713,18 +712,13 @@ const config = {
|
|
|
713
712
|
// no-op: conversion differentiation handled via event filtering below
|
|
714
713
|
}
|
|
715
714
|
|
|
716
|
-
// -- HOOK 1: MONTH-END REPORTING SURGE
|
|
717
|
-
//
|
|
718
|
-
|
|
719
|
-
if (record.event === "report generated") {
|
|
720
|
-
const dayOfMonth = dayjs(record.time).date();
|
|
721
|
-
if (dayOfMonth >= 28) {
|
|
722
|
-
record.report_pages = Math.floor((record.report_pages || 20) * 2);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
715
|
+
// -- HOOK 1: MONTH-END REPORTING SURGE ------------------------
|
|
716
|
+
// Moved to everything hook (after sessionization) so day-of-month
|
|
717
|
+
// tags match final timestamps. See everything hook below.
|
|
725
718
|
|
|
726
|
-
|
|
727
|
-
|
|
719
|
+
// -- HOOK 2: RUSH ORDER PREMIUM (event) -------------------
|
|
720
|
+
// Urgent purchase orders get 1.5x unit_cost.
|
|
721
|
+
if (type === "event") {
|
|
728
722
|
if (record.event === "purchase order created" && record.priority === "urgent") {
|
|
729
723
|
record.unit_cost = Math.floor((record.unit_cost || 50) * 1.5);
|
|
730
724
|
}
|
|
@@ -746,6 +740,18 @@ const config = {
|
|
|
746
740
|
});
|
|
747
741
|
}
|
|
748
742
|
|
|
743
|
+
// -- HOOK 1: MONTH-END REPORTING SURGE --------------------
|
|
744
|
+
// Reports on days 28-31 get 2x report_pages.
|
|
745
|
+
// Runs after sessionization so day-of-month matches final timestamps.
|
|
746
|
+
for (const e of record) {
|
|
747
|
+
if (e.event === 'report generated') {
|
|
748
|
+
const dayOfMonth = new Date(e.time).getUTCDate();
|
|
749
|
+
if (dayOfMonth >= 28) {
|
|
750
|
+
e.report_pages = Math.floor((e.report_pages || 20) * 2);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
749
755
|
// -- HOOK 8: SMALL-BUSINESS CONVERSION DROP ---------------
|
|
750
756
|
// Small-business users lose ~35% of "alert configured" events
|
|
751
757
|
// (last step of Integration Setup funnel), simulating lower
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const SEED = "dm4-marketplace";
|
|
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 ──
|
|
@@ -259,7 +259,7 @@ const config = {
|
|
|
259
259
|
token,
|
|
260
260
|
seed: SEED,
|
|
261
261
|
numDays: num_days,
|
|
262
|
-
|
|
262
|
+
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
263
263
|
numUsers: num_users,
|
|
264
264
|
hasAnonIds: false,
|
|
265
265
|
hasSessionIds: true,
|
|
@@ -274,7 +274,6 @@ const config = {
|
|
|
274
274
|
hasCampaigns: false,
|
|
275
275
|
isAnonymous: false,
|
|
276
276
|
hasAdSpend: false,
|
|
277
|
-
percentUsersBornInDataset: 35,
|
|
278
277
|
hasAvatar: true,
|
|
279
278
|
concurrency: 1,
|
|
280
279
|
writeToDisk: false,
|
|
@@ -747,15 +746,9 @@ const config = {
|
|
|
747
746
|
}
|
|
748
747
|
}
|
|
749
748
|
|
|
750
|
-
// ── HOOK 2: WEEKEND SHOPPING SURGE
|
|
751
|
-
//
|
|
752
|
-
|
|
753
|
-
const dayOfWeek = dayjs(record.time).day();
|
|
754
|
-
// Saturday=6, Sunday=0
|
|
755
|
-
if (dayOfWeek === 0 || dayOfWeek === 6) {
|
|
756
|
-
record.total_amount = Math.floor((record.total_amount || 60) * 1.2);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
749
|
+
// ── HOOK 2: WEEKEND SHOPPING SURGE ───────────────
|
|
750
|
+
// Moved to the everything hook (after purchase cloning)
|
|
751
|
+
// so the 1.2x boost applies to both original AND cloned purchases.
|
|
759
752
|
}
|
|
760
753
|
|
|
761
754
|
// ── EVERYTHING HOOKS ─────────────────────────────────
|
|
@@ -831,11 +824,13 @@ const config = {
|
|
|
831
824
|
}
|
|
832
825
|
|
|
833
826
|
// ── HOOK 5: RESPONSE TIME → CONVERSION ───────────
|
|
834
|
-
// Sellers with avg response_time <
|
|
827
|
+
// Sellers with avg response_time < 12 hours get more offer_accepted.
|
|
828
|
+
// (response_time_hours centers around ~6h via weighNumRange, so a
|
|
829
|
+
// threshold of 2h was too tight — almost no users qualified.)
|
|
835
830
|
const messages = events.filter(e => e.event === "message sent" && e.response_time_hours);
|
|
836
831
|
if (messages.length > 0) {
|
|
837
832
|
const avgResponseTime = messages.reduce((sum, m) => sum + m.response_time_hours, 0) / messages.length;
|
|
838
|
-
if (avgResponseTime <
|
|
833
|
+
if (avgResponseTime < 12) {
|
|
839
834
|
const templateOffer = events.find(e => e.event === "offer accepted");
|
|
840
835
|
if (templateOffer) {
|
|
841
836
|
const offers = events.filter(e => e.event === "offer received");
|
|
@@ -865,6 +860,19 @@ const config = {
|
|
|
865
860
|
}
|
|
866
861
|
}
|
|
867
862
|
|
|
863
|
+
// ── HOOK 2: WEEKEND SHOPPING SURGE (everything) ─────
|
|
864
|
+
// Applied AFTER all purchase cloning (Hooks 3, 4) so the
|
|
865
|
+
// 1.2x boost hits both original and injected purchases.
|
|
866
|
+
events.forEach(e => {
|
|
867
|
+
if (e.event === "purchase completed") {
|
|
868
|
+
const dow = new Date(e.time).getUTCDay();
|
|
869
|
+
// Saturday=6, Sunday=0
|
|
870
|
+
if (dow === 0 || dow === 6) {
|
|
871
|
+
e.total_amount = Math.floor((e.total_amount || 60) * 1.2);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
|
|
868
876
|
return record;
|
|
869
877
|
}
|
|
870
878
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const SEED = "harness-media";
|
|
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 ──
|
|
@@ -228,7 +228,7 @@ const config = {
|
|
|
228
228
|
token,
|
|
229
229
|
seed: SEED,
|
|
230
230
|
numDays: num_days,
|
|
231
|
-
|
|
231
|
+
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
232
232
|
numUsers: num_users,
|
|
233
233
|
hasAnonIds: false,
|
|
234
234
|
hasSessionIds: true,
|
|
@@ -243,7 +243,6 @@ const config = {
|
|
|
243
243
|
hasCampaigns: false,
|
|
244
244
|
isAnonymous: false,
|
|
245
245
|
hasAdSpend: false,
|
|
246
|
-
percentUsersBornInDataset: 50,
|
|
247
246
|
hasAvatar: true,
|
|
248
247
|
concurrency: 1,
|
|
249
248
|
writeToDisk: false,
|
|
@@ -637,38 +636,23 @@ const config = {
|
|
|
637
636
|
}
|
|
638
637
|
|
|
639
638
|
// ─────────────────────────────────────────────────────────────
|
|
640
|
-
// Hook #3: WEEKEND vs WEEKDAY PATTERNS
|
|
641
|
-
//
|
|
639
|
+
// Hook #3: WEEKEND vs WEEKDAY PATTERNS
|
|
640
|
+
// Moved to everything hook (after sessionization) so DOW/HOD
|
|
641
|
+
// tags match final timestamps. See everything hook below.
|
|
642
642
|
// ─────────────────────────────────────────────────────────────
|
|
643
|
-
if (type === "event") {
|
|
644
|
-
const EVENT_TIME = dayjs(record.time);
|
|
645
|
-
const dayOfWeek = EVENT_TIME.day(); // 0 = Sunday, 6 = Saturday
|
|
646
|
-
const hour = EVENT_TIME.hour();
|
|
647
|
-
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
|
|
648
|
-
|
|
649
|
-
if (isWeekend) {
|
|
650
|
-
record.weekend_viewing = true;
|
|
651
|
-
record.prime_time = false;
|
|
652
|
-
if (record.event === "playback completed" && record.watch_duration_min) {
|
|
653
|
-
record.watch_duration_min = Math.round(record.watch_duration_min * 1.5);
|
|
654
|
-
}
|
|
655
|
-
} else {
|
|
656
|
-
record.weekend_viewing = false;
|
|
657
|
-
// Weekday prime-time: 6PM to 11PM
|
|
658
|
-
if (hour >= 18 && hour <= 23) {
|
|
659
|
-
record.prime_time = true;
|
|
660
|
-
} else {
|
|
661
|
-
record.prime_time = false;
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
643
|
|
|
644
|
+
if (type === "event") {
|
|
665
645
|
// ─────────────────────────────────────────────────────────────
|
|
666
646
|
// Hook #5: NEW RELEASE SPIKE (event)
|
|
667
|
-
//
|
|
647
|
+
// Days 50-65: blockbuster release drives content selection.
|
|
648
|
+
// Bounded window concentrates the spike instead of spreading
|
|
649
|
+
// it across the entire second half of the dataset.
|
|
668
650
|
// ─────────────────────────────────────────────────────────────
|
|
669
|
-
const
|
|
651
|
+
const BLOCKBUSTER_START = DATASET_START.add(50, 'days');
|
|
652
|
+
const BLOCKBUSTER_END = DATASET_START.add(65, 'days');
|
|
653
|
+
const EVENT_TIME = dayjs(record.time);
|
|
670
654
|
if (record.event === "content selected" || record.event === "playback started") {
|
|
671
|
-
if (EVENT_TIME.isAfter(
|
|
655
|
+
if (EVENT_TIME.isAfter(BLOCKBUSTER_START) && EVENT_TIME.isBefore(BLOCKBUSTER_END) && chance.bool({ likelihood: 20 })) {
|
|
672
656
|
record.content_type = "movie";
|
|
673
657
|
record.content_id = blockbusterId;
|
|
674
658
|
record.blockbuster_release = true;
|
|
@@ -678,7 +662,7 @@ const config = {
|
|
|
678
662
|
}
|
|
679
663
|
|
|
680
664
|
if (record.event === "content rated") {
|
|
681
|
-
if (EVENT_TIME.isAfter(
|
|
665
|
+
if (EVENT_TIME.isAfter(BLOCKBUSTER_START) && EVENT_TIME.isBefore(BLOCKBUSTER_END) && chance.bool({ likelihood: 20 })) {
|
|
682
666
|
record.rating = chance.integer({ min: 4, max: 5 });
|
|
683
667
|
record.content_id = blockbusterId;
|
|
684
668
|
record.blockbuster_release = true;
|
|
@@ -727,6 +711,31 @@ const config = {
|
|
|
727
711
|
});
|
|
728
712
|
}
|
|
729
713
|
|
|
714
|
+
// ─── Hook #3: WEEKEND vs WEEKDAY PATTERNS ───
|
|
715
|
+
// Weekend: 1.5x watch duration. Weekday 6PM-11PM: prime_time tag.
|
|
716
|
+
// Runs after sessionization so DOW/HOD tags match final timestamps.
|
|
717
|
+
for (const e of userEvents) {
|
|
718
|
+
const eventDate = new Date(e.time);
|
|
719
|
+
const dayOfWeek = eventDate.getUTCDay(); // 0 = Sunday, 6 = Saturday
|
|
720
|
+
const hour = eventDate.getUTCHours();
|
|
721
|
+
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
|
|
722
|
+
|
|
723
|
+
if (isWeekend) {
|
|
724
|
+
e.weekend_viewing = true;
|
|
725
|
+
e.prime_time = false;
|
|
726
|
+
if (e.event === "playback completed" && e.watch_duration_min) {
|
|
727
|
+
e.watch_duration_min = Math.round(e.watch_duration_min * 1.5);
|
|
728
|
+
}
|
|
729
|
+
} else {
|
|
730
|
+
e.weekend_viewing = false;
|
|
731
|
+
if (hour >= 18 && hour <= 23) {
|
|
732
|
+
e.prime_time = true;
|
|
733
|
+
} else {
|
|
734
|
+
e.prime_time = false;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
730
739
|
// ─── Bug 2 fix: Genre funnel conversion filtering ───
|
|
731
740
|
// Drop ~25% of "playback completed" events for documentary genre
|
|
732
741
|
// to simulate lower documentary funnel completion (was conversionRate * 0.7)
|