@ak--47/dungeon-master 1.1.0 → 1.2.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.
Files changed (67) hide show
  1. package/dungeons/technical/ad-spend-schema.json +2 -2
  2. package/dungeons/technical/ad-spend.js +1 -1
  3. package/dungeons/technical/anonymous-users-schema.json +4 -3
  4. package/dungeons/technical/anonymous-users.js +1 -1
  5. package/dungeons/technical/array-of-object-lookup-schema.json +1 -1
  6. package/dungeons/technical/array-of-object-lookup.js +1 -1
  7. package/dungeons/technical/experiments-schema.json +25 -19
  8. package/dungeons/technical/experiments.js +1 -1
  9. package/dungeons/technical/foobar.js +1 -1
  10. package/dungeons/technical/group-analytics-schema.json +92 -0
  11. package/dungeons/technical/group-analytics.js +1 -1
  12. package/dungeons/technical/mirror-strategies-schema.json +4 -4
  13. package/dungeons/technical/mirror-strategies.js +1 -1
  14. package/dungeons/technical/nested-objects.js +1 -1
  15. package/dungeons/technical/retention-cadence.js +1 -2
  16. package/dungeons/technical/sanity-schema.json +22 -22
  17. package/dungeons/technical/sanity.js +1 -0
  18. package/dungeons/technical/scale-test.js +1 -1
  19. package/dungeons/technical/scd-schema.json +230 -33
  20. package/dungeons/technical/scd.js +1 -0
  21. package/dungeons/technical/simple-schema.json +132 -48
  22. package/dungeons/technical/simple.js +1 -1
  23. package/dungeons/technical/simplest-schema.json +168 -79
  24. package/dungeons/technical/simplest.js +1 -1
  25. package/dungeons/technical/text-generation-schema.json +7 -4
  26. package/dungeons/technical/text-generation.js +1 -2
  27. package/dungeons/vertical/community-schema.json +71 -49
  28. package/dungeons/vertical/community.js +8 -2
  29. package/dungeons/vertical/devtools-schema.json +69 -48
  30. package/dungeons/vertical/devtools.js +8 -2
  31. package/dungeons/vertical/ecommerce-schema.json +126 -108
  32. package/dungeons/vertical/ecommerce.js +9 -2
  33. package/dungeons/vertical/education-schema.json +5261 -272
  34. package/dungeons/vertical/education.js +16 -3
  35. package/dungeons/vertical/fintech-schema.json +165 -98
  36. package/dungeons/vertical/fintech.js +16 -3
  37. package/dungeons/vertical/fitness-schema.json +69 -47
  38. package/dungeons/vertical/fitness.js +8 -2
  39. package/dungeons/vertical/food-delivery-schema.json +36237 -187
  40. package/dungeons/vertical/food-delivery.js +16 -3
  41. package/dungeons/vertical/gaming-schema.json +103 -59
  42. package/dungeons/vertical/gaming.js +20 -9
  43. package/dungeons/vertical/healthcare-schema.json +70 -48
  44. package/dungeons/vertical/healthcare.js +8 -2
  45. package/dungeons/vertical/insurance-application-schema.json +66 -47
  46. package/dungeons/vertical/insurance-application.js +8 -2
  47. package/dungeons/vertical/logistics-schema.json +60 -38
  48. package/dungeons/vertical/logistics.js +8 -2
  49. package/dungeons/vertical/marketplace-schema.json +65 -43
  50. package/dungeons/vertical/marketplace.js +8 -2
  51. package/dungeons/vertical/media-schema.json +4085 -123
  52. package/dungeons/vertical/media.js +9 -3
  53. package/dungeons/vertical/rpg-schema.json +1984 -147
  54. package/dungeons/vertical/rpg.js +9 -3
  55. package/dungeons/vertical/sass-schema.json +2622 -147
  56. package/dungeons/vertical/sass.js +16 -3
  57. package/dungeons/vertical/social-schema.json +146 -78
  58. package/dungeons/vertical/social.js +16 -3
  59. package/dungeons/vertical/travel-schema.json +57 -35
  60. package/dungeons/vertical/travel.js +8 -2
  61. package/index.js +1 -1
  62. package/lib/core/context.js +9 -0
  63. package/lib/core/storage.js +2 -0
  64. package/lib/orchestrators/user-loop.js +4 -1
  65. package/package.json +1 -1
  66. package/scripts/extract-dungeon-schema.mjs +64 -18
  67. package/types.d.ts +3 -0
@@ -10,7 +10,7 @@ const chance = u.initChance(SEED);
10
10
  const num_users = 5_000;
11
11
  const days = 100;
12
12
 
13
- /** @typedef {import("../types.js").Dungeon} Config */
13
+ /** @typedef {import("../../types").Dungeon} Config */
14
14
 
15
15
  /*
16
16
  * ═══════════════════════════════════════════════════════════════════════════════
@@ -268,10 +268,23 @@ const config = {
268
268
  hasAdSpend: false,
269
269
  percentUsersBornInDataset: 50,
270
270
  hasAvatar: true,
271
- batchSize: 2_500_000,
272
271
  concurrency: 1,
273
272
  writeToDisk: false,
274
- scdProps: {},
273
+ scdProps: {
274
+ primary_role: {
275
+ values: ["viewer", "editor", "admin", "owner"],
276
+ frequency: "month",
277
+ timing: "fuzzy",
278
+ max: 6
279
+ },
280
+ plan_tier: {
281
+ values: ["starter", "growth", "enterprise", "scale"],
282
+ frequency: "month",
283
+ timing: "fixed",
284
+ max: 6,
285
+ type: "company_id"
286
+ }
287
+ },
275
288
 
276
289
  funnels: [
277
290
  {
@@ -38,9 +38,10 @@
38
38
  241
39
39
  ]
40
40
  },
41
- "has_media": {
42
- "$type": "array"
43
- },
41
+ "has_media": [
42
+ false,
43
+ true
44
+ ],
44
45
  "hashtag_count": {
45
46
  "$range": [
46
47
  1,
@@ -206,14 +207,15 @@
206
207
  "text"
207
208
  ],
208
209
  "view_duration_sec": [
209
- 11,
210
- 20,
211
- 23,
212
- 13
210
+ 14,
211
+ 9,
212
+ 25,
213
+ 20
214
+ ],
215
+ "completed": [
216
+ false,
217
+ true
213
218
  ],
214
- "completed": {
215
- "$type": "array"
216
- },
217
219
  "toxic_user": [
218
220
  false
219
221
  ]
@@ -228,12 +230,14 @@
228
230
  "video",
229
231
  "text"
230
232
  ],
231
- "has_filter": {
232
- "$type": "array"
233
- },
234
- "has_sticker": {
235
- "$type": "array"
236
- },
233
+ "has_filter": [
234
+ true,
235
+ false
236
+ ],
237
+ "has_sticker": [
238
+ false,
239
+ true
240
+ ],
237
241
  "weekend_surge": [
238
242
  false
239
243
  ],
@@ -258,16 +262,15 @@
258
262
  "posts"
259
263
  ],
260
264
  "results_count": [
261
- 33,
262
- 40,
263
- 35,
264
- 28,
265
- 17,
266
- 36,
267
265
  37,
268
- 16,
266
+ 14,
267
+ 11,
268
+ 23,
269
+ 9,
270
+ 8,
269
271
  15,
270
- 34
272
+ 36,
273
+ 17
271
274
  ],
272
275
  "toxic_user": [
273
276
  false
@@ -285,9 +288,10 @@
285
288
  "mention",
286
289
  "trending"
287
290
  ],
288
- "clicked": {
289
- "$type": "array"
290
- },
291
+ "clicked": [
292
+ false,
293
+ true
294
+ ],
291
295
  "toxic_user": [
292
296
  false
293
297
  ]
@@ -305,8 +309,8 @@
305
309
  ],
306
310
  "conversation_length": {
307
311
  "$range": [
308
- 3,
309
- 98
312
+ 4,
313
+ 93
310
314
  ]
311
315
  },
312
316
  "toxic_user": [
@@ -411,8 +415,8 @@
411
415
  "vip"
412
416
  ],
413
417
  "price_usd": [
414
- 9.99,
415
418
  4.99,
419
+ 9.99,
416
420
  19.99
417
421
  ],
418
422
  "toxic_user": [
@@ -421,53 +425,6 @@
421
425
  }
422
426
  }
423
427
  ],
424
- "superProps": {
425
- "app_version": [
426
- "4.0",
427
- "4.1",
428
- "4.2",
429
- "4.3",
430
- "5.0"
431
- ],
432
- "account_type": [
433
- "personal",
434
- "creator",
435
- "business"
436
- ]
437
- },
438
- "userProps": {
439
- "follower_count": {
440
- "$range": [
441
- 2283,
442
- 7639
443
- ]
444
- },
445
- "following_count": {
446
- "$range": [
447
- 869,
448
- 3942
449
- ]
450
- },
451
- "bio_length": {
452
- "$range": [
453
- 2,
454
- 132
455
- ]
456
- },
457
- "verified": {
458
- "$type": "array"
459
- },
460
- "content_niche": [
461
- "lifestyle",
462
- "tech",
463
- "food",
464
- "fitness",
465
- "travel",
466
- "comedy",
467
- "news",
468
- "art"
469
- ]
470
- },
471
428
  "funnels": [
472
429
  {
473
430
  "sequence": [
@@ -548,5 +505,116 @@
548
505
  "conversionRate": 20,
549
506
  "timeToConvert": 2
550
507
  }
551
- ]
508
+ ],
509
+ "superProps": {
510
+ "app_version": [
511
+ "4.0",
512
+ "4.1",
513
+ "4.2",
514
+ "4.3",
515
+ "5.0"
516
+ ],
517
+ "account_type": [
518
+ "personal",
519
+ "creator",
520
+ "business"
521
+ ]
522
+ },
523
+ "userProps": {
524
+ "follower_count": {
525
+ "$range": [
526
+ 2075,
527
+ 7782
528
+ ]
529
+ },
530
+ "following_count": {
531
+ "$range": [
532
+ 967,
533
+ 4229
534
+ ]
535
+ },
536
+ "bio_length": {
537
+ "$range": [
538
+ 10,
539
+ 149
540
+ ]
541
+ },
542
+ "verified": [
543
+ false,
544
+ true
545
+ ],
546
+ "content_niche": [
547
+ "lifestyle",
548
+ "tech",
549
+ "food",
550
+ "fitness",
551
+ "travel",
552
+ "comedy",
553
+ "news",
554
+ "art"
555
+ ]
556
+ },
557
+ "groupKeys": [
558
+ {
559
+ "key": "community_id",
560
+ "count": 100,
561
+ "affectsEvents": [
562
+ "post created",
563
+ "comment posted",
564
+ "post liked",
565
+ "post shared"
566
+ ]
567
+ }
568
+ ],
569
+ "groupProps": {
570
+ "community_id": {
571
+ "name": {
572
+ "$type": "string"
573
+ },
574
+ "member_count": {
575
+ "$range": [
576
+ 850,
577
+ 4126
578
+ ]
579
+ },
580
+ "category": [
581
+ "technology",
582
+ "entertainment",
583
+ "sports",
584
+ "politics",
585
+ "art",
586
+ "science"
587
+ ],
588
+ "is_moderated": [
589
+ false,
590
+ true
591
+ ]
592
+ }
593
+ },
594
+ "scdProps": {
595
+ "account_type": {
596
+ "type": "user",
597
+ "frequency": "month",
598
+ "timing": "fuzzy",
599
+ "max": 6,
600
+ "values": [
601
+ "personal",
602
+ "creator",
603
+ "business",
604
+ "verified"
605
+ ]
606
+ },
607
+ "community_status": {
608
+ "type": "community_id",
609
+ "frequency": "month",
610
+ "timing": "fixed",
611
+ "max": 6,
612
+ "values": [
613
+ "new",
614
+ "growing",
615
+ "established",
616
+ "featured"
617
+ ]
618
+ }
619
+ }
552
620
  }
@@ -10,7 +10,7 @@ const chance = u.initChance(SEED);
10
10
  const num_users = 5_000;
11
11
  const days = 100;
12
12
 
13
- /** @typedef {import("../types.js").Dungeon} Config */
13
+ /** @typedef {import("../../types").Dungeon} Config */
14
14
 
15
15
  /*
16
16
  * =====================================================================================
@@ -182,10 +182,23 @@ const config = {
182
182
  hasAdSpend: false,
183
183
  percentUsersBornInDataset: 50,
184
184
  hasAvatar: true,
185
- batchSize: 2_500_000,
186
185
  concurrency: 1,
187
186
  writeToDisk: false,
188
- scdProps: {},
187
+ scdProps: {
188
+ account_type: {
189
+ values: ["personal", "creator", "business", "verified"],
190
+ frequency: "month",
191
+ timing: "fuzzy",
192
+ max: 6
193
+ },
194
+ community_status: {
195
+ values: ["new", "growing", "established", "featured"],
196
+ frequency: "month",
197
+ timing: "fixed",
198
+ max: 6,
199
+ type: "community_id"
200
+ }
201
+ },
189
202
 
190
203
  funnels: [
191
204
  {
@@ -454,6 +454,9 @@
454
454
  },
455
455
  {
456
456
  "event": "account deactivated",
457
+ "isChurnEvent": true,
458
+ "returnLikelihood": 0.2,
459
+ "isStrictEvent": true,
457
460
  "properties": {
458
461
  "reason": [
459
462
  "found_alternative",
@@ -465,40 +468,6 @@
465
468
  }
466
469
  }
467
470
  ],
468
- "superProps": {
469
- "platform": [
470
- "ios",
471
- "android",
472
- "web"
473
- ],
474
- "membership_tier": [
475
- "standard",
476
- "gold",
477
- "platinum"
478
- ]
479
- },
480
- "userProps": {
481
- "customer_segment": [
482
- "leisure_family"
483
- ],
484
- "travel_frequency": [
485
- "occasional",
486
- "monthly",
487
- "weekly"
488
- ],
489
- "company_name": [
490
- "none"
491
- ],
492
- "preferred_destination": {
493
- "$type": "string"
494
- },
495
- "avg_budget_per_night": {
496
- "$range": [
497
- 98,
498
- 339
499
- ]
500
- }
501
- },
502
471
  "funnels": [
503
472
  {
504
473
  "sequence": [
@@ -507,6 +476,7 @@
507
476
  "hotel viewed",
508
477
  "booking completed"
509
478
  ],
479
+ "name": "Onboarding to First Booking",
510
480
  "isFirstFunnel": true,
511
481
  "conversionRate": 35,
512
482
  "timeToConvert": 72,
@@ -519,6 +489,7 @@
519
489
  "price compared",
520
490
  "booking completed"
521
491
  ],
492
+ "name": "Search to Book",
522
493
  "conversionRate": 25,
523
494
  "timeToConvert": 48,
524
495
  "weight": 5
@@ -530,6 +501,7 @@
530
501
  "amenity used",
531
502
  "review submitted"
532
503
  ],
504
+ "name": "Full Stay Journey",
533
505
  "conversionRate": 30,
534
506
  "timeToConvert": 336,
535
507
  "weight": 3
@@ -540,6 +512,7 @@
540
512
  "loyalty points redeemed",
541
513
  "review submitted"
542
514
  ],
515
+ "name": "Loyalty Engagement",
543
516
  "conversionRate": 15,
544
517
  "timeToConvert": 720,
545
518
  "weight": 2
@@ -550,9 +523,58 @@
550
523
  "booking completed",
551
524
  "room upgrade selected"
552
525
  ],
526
+ "name": "Upsell Path",
553
527
  "conversionRate": 20,
554
528
  "timeToConvert": 24,
555
529
  "weight": 2
556
530
  }
557
- ]
531
+ ],
532
+ "superProps": {
533
+ "platform": [
534
+ "ios",
535
+ "android",
536
+ "web"
537
+ ],
538
+ "membership_tier": [
539
+ "standard",
540
+ "gold",
541
+ "platinum"
542
+ ]
543
+ },
544
+ "userProps": {
545
+ "customer_segment": [
546
+ "leisure_family"
547
+ ],
548
+ "travel_frequency": [
549
+ "occasional",
550
+ "monthly",
551
+ "weekly"
552
+ ],
553
+ "company_name": [
554
+ "none"
555
+ ],
556
+ "preferred_destination": {
557
+ "$type": "string"
558
+ },
559
+ "avg_budget_per_night": {
560
+ "$range": [
561
+ 98,
562
+ 339
563
+ ]
564
+ }
565
+ },
566
+ "scdProps": {
567
+ "membership_tier": {
568
+ "type": "user",
569
+ "frequency": "month",
570
+ "timing": "fuzzy",
571
+ "max": 8,
572
+ "values": [
573
+ "member",
574
+ "silver",
575
+ "gold",
576
+ "platinum"
577
+ ]
578
+ }
579
+ }
558
580
  }
@@ -217,10 +217,16 @@ const config = {
217
217
  hasAdSpend: false,
218
218
  percentUsersBornInDataset: 35,
219
219
  hasAvatar: true,
220
- batchSize: 2_500_000,
221
220
  concurrency: 1,
222
221
  writeToDisk: false,
223
- scdProps: {},
222
+ scdProps: {
223
+ membership_tier: {
224
+ values: ["member", "silver", "gold", "platinum"],
225
+ frequency: "month",
226
+ timing: "fuzzy",
227
+ max: 8
228
+ }
229
+ },
224
230
  mirrorProps: {},
225
231
  lookupTables: [],
226
232
 
package/index.js CHANGED
@@ -216,7 +216,7 @@ async function runDungeon(config) {
216
216
  files: await extractFileInfo(storage, validatedConfig),
217
217
  time: { start, end, delta, human },
218
218
  operations: context.getOperations(),
219
- eventCount: context.getEventCount(),
219
+ eventCount: context.getStoredEventCount(),
220
220
  userCount: context.getUserCount()
221
221
  };
222
222
 
@@ -71,6 +71,7 @@ function createRuntimeState() {
71
71
  return {
72
72
  operations: 0,
73
73
  eventCount: 0,
74
+ storedEventCount: 0,
74
75
  userCount: 0,
75
76
  isBatchMode: false,
76
77
  verbose: false
@@ -143,6 +144,14 @@ export function createContext(config, storage = null, timeConstants = {}) {
143
144
  runtime.eventCount++;
144
145
  },
145
146
 
147
+ incrementStoredEvents(count = 1) {
148
+ runtime.storedEventCount += count;
149
+ },
150
+
151
+ getStoredEventCount() {
152
+ return runtime.storedEventCount;
153
+ },
154
+
146
155
  isBatchMode() {
147
156
  return runtime.isBatchMode;
148
157
  },
@@ -99,8 +99,10 @@ export async function createHookArray(arr = [], opts) {
99
99
  // Fast path for passthrough hooks - no transformation needed
100
100
  if (Array.isArray(item)) {
101
101
  arr.push(...item);
102
+ if (type === "event" && context.incrementStoredEvents) context.incrementStoredEvents(item.length);
102
103
  } else {
103
104
  arr.push(item);
105
+ if (type === "event" && context.incrementStoredEvents) context.incrementStoredEvents(1);
104
106
  }
105
107
  } else {
106
108
  // Slow path for actual transformation hooks
@@ -397,7 +397,10 @@ export async function userLoop(context) {
397
397
  // Subscription events (trial, upgrade, cancel) must not be randomly dropped by decay
398
398
  const userDecay = persona?.engagementDecay || globalEngagementDecay;
399
399
  if (userDecay && userDecay.model !== 'none' && usersEvents.length > 0) {
400
- usersEvents = applyEngagementDecay(usersEvents, userDecay, adjustedCreated, context, chance);
400
+ // adjustedCreated is in FIXED time space, but ev.time is in PRESENT time (shifted).
401
+ // Shift adjustedCreated to present so daysSinceBirth reflects within-dataset age.
402
+ const adjustedCreatedPresent = adjustedCreated.add(context.TIME_SHIFT_SECONDS, 'seconds');
403
+ usersEvents = applyEngagementDecay(usersEvents, userDecay, adjustedCreatedPresent, context, chance);
401
404
  }
402
405
 
403
406
  // Feature 5: Subscription lifecycle — inject after decay (exempt from decay filtering)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ak--47/dungeon-master",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "generate fancy datasets",
5
5
  "type": "module",
6
6
  "main": "index.js",