@ak--47/dungeon-master 1.0.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 (104) hide show
  1. package/README.md +7 -7
  2. package/dungeons/technical/ad-spend-schema.json +128 -0
  3. package/dungeons/technical/ad-spend.js +116 -0
  4. package/dungeons/technical/anonymous-users-schema.json +92 -0
  5. package/dungeons/technical/anonymous-users.js +102 -0
  6. package/dungeons/technical/array-of-object-lookup-schema.json +191 -0
  7. package/dungeons/{array-of-object-lookup.js → technical/array-of-object-lookup.js} +12 -5
  8. package/dungeons/technical/experiments-schema.json +203 -0
  9. package/dungeons/technical/experiments.js +168 -0
  10. package/dungeons/technical/foobar-schema.json +362 -0
  11. package/dungeons/{foobar.js → technical/foobar.js} +3 -3
  12. package/dungeons/technical/group-analytics-schema.json +241 -0
  13. package/dungeons/technical/group-analytics.js +151 -0
  14. package/dungeons/technical/mirror-strategies-schema.json +84 -0
  15. package/dungeons/technical/mirror-strategies.js +126 -0
  16. package/dungeons/technical/nested-objects-schema.json +145 -0
  17. package/dungeons/technical/nested-objects.js +207 -0
  18. package/dungeons/technical/retention-cadence-schema.json +37 -0
  19. package/dungeons/{retention-cadence.js → technical/retention-cadence.js} +2 -3
  20. package/dungeons/technical/sanity-schema.json +185 -0
  21. package/dungeons/{sanity.js → technical/sanity.js} +4 -2
  22. package/dungeons/technical/scale-test-schema.json +70 -0
  23. package/dungeons/technical/scale-test.js +90 -0
  24. package/dungeons/technical/scd-schema.json +467 -0
  25. package/dungeons/{scd.js → technical/scd.js} +20 -10
  26. package/dungeons/technical/simple-schema.json +362 -0
  27. package/dungeons/{simple.js → technical/simple.js} +7 -7
  28. package/dungeons/technical/simplest-schema.json +724 -0
  29. package/dungeons/{simplest.js → technical/simplest.js} +7 -7
  30. package/dungeons/technical/text-generation-schema.json +1062 -0
  31. package/dungeons/{text-generation.js → technical/text-generation.js} +24 -11
  32. package/dungeons/vertical/community-schema.json +579 -0
  33. package/dungeons/vertical/community.js +794 -0
  34. package/dungeons/vertical/devtools-schema.json +601 -0
  35. package/dungeons/vertical/devtools.js +843 -0
  36. package/dungeons/vertical/ecommerce-schema.json +604 -0
  37. package/dungeons/{ecommerce.js → vertical/ecommerce.js} +43 -5
  38. package/dungeons/vertical/education-schema.json +5686 -0
  39. package/dungeons/{education.js → vertical/education.js} +70 -39
  40. package/dungeons/vertical/fintech-schema.json +630 -0
  41. package/dungeons/{fintech.js → vertical/fintech.js} +107 -56
  42. package/dungeons/vertical/fitness-schema.json +530 -0
  43. package/dungeons/vertical/fitness.js +808 -0
  44. package/dungeons/vertical/food-delivery-schema.json +36728 -0
  45. package/dungeons/{food.js → vertical/food-delivery.js} +67 -26
  46. package/dungeons/vertical/gaming-schema.json +438 -0
  47. package/dungeons/{gaming.js → vertical/gaming.js} +29 -16
  48. package/dungeons/vertical/healthcare-schema.json +549 -0
  49. package/dungeons/vertical/healthcare.js +775 -0
  50. package/dungeons/vertical/insurance-application-schema.json +485 -0
  51. package/dungeons/{insurance-application.js → vertical/insurance-application.js} +41 -31
  52. package/dungeons/vertical/logistics-schema.json +574 -0
  53. package/dungeons/vertical/logistics.js +799 -0
  54. package/dungeons/vertical/marketplace-schema.json +533 -0
  55. package/dungeons/vertical/marketplace.js +850 -0
  56. package/dungeons/vertical/media-schema.json +4749 -0
  57. package/dungeons/{media.js → vertical/media.js} +103 -19
  58. package/dungeons/vertical/rpg-schema.json +2491 -0
  59. package/dungeons/{rpg.js → vertical/rpg.js} +87 -60
  60. package/dungeons/vertical/sass-schema.json +3128 -0
  61. package/dungeons/{sass.js → vertical/sass.js} +65 -26
  62. package/dungeons/vertical/social-schema.json +620 -0
  63. package/dungeons/{social.js → vertical/social.js} +76 -17
  64. package/dungeons/vertical/travel-schema.json +580 -0
  65. package/dungeons/vertical/travel.js +742 -0
  66. package/index.js +20 -16
  67. package/lib/core/config-validator.js +286 -1
  68. package/lib/core/context.js +16 -5
  69. package/lib/core/storage.js +2 -0
  70. package/lib/generators/adspend.js +3 -3
  71. package/lib/generators/events.js +141 -14
  72. package/lib/generators/funnels.js +67 -7
  73. package/lib/generators/text.js +2 -2
  74. package/lib/orchestrators/user-loop.js +444 -22
  75. package/lib/templates/soup-presets.js +2 -2
  76. package/lib/utils/utils.js +4 -5
  77. package/package.json +4 -3
  78. package/scripts/dungeon-to-json.mjs +163 -0
  79. package/scripts/extract-dungeon-schema.mjs +343 -0
  80. package/scripts/json-to-dungeon.mjs +200 -0
  81. package/scripts/run-dungeon.mjs +76 -0
  82. package/scripts/run-many.mjs +118 -0
  83. package/scripts/verify-runner.mjs +42 -0
  84. package/types.d.ts +316 -1
  85. package/dungeons/array-of-object-lookup-schema.json +0 -327
  86. package/dungeons/ecommerce-schema.json +0 -462
  87. package/dungeons/education-schema.json +0 -2409
  88. package/dungeons/fintech-schema.json +0 -14034
  89. package/dungeons/foobar-schema.json +0 -403
  90. package/dungeons/food-delivery-schema.json +0 -192
  91. package/dungeons/food-delivery.js +0 -602
  92. package/dungeons/food-schema.json +0 -1152
  93. package/dungeons/gaming-schema.json +0 -1270
  94. package/dungeons/insurance-application-schema.json +0 -204
  95. package/dungeons/media-schema.json +0 -906
  96. package/dungeons/retention-cadence-schema.json +0 -78
  97. package/dungeons/rpg-schema.json +0 -4526
  98. package/dungeons/sanity-schema.json +0 -255
  99. package/dungeons/sass-schema.json +0 -1291
  100. package/dungeons/scd-schema.json +0 -919
  101. package/dungeons/simple-schema.json +0 -608
  102. package/dungeons/simplest-schema.json +0 -1418
  103. package/dungeons/social-schema.json +0 -1118
  104. package/dungeons/text-generation-schema.json +0 -3096
@@ -1,7 +1,7 @@
1
1
  import dayjs from "dayjs";
2
2
  import utc from "dayjs/plugin/utc.js";
3
3
  import "dotenv/config";
4
- import * as u from "../lib/utils/utils.js";
4
+ import * as u from "../../lib/utils/utils.js";
5
5
  import * as v from "ak-tools";
6
6
 
7
7
  const SEED = "harness-food";
@@ -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.d.ts").Dungeon} Config */
13
+ /** @typedef {import("../../types").Dungeon} Config */
14
14
 
15
15
  /*
16
16
  * ═══════════════════════════════════════════════════════════════════════════════
@@ -176,10 +176,23 @@ const config = {
176
176
  hasAdSpend: false,
177
177
  percentUsersBornInDataset: 50,
178
178
  hasAvatar: true,
179
- batchSize: 2_500_000,
180
179
  concurrency: 1,
181
180
  writeToDisk: false,
182
- scdProps: {},
181
+ scdProps: {
182
+ subscription_tier: {
183
+ values: ["free", "trial", "monthly", "annual"],
184
+ frequency: "month",
185
+ timing: "fuzzy",
186
+ max: 6
187
+ },
188
+ restaurant_tier: {
189
+ values: ["new", "verified", "featured", "premium"],
190
+ frequency: "month",
191
+ timing: "fixed",
192
+ max: 6,
193
+ type: "restaurant_id"
194
+ }
195
+ },
183
196
 
184
197
  funnels: [
185
198
  {
@@ -194,7 +207,7 @@ const config = {
194
207
  conversionRate: 55,
195
208
  timeToConvert: 1,
196
209
  weight: 5,
197
- props: { "restaurant_id": u.pickAWinner(restaurantIds) },
210
+ props: { "restaurant_id": restaurantIds },
198
211
  },
199
212
  {
200
213
  // Search-driven ordering
@@ -209,7 +222,7 @@ const config = {
209
222
  conversionRate: 65,
210
223
  timeToConvert: 2,
211
224
  weight: 4,
212
- props: { "order_id": u.pickAWinner(orderIds) },
225
+ props: { "order_id": orderIds },
213
226
  },
214
227
  {
215
228
  // Post-order: rate and reorder
@@ -248,7 +261,8 @@ const config = {
248
261
  isFirstEvent: true,
249
262
  properties: {
250
263
  "signup_method": ["email", "google", "apple", "facebook"],
251
- "referral_code": u.pickAWinner([true, false], 0.3),
264
+ "referral_code": [false, false, true],
265
+ "trial_retained": [false],
252
266
  }
253
267
  },
254
268
  {
@@ -266,14 +280,15 @@ const config = {
266
280
  "Mediterranean"
267
281
  ],
268
282
  "sort_by": ["recommended", "distance", "rating", "price"],
269
- "filter_applied": u.pickAWinner([true, false], 0.4),
283
+ "filter_applied": [false, false, false, true, true],
284
+ "trial_retained": [false],
270
285
  }
271
286
  },
272
287
  {
273
288
  event: "restaurant viewed",
274
289
  weight: 15,
275
290
  properties: {
276
- "restaurant_id": u.pickAWinner(restaurantIds),
291
+ "restaurant_id": restaurantIds,
277
292
  "cuisine_type": [
278
293
  "American",
279
294
  "Italian",
@@ -287,33 +302,40 @@ const config = {
287
302
  "avg_rating": u.weighNumRange(1, 5, 0.8, 30),
288
303
  "delivery_time_est_mins": u.weighNumRange(15, 90, 1.2, 40),
289
304
  "price_tier": ["$", "$$", "$$$", "$$$$"],
305
+ "late_night_order": [false],
306
+ "trial_retained": [false],
290
307
  }
291
308
  },
292
309
  {
293
310
  event: "item added to cart",
294
311
  weight: 14,
295
312
  properties: {
296
- "item_id": u.pickAWinner(itemIds),
313
+ "item_id": itemIds,
297
314
  "item_category": ["entree", "appetizer", "drink", "dessert", "side"],
298
315
  "item_price": u.weighNumRange(3, 65, 1.0, 40),
299
316
  "customization_count": u.weighNumRange(0, 5, 1.5, 20),
317
+ "late_night_order": [false],
318
+ "trial_retained": [false],
300
319
  }
301
320
  },
302
321
  {
303
322
  event: "item removed from cart",
304
323
  weight: 5,
305
324
  properties: {
306
- "item_id": u.pickAWinner(itemIds),
325
+ "item_id": itemIds,
307
326
  "removal_reason": ["changed_mind", "too_expensive", "substitution"],
327
+ "trial_retained": [false],
308
328
  }
309
329
  },
310
330
  {
311
331
  event: "coupon applied",
312
332
  weight: 4,
313
333
  properties: {
314
- "coupon_code": u.pickAWinner(couponCodes),
334
+ "coupon_code": couponCodes,
315
335
  "discount_type": ["percent", "flat", "free_delivery"],
316
336
  "discount_value": u.weighNumRange(5, 50, 1.2, 20),
337
+ "coupon_injected": [false],
338
+ "trial_retained": [false],
317
339
  }
318
340
  },
319
341
  {
@@ -322,46 +344,54 @@ const config = {
322
344
  properties: {
323
345
  "cart_total": u.weighNumRange(8, 150, 0.8, 40),
324
346
  "items_count": u.weighNumRange(1, 8, 1.2, 20),
325
- "delivery_address_saved": u.pickAWinner([true, false], 0.7),
347
+ "delivery_address_saved": [false, false, false, true, true, true, true, true, true, true],
348
+ "trial_retained": [false],
326
349
  }
327
350
  },
328
351
  {
329
352
  event: "order placed",
330
353
  weight: 10,
331
354
  properties: {
332
- "order_id": u.pickAWinner(orderIds),
355
+ "order_id": orderIds,
333
356
  "payment_method": ["credit_card", "apple_pay", "google_pay", "paypal", "cash"],
334
357
  "order_total": u.weighNumRange(10, 200, 0.8, 40),
335
358
  "tip_amount": u.weighNumRange(0, 30, 1.5, 20),
336
359
  "delivery_fee": u.weighNumRange(0, 12, 1.0, 20),
360
+ "surge_pricing": [false],
361
+ "rainy_week": [false],
362
+ "trial_retained": [false],
337
363
  }
338
364
  },
339
365
  {
340
366
  event: "order tracked",
341
367
  weight: 13,
342
368
  properties: {
343
- "order_id": u.pickAWinner(orderIds),
369
+ "order_id": orderIds,
344
370
  "order_status": ["confirmed", "preparing", "picked_up", "en_route", "delivered"],
345
371
  "eta_mins": u.weighNumRange(5, 60, 1.0, 30),
372
+ "trial_retained": [false],
346
373
  }
347
374
  },
348
375
  {
349
376
  event: "order delivered",
350
377
  weight: 9,
351
378
  properties: {
352
- "order_id": u.pickAWinner(orderIds),
379
+ "order_id": orderIds,
353
380
  "actual_delivery_mins": u.weighNumRange(12, 90, 1.0, 40),
354
- "on_time": u.pickAWinner([true, false], 0.7),
381
+ "on_time": [false, false, false, true, true, true, true, true, true, true],
382
+ "trial_retained": [false],
355
383
  }
356
384
  },
357
385
  {
358
386
  event: "order rated",
359
387
  weight: 7,
360
388
  properties: {
361
- "order_id": u.pickAWinner(orderIds),
389
+ "order_id": orderIds,
362
390
  "food_rating": u.weighNumRange(1, 5, 0.8, 30),
363
391
  "delivery_rating": u.weighNumRange(1, 5, 0.8, 30),
364
- "would_reorder": u.pickAWinner([true, false], 0.65),
392
+ "would_reorder": [false, true, true],
393
+ "referral_user": [false],
394
+ "trial_retained": [false],
365
395
  }
366
396
  },
367
397
  {
@@ -375,6 +405,7 @@ const config = {
375
405
  ]),
376
406
  "results_count": u.weighNumRange(0, 50, 0.8, 30),
377
407
  "search_type": ["restaurant", "cuisine", "dish"],
408
+ "trial_retained": [false],
378
409
  }
379
410
  },
380
411
  {
@@ -384,15 +415,17 @@ const config = {
384
415
  "promo_id": () => `promo_${v.uid(5)}`,
385
416
  "promo_type": ["banner", "push", "in_feed"],
386
417
  "promo_value": ["10%", "15%", "20%", "25%", "30%", "40%", "50%"],
418
+ "trial_retained": [false],
387
419
  }
388
420
  },
389
421
  {
390
422
  event: "subscription started",
391
423
  weight: 2,
392
424
  properties: {
393
- "plan": u.pickAWinner(["quickbite_plus_monthly", "quickbite_plus_monthly", "quickbite_plus_annual"]),
394
- "price": u.pickAWinner([9.99, 9.99, 79.99]),
395
- "trial": u.pickAWinner([true, false], 0.5),
425
+ "plan": ["quickbite_plus_monthly", "quickbite_plus_monthly", "quickbite_plus_annual"],
426
+ "price": [9.99, 9.99, 79.99],
427
+ "trial": [true, false],
428
+ "trial_retained": [false],
396
429
  }
397
430
  },
398
431
  {
@@ -401,6 +434,7 @@ const config = {
401
434
  properties: {
402
435
  "reason": ["too_expensive", "not_ordering_enough", "found_alternative", "bad_experience"],
403
436
  "months_subscribed": u.weighNumRange(1, 24, 1.5, 15),
437
+ "trial_retained": [false],
404
438
  }
405
439
  },
406
440
  {
@@ -408,22 +442,25 @@ const config = {
408
442
  weight: 3,
409
443
  properties: {
410
444
  "issue_type": ["missing_item", "wrong_order", "late_delivery", "quality_issue", "refund_request"],
411
- "order_id": u.pickAWinner(orderIds),
445
+ "order_id": orderIds,
446
+ "trial_retained": [false],
412
447
  }
413
448
  },
414
449
  {
415
450
  event: "reorder initiated",
416
451
  weight: 6,
417
452
  properties: {
418
- "order_id": u.pickAWinner(orderIds),
453
+ "order_id": orderIds,
419
454
  "original_order_age_days": u.weighNumRange(1, 60, 1.5, 30),
455
+ "referral_user": [false],
456
+ "trial_retained": [false],
420
457
  }
421
458
  },
422
459
  ],
423
460
 
424
461
  superProps: {
425
462
  platform: ["iOS", "Android", "Web"],
426
- subscription_tier: u.pickAWinner(["Free", "Free", "Free", "Free", "QuickBite+"]),
463
+ subscription_tier: ["Free", "Free", "Free", "Free", "QuickBite+"],
427
464
  city: ["New York", "Los Angeles", "Chicago", "Houston", "Phoenix", "San Francisco"],
428
465
  },
429
466
 
@@ -441,6 +478,8 @@ const config = {
441
478
  "avg_order_value": u.weighNumRange(15, 80, 0.8, 40),
442
479
  "orders_per_month": u.weighNumRange(1, 20, 1.5, 10),
443
480
  "favorite_restaurant_count": u.weighNumRange(1, 10),
481
+ "is_high_risk": [false],
482
+ "churn_risk_score": [0],
444
483
  },
445
484
 
446
485
  groupKeys: [
@@ -559,7 +598,9 @@ const config = {
559
598
  'milliseconds'
560
599
  ).toISOString();
561
600
 
601
+ const couponTemplate = record.find(e => e.event === "coupon applied");
562
602
  const couponEvent = {
603
+ ...(couponTemplate || firstEvent),
563
604
  event: "coupon applied",
564
605
  time: midTime,
565
606
  user_id: firstEvent.user_id,
@@ -670,7 +711,7 @@ const config = {
670
711
  if (isReferralUser && event.event === "reorder initiated" && chance.bool({ likelihood: 50 })) {
671
712
  const eventTime = dayjs(event.time);
672
713
  const extraReorder = {
673
- event: "reorder initiated",
714
+ ...event,
674
715
  time: eventTime.add(chance.integer({ min: 1, max: 7 }), 'days').toISOString(),
675
716
  user_id: event.user_id,
676
717
  order_id: chance.pickone(orderIds),