@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-education";
@@ -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
  * ═══════════════════════════════════════════════════════════════════════════════
@@ -203,7 +203,6 @@ const config = {
203
203
  hasAdSpend: false,
204
204
  percentUsersBornInDataset: 50,
205
205
  hasAvatar: true,
206
- batchSize: 2_500_000,
207
206
  concurrency: 1,
208
207
  writeToDisk: false,
209
208
 
@@ -264,7 +263,7 @@ const config = {
264
263
  weight: 1,
265
264
  isFirstEvent: true,
266
265
  properties: {
267
- "account_type": u.pickAWinner(["student", "instructor"], 0.15),
266
+ "account_type": ["instructor", "instructor", "instructor", "instructor", "instructor", "instructor", "student"],
268
267
  "signup_source": ["organic", "referral", "school_partnership", "social_ad"],
269
268
  }
270
269
  },
@@ -272,18 +271,18 @@ const config = {
272
271
  event: "course enrolled",
273
272
  weight: 8,
274
273
  properties: {
275
- "course_id": u.pickAWinner(courseIds),
274
+ "course_id": courseIds,
276
275
  "course_category": ["CS", "Math", "Science", "Business", "Arts", "Languages"],
277
276
  "difficulty": ["beginner", "intermediate", "advanced"],
278
- "is_free": u.pickAWinner([true, false], 0.4),
277
+ "is_free": [false, false, false, true, true],
279
278
  }
280
279
  },
281
280
  {
282
281
  event: "lecture started",
283
282
  weight: 18,
284
283
  properties: {
285
- "course_id": u.pickAWinner(courseIds),
286
- "lecture_id": u.pickAWinner(lectureIds),
284
+ "course_id": courseIds,
285
+ "lecture_id": lectureIds,
287
286
  "lecture_duration_mins": u.weighNumRange(5, 60, 0.8, 20),
288
287
  "module_number": u.weighNumRange(1, 12),
289
288
  }
@@ -292,51 +291,59 @@ const config = {
292
291
  event: "lecture completed",
293
292
  weight: 14,
294
293
  properties: {
295
- "course_id": u.pickAWinner(courseIds),
296
- "lecture_id": u.pickAWinner(lectureIds),
294
+ "course_id": courseIds,
295
+ "lecture_id": lectureIds,
297
296
  "watch_time_mins": u.weighNumRange(3, 60, 0.8, 20),
298
- "playback_speed": u.pickAWinner([0.75, 1.0, 1.0, 1.0, 1.25, 1.5, 2.0]),
299
- "notes_taken": u.pickAWinner([true, false], 0.35),
297
+ "playback_speed": [0.75, 1.0, 1.0, 1.0, 1.25, 1.5, 2.0],
298
+ "notes_taken": [false, false, true],
299
+ "speed_learner": [false],
300
+ "thorough_learner": [false],
300
301
  }
301
302
  },
302
303
  {
303
304
  event: "quiz started",
304
305
  weight: 10,
305
306
  properties: {
306
- "course_id": u.pickAWinner(courseIds),
307
- "quiz_id": u.pickAWinner(quizIds),
307
+ "course_id": courseIds,
308
+ "quiz_id": quizIds,
308
309
  "quiz_type": ["practice", "graded", "final_exam"],
309
310
  "question_count": u.weighNumRange(5, 50, 0.7, 15),
311
+ "semester_end_rush": [false],
310
312
  }
311
313
  },
312
314
  {
313
315
  event: "quiz completed",
314
316
  weight: 8,
315
317
  properties: {
316
- "course_id": u.pickAWinner(courseIds),
317
- "quiz_id": u.pickAWinner(quizIds),
318
+ "course_id": courseIds,
319
+ "quiz_id": quizIds,
318
320
  "score_percent": u.weighNumRange(0, 100, 1.2, 50),
319
321
  "time_spent_mins": u.weighNumRange(3, 120, 0.6, 25),
320
322
  "attempts": u.weighNumRange(1, 5, 0.5, 3),
323
+ "diligent_student": [false],
324
+ "speed_learner_effect": [false],
325
+ "semester_end_rush": [false],
321
326
  }
322
327
  },
323
328
  {
324
329
  event: "assignment submitted",
325
330
  weight: 6,
326
331
  properties: {
327
- "course_id": u.pickAWinner(courseIds),
328
- "assignment_id": u.pickAWinner(assignmentIds),
332
+ "course_id": courseIds,
333
+ "assignment_id": assignmentIds,
329
334
  "submission_type": ["text", "code", "file", "project"],
330
335
  "word_count": u.weighNumRange(100, 5000, 0.6, 500),
331
- "is_late": u.pickAWinner([true, false], 0.2),
336
+ "is_late": [false, false, false, false, true],
337
+ "is_deadline_rush": [false],
338
+ "semester_end_rush": [false],
332
339
  }
333
340
  },
334
341
  {
335
342
  event: "assignment graded",
336
343
  weight: 5,
337
344
  properties: {
338
- "course_id": u.pickAWinner(courseIds),
339
- "assignment_id": u.pickAWinner(assignmentIds),
345
+ "course_id": courseIds,
346
+ "assignment_id": assignmentIds,
340
347
  "grade": ["A", "B", "C", "D", "F"],
341
348
  "feedback_length": u.weighNumRange(0, 500, 0.5, 100),
342
349
  "grader": ["instructor", "peer", "auto"],
@@ -346,25 +353,27 @@ const config = {
346
353
  event: "discussion posted",
347
354
  weight: 7,
348
355
  properties: {
349
- "course_id": u.pickAWinner(courseIds),
356
+ "course_id": courseIds,
350
357
  "post_type": ["question", "answer", "comment"],
351
358
  "word_count": u.weighNumRange(10, 500, 0.6, 80),
359
+ "study_group_member": [false],
352
360
  }
353
361
  },
354
362
  {
355
363
  event: "certificate earned",
356
364
  weight: 2,
357
365
  properties: {
358
- "course_id": u.pickAWinner(courseIds),
366
+ "course_id": courseIds,
359
367
  "completion_time_days": u.weighNumRange(7, 180, 0.5, 45),
360
368
  "final_grade": u.weighNumRange(60, 100, 1.2, 30),
369
+ "diligent_student": [false],
361
370
  }
362
371
  },
363
372
  {
364
373
  event: "study group joined",
365
374
  weight: 4,
366
375
  properties: {
367
- "group_id": u.pickAWinner(groupIds),
376
+ "group_id": groupIds,
368
377
  "group_size": u.weighNumRange(3, 20, 0.7, 8),
369
378
  "group_type": ["study_circle", "project_team", "tutoring"],
370
379
  }
@@ -374,14 +383,14 @@ const config = {
374
383
  weight: 9,
375
384
  properties: {
376
385
  "resource_type": ["pdf", "slides", "code_sample", "dataset", "cheat_sheet"],
377
- "course_id": u.pickAWinner(courseIds),
386
+ "course_id": courseIds,
378
387
  }
379
388
  },
380
389
  {
381
390
  event: "instructor feedback given",
382
391
  weight: 3,
383
392
  properties: {
384
- "course_id": u.pickAWinner(courseIds),
393
+ "course_id": courseIds,
385
394
  "feedback_type": ["written", "video", "rubric"],
386
395
  "response_time_hours": u.weighNumRange(1, 72, 0.5, 15),
387
396
  }
@@ -390,10 +399,10 @@ const config = {
390
399
  event: "course reviewed",
391
400
  weight: 3,
392
401
  properties: {
393
- "course_id": u.pickAWinner(courseIds),
402
+ "course_id": courseIds,
394
403
  "rating": u.weighNumRange(1, 5, 1.5, 3),
395
404
  "review_length": u.weighNumRange(10, 1000, 0.5, 100),
396
- "would_recommend": u.pickAWinner([true, false], 0.7),
405
+ "would_recommend": [false, false, false, true, true, true, true, true, true, true],
397
406
  }
398
407
  },
399
408
  {
@@ -401,7 +410,7 @@ const config = {
401
410
  weight: 2,
402
411
  properties: {
403
412
  "plan": ["monthly", "annual", "lifetime"],
404
- "price": u.pickAWinner([19.99, 149.99, 499.99]),
413
+ "price": [19.99, 149.99, 499.99],
405
414
  }
406
415
  },
407
416
  {
@@ -416,11 +425,12 @@ const config = {
416
425
  event: "practice problem solved",
417
426
  weight: 12,
418
427
  properties: {
419
- "course_id": u.pickAWinner(courseIds),
420
- "problem_id": u.pickAWinner(problemIds),
428
+ "course_id": courseIds,
429
+ "problem_id": problemIds,
421
430
  "difficulty": ["easy", "medium", "hard"],
422
431
  "time_to_solve_sec": u.weighNumRange(10, 3600, 0.5, 300),
423
- "hint_used": u.pickAWinner([true, false], 0.35),
432
+ "hint_used": [false, false, true],
433
+ "independent_solver": [false],
424
434
  }
425
435
  },
426
436
  ],
@@ -429,14 +439,33 @@ const config = {
429
439
  platform: ["Web", "iOS", "Android", "iPad"],
430
440
  },
431
441
 
432
- scdProps: {},
442
+ scdProps: {
443
+ enrollment_status: {
444
+ values: ["enrolled", "active", "completed", "dropped"],
445
+ frequency: "month",
446
+ timing: "fuzzy",
447
+ max: 6
448
+ },
449
+ course_status: {
450
+ values: ["draft", "published", "archived", "deprecated"],
451
+ frequency: "month",
452
+ timing: "fixed",
453
+ max: 6,
454
+ type: "course_id"
455
+ }
456
+ },
433
457
 
434
458
  userProps: {
435
- "account_type": u.pickAWinner(["student", "student", "student", "student", "student", "student", "student", "student", "instructor"]),
436
- "subscription_status": u.pickAWinner(["free", "free", "free", "monthly", "annual"]),
459
+ "account_type": ["student", "student", "student", "student", "student", "student", "student", "student", "instructor"],
460
+ "subscription_status": ["free", "free", "free", "monthly", "annual"],
437
461
  "learning_style": ["visual", "reading", "hands_on", "auditory"],
438
462
  "education_level": ["high_school", "bachelors", "masters", "phd", "self_taught"],
439
463
  "timezone": ["US_Eastern", "US_Pacific", "US_Central", "Europe", "Asia"],
464
+ "courses_created": [0],
465
+ "teaching_experience_years": [0],
466
+ "instructor_rating": [0],
467
+ "learning_goal": ["none"],
468
+ "study_hours_per_week": [0],
440
469
  },
441
470
 
442
471
  groupKeys: [
@@ -640,9 +669,10 @@ const config = {
640
669
  // 40% chance to splice in an extra certificate_earned event
641
670
  if (chance.bool({ likelihood: 40 })) {
642
671
  const lastEvent = userEvents[userEvents.length - 1];
643
- if (lastEvent) {
672
+ const certTemplate = userEvents.find(e => e.event === "certificate earned");
673
+ if (lastEvent && certTemplate) {
644
674
  const certEvent = {
645
- event: "certificate earned",
675
+ ...certTemplate,
646
676
  time: dayjs(lastEvent.time).add(chance.integer({ min: 1, max: 5 }), 'days').toISOString(),
647
677
  user_id: lastEvent.user_id,
648
678
  course_id: chance.pickone(courseIds),
@@ -713,9 +743,10 @@ const config = {
713
743
  } else if (joinedStudyGroupEarly) {
714
744
  // Study group joiners keep all events and get bonus discussion_posted events
715
745
  const lastEvent = userEvents[userEvents.length - 1];
716
- if (lastEvent && chance.bool({ likelihood: 60 })) {
746
+ const discussionTemplate = userEvents.find(e => e.event === "discussion posted");
747
+ if (lastEvent && discussionTemplate && chance.bool({ likelihood: 60 })) {
717
748
  const bonusDiscussion = {
718
- event: "discussion posted",
749
+ ...discussionTemplate,
719
750
  time: dayjs(lastEvent.time).add(chance.integer({ min: 1, max: 3 }), 'days').toISOString(),
720
751
  user_id: lastEvent.user_id,
721
752
  course_id: chance.pickone(courseIds),