@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.
- package/README.md +7 -7
- package/dungeons/technical/ad-spend-schema.json +128 -0
- package/dungeons/technical/ad-spend.js +116 -0
- package/dungeons/technical/anonymous-users-schema.json +92 -0
- package/dungeons/technical/anonymous-users.js +102 -0
- package/dungeons/technical/array-of-object-lookup-schema.json +191 -0
- package/dungeons/{array-of-object-lookup.js → technical/array-of-object-lookup.js} +12 -5
- package/dungeons/technical/experiments-schema.json +203 -0
- package/dungeons/technical/experiments.js +168 -0
- package/dungeons/technical/foobar-schema.json +362 -0
- package/dungeons/{foobar.js → technical/foobar.js} +3 -3
- package/dungeons/technical/group-analytics-schema.json +241 -0
- package/dungeons/technical/group-analytics.js +151 -0
- package/dungeons/technical/mirror-strategies-schema.json +84 -0
- package/dungeons/technical/mirror-strategies.js +126 -0
- package/dungeons/technical/nested-objects-schema.json +145 -0
- package/dungeons/technical/nested-objects.js +207 -0
- package/dungeons/technical/retention-cadence-schema.json +37 -0
- package/dungeons/{retention-cadence.js → technical/retention-cadence.js} +2 -3
- package/dungeons/technical/sanity-schema.json +185 -0
- package/dungeons/{sanity.js → technical/sanity.js} +4 -2
- package/dungeons/technical/scale-test-schema.json +70 -0
- package/dungeons/technical/scale-test.js +90 -0
- package/dungeons/technical/scd-schema.json +467 -0
- package/dungeons/{scd.js → technical/scd.js} +20 -10
- package/dungeons/technical/simple-schema.json +362 -0
- package/dungeons/{simple.js → technical/simple.js} +7 -7
- package/dungeons/technical/simplest-schema.json +724 -0
- package/dungeons/{simplest.js → technical/simplest.js} +7 -7
- package/dungeons/technical/text-generation-schema.json +1062 -0
- package/dungeons/{text-generation.js → technical/text-generation.js} +24 -11
- package/dungeons/vertical/community-schema.json +579 -0
- package/dungeons/vertical/community.js +794 -0
- package/dungeons/vertical/devtools-schema.json +601 -0
- package/dungeons/vertical/devtools.js +843 -0
- package/dungeons/vertical/ecommerce-schema.json +604 -0
- package/dungeons/{ecommerce.js → vertical/ecommerce.js} +43 -5
- package/dungeons/vertical/education-schema.json +5686 -0
- package/dungeons/{education.js → vertical/education.js} +70 -39
- package/dungeons/vertical/fintech-schema.json +630 -0
- package/dungeons/{fintech.js → vertical/fintech.js} +107 -56
- package/dungeons/vertical/fitness-schema.json +530 -0
- package/dungeons/vertical/fitness.js +808 -0
- package/dungeons/vertical/food-delivery-schema.json +36728 -0
- package/dungeons/{food.js → vertical/food-delivery.js} +67 -26
- package/dungeons/vertical/gaming-schema.json +438 -0
- package/dungeons/{gaming.js → vertical/gaming.js} +29 -16
- package/dungeons/vertical/healthcare-schema.json +549 -0
- package/dungeons/vertical/healthcare.js +775 -0
- package/dungeons/vertical/insurance-application-schema.json +485 -0
- package/dungeons/{insurance-application.js → vertical/insurance-application.js} +41 -31
- package/dungeons/vertical/logistics-schema.json +574 -0
- package/dungeons/vertical/logistics.js +799 -0
- package/dungeons/vertical/marketplace-schema.json +533 -0
- package/dungeons/vertical/marketplace.js +850 -0
- package/dungeons/vertical/media-schema.json +4749 -0
- package/dungeons/{media.js → vertical/media.js} +103 -19
- package/dungeons/vertical/rpg-schema.json +2491 -0
- package/dungeons/{rpg.js → vertical/rpg.js} +87 -60
- package/dungeons/vertical/sass-schema.json +3128 -0
- package/dungeons/{sass.js → vertical/sass.js} +65 -26
- package/dungeons/vertical/social-schema.json +620 -0
- package/dungeons/{social.js → vertical/social.js} +76 -17
- package/dungeons/vertical/travel-schema.json +580 -0
- package/dungeons/vertical/travel.js +742 -0
- package/index.js +20 -16
- package/lib/core/config-validator.js +286 -1
- package/lib/core/context.js +16 -5
- package/lib/core/storage.js +2 -0
- package/lib/generators/adspend.js +3 -3
- package/lib/generators/events.js +141 -14
- package/lib/generators/funnels.js +67 -7
- package/lib/generators/text.js +2 -2
- package/lib/orchestrators/user-loop.js +444 -22
- package/lib/templates/soup-presets.js +2 -2
- package/lib/utils/utils.js +4 -5
- package/package.json +4 -3
- package/scripts/dungeon-to-json.mjs +163 -0
- package/scripts/extract-dungeon-schema.mjs +343 -0
- package/scripts/json-to-dungeon.mjs +200 -0
- package/scripts/run-dungeon.mjs +76 -0
- package/scripts/run-many.mjs +118 -0
- package/scripts/verify-runner.mjs +42 -0
- package/types.d.ts +316 -1
- package/dungeons/array-of-object-lookup-schema.json +0 -327
- package/dungeons/ecommerce-schema.json +0 -462
- package/dungeons/education-schema.json +0 -2409
- package/dungeons/fintech-schema.json +0 -14034
- package/dungeons/foobar-schema.json +0 -403
- package/dungeons/food-delivery-schema.json +0 -192
- package/dungeons/food-delivery.js +0 -602
- package/dungeons/food-schema.json +0 -1152
- package/dungeons/gaming-schema.json +0 -1270
- package/dungeons/insurance-application-schema.json +0 -204
- package/dungeons/media-schema.json +0 -906
- package/dungeons/retention-cadence-schema.json +0 -78
- package/dungeons/rpg-schema.json +0 -4526
- package/dungeons/sanity-schema.json +0 -255
- package/dungeons/sass-schema.json +0 -1291
- package/dungeons/scd-schema.json +0 -919
- package/dungeons/simple-schema.json +0 -608
- package/dungeons/simplest-schema.json +0 -1418
- package/dungeons/social-schema.json +0 -1118
- 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 "
|
|
4
|
+
import * as u from "../../lib/utils/utils.js";
|
|
5
5
|
|
|
6
6
|
const SEED = "harness-fintech";
|
|
7
7
|
dayjs.extend(utc);
|
|
@@ -9,7 +9,7 @@ const chance = u.initChance(SEED);
|
|
|
9
9
|
const num_users = 5_000;
|
|
10
10
|
const days = 100;
|
|
11
11
|
|
|
12
|
-
/** @typedef {import("
|
|
12
|
+
/** @typedef {import("../../types").Dungeon} Config */
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* ===================================================================
|
|
@@ -151,11 +151,24 @@ const config = {
|
|
|
151
151
|
|
|
152
152
|
hasAvatar: true,
|
|
153
153
|
|
|
154
|
-
batchSize: 2_500_000,
|
|
155
154
|
concurrency: 1,
|
|
156
155
|
writeToDisk: false,
|
|
157
156
|
|
|
158
|
-
scdProps: {
|
|
157
|
+
scdProps: {
|
|
158
|
+
account_tier: {
|
|
159
|
+
values: ["basic", "plus", "premium"],
|
|
160
|
+
frequency: "month",
|
|
161
|
+
timing: "fuzzy",
|
|
162
|
+
max: 6
|
|
163
|
+
},
|
|
164
|
+
risk_category: {
|
|
165
|
+
values: ["low", "medium", "high", "critical"],
|
|
166
|
+
frequency: "month",
|
|
167
|
+
timing: "fixed",
|
|
168
|
+
max: 8,
|
|
169
|
+
type: "household_id"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
159
172
|
|
|
160
173
|
funnels: [
|
|
161
174
|
{
|
|
@@ -221,7 +234,7 @@ const config = {
|
|
|
221
234
|
weight: 1,
|
|
222
235
|
isFirstEvent: true,
|
|
223
236
|
properties: {
|
|
224
|
-
"account_type":
|
|
237
|
+
"account_type": ["personal", "business", "personal"],
|
|
225
238
|
"signup_channel": ["app", "web", "referral", "branch"],
|
|
226
239
|
}
|
|
227
240
|
},
|
|
@@ -231,6 +244,7 @@ const config = {
|
|
|
231
244
|
properties: {
|
|
232
245
|
"session_duration_sec": u.weighNumRange(10, 600, 0.3, 60),
|
|
233
246
|
"pages_viewed": u.weighNumRange(1, 15, 0.5, 3),
|
|
247
|
+
"month_end_anxiety": [false],
|
|
234
248
|
}
|
|
235
249
|
},
|
|
236
250
|
{
|
|
@@ -239,6 +253,7 @@ const config = {
|
|
|
239
253
|
properties: {
|
|
240
254
|
"account_balance": u.weighNumRange(0, 50000, 0.8, 2500),
|
|
241
255
|
"account_type": ["checking", "savings", "investment"],
|
|
256
|
+
"month_end_check": [false],
|
|
242
257
|
}
|
|
243
258
|
},
|
|
244
259
|
{
|
|
@@ -249,6 +264,8 @@ const config = {
|
|
|
249
264
|
"amount": u.weighNumRange(1, 5000, 0.3, 50),
|
|
250
265
|
"merchant_category": ["grocery", "restaurant", "gas", "retail", "online", "subscription", "utilities"],
|
|
251
266
|
"payment_method": ["debit", "credit", "contactless", "online"],
|
|
267
|
+
"payday": [false],
|
|
268
|
+
"fraud_sequence": [false],
|
|
252
269
|
}
|
|
253
270
|
},
|
|
254
271
|
{
|
|
@@ -258,6 +275,7 @@ const config = {
|
|
|
258
275
|
"transfer_type": ["internal", "external", "p2p", "wire"],
|
|
259
276
|
"amount": u.weighNumRange(10, 10000, 0.3, 200),
|
|
260
277
|
"recipient_type": ["friend", "family", "business", "self"],
|
|
278
|
+
"post_payday_spending": [false],
|
|
261
279
|
}
|
|
262
280
|
},
|
|
263
281
|
{
|
|
@@ -266,7 +284,9 @@ const config = {
|
|
|
266
284
|
properties: {
|
|
267
285
|
"bill_type": ["rent", "utilities", "phone", "insurance", "subscription", "loan_payment"],
|
|
268
286
|
"amount": u.weighNumRange(20, 3000, 0.5, 150),
|
|
269
|
-
"auto_pay":
|
|
287
|
+
"auto_pay": [false, false, false, true, true],
|
|
288
|
+
"missed_payment": [false],
|
|
289
|
+
"manual_payment": [false],
|
|
270
290
|
}
|
|
271
291
|
},
|
|
272
292
|
{
|
|
@@ -292,6 +312,7 @@ const config = {
|
|
|
292
312
|
"goal_type": ["emergency", "vacation", "car", "home", "education", "retirement"],
|
|
293
313
|
"target_amount": u.weighNumRange(500, 50000, 0.3, 5000),
|
|
294
314
|
"monthly_contribution": u.weighNumRange(25, 2000, 0.5, 200),
|
|
315
|
+
"budget_discipline": [false],
|
|
295
316
|
}
|
|
296
317
|
},
|
|
297
318
|
{
|
|
@@ -300,7 +321,9 @@ const config = {
|
|
|
300
321
|
properties: {
|
|
301
322
|
"investment_type": ["stocks", "etf", "crypto", "bonds", "mutual_fund"],
|
|
302
323
|
"amount": u.weighNumRange(10, 10000, 0.3, 250),
|
|
303
|
-
"action":
|
|
324
|
+
"action": ["buy", "sell", "buy"],
|
|
325
|
+
"premium_returns": [false],
|
|
326
|
+
"budget_discipline": [false],
|
|
304
327
|
}
|
|
305
328
|
},
|
|
306
329
|
{
|
|
@@ -308,6 +331,7 @@ const config = {
|
|
|
308
331
|
weight: 1,
|
|
309
332
|
properties: {
|
|
310
333
|
"reason": ["lost", "stolen", "suspicious_activity", "travel"],
|
|
334
|
+
"fraud_sequence": [false],
|
|
311
335
|
}
|
|
312
336
|
},
|
|
313
337
|
{
|
|
@@ -316,6 +340,7 @@ const config = {
|
|
|
316
340
|
properties: {
|
|
317
341
|
"dispute_amount": u.weighNumRange(10, 2000, 0.5, 100),
|
|
318
342
|
"reason": ["unauthorized", "duplicate", "not_received", "damaged", "wrong_amount"],
|
|
343
|
+
"fraud_sequence": [false],
|
|
319
344
|
}
|
|
320
345
|
},
|
|
321
346
|
{
|
|
@@ -340,8 +365,8 @@ const config = {
|
|
|
340
365
|
weight: 2,
|
|
341
366
|
properties: {
|
|
342
367
|
"old_tier": ["basic", "plus", "premium"],
|
|
343
|
-
"new_tier":
|
|
344
|
-
"monthly_fee":
|
|
368
|
+
"new_tier": ["plus", "premium", "premium"],
|
|
369
|
+
"monthly_fee": [4.99, 9.99, 14.99],
|
|
345
370
|
}
|
|
346
371
|
},
|
|
347
372
|
{
|
|
@@ -350,7 +375,8 @@ const config = {
|
|
|
350
375
|
properties: {
|
|
351
376
|
"channel": ["chat", "phone", "email", "in_app"],
|
|
352
377
|
"issue_type": ["transaction", "account", "card", "transfer", "technical"],
|
|
353
|
-
"resolved":
|
|
378
|
+
"resolved": [false, true, true, true, true],
|
|
379
|
+
"fraud_sequence": [false],
|
|
354
380
|
}
|
|
355
381
|
},
|
|
356
382
|
{
|
|
@@ -358,7 +384,7 @@ const config = {
|
|
|
358
384
|
weight: 10,
|
|
359
385
|
properties: {
|
|
360
386
|
"notification_type": ["transaction", "low_balance", "bill_due", "reward", "security", "promo"],
|
|
361
|
-
"action_taken":
|
|
387
|
+
"action_taken": [false, false, true, true, true],
|
|
362
388
|
}
|
|
363
389
|
},
|
|
364
390
|
{
|
|
@@ -367,13 +393,15 @@ const config = {
|
|
|
367
393
|
properties: {
|
|
368
394
|
"reward_type": ["cashback", "points", "discount", "partner_offer"],
|
|
369
395
|
"value": u.weighNumRange(1, 100, 0.5, 10),
|
|
396
|
+
"premium_reward": [false],
|
|
370
397
|
}
|
|
371
398
|
}
|
|
372
399
|
],
|
|
373
400
|
|
|
374
401
|
superProps: {
|
|
375
|
-
account_tier:
|
|
402
|
+
account_tier: ["basic", "basic", "basic", "plus", "plus", "premium"],
|
|
376
403
|
platform: ["ios", "android", "web"],
|
|
404
|
+
low_balance_churn: [false],
|
|
377
405
|
},
|
|
378
406
|
|
|
379
407
|
userProps: {
|
|
@@ -381,7 +409,13 @@ const config = {
|
|
|
381
409
|
"income_bracket": ["under_30k", "30k_50k", "50k_75k", "75k_100k", "100k_150k", "over_150k"],
|
|
382
410
|
"account_age_months": u.weighNumRange(1, 60, 0.5, 12),
|
|
383
411
|
"total_balance": u.weighNumRange(0, 100000, 0.3, 5000),
|
|
384
|
-
"has_direct_deposit":
|
|
412
|
+
"has_direct_deposit": [false, false, true, true, true],
|
|
413
|
+
"account_segment": ["personal"],
|
|
414
|
+
"employee_count": [0],
|
|
415
|
+
"annual_revenue": [0],
|
|
416
|
+
"industry": [""],
|
|
417
|
+
"age_range": [""],
|
|
418
|
+
"life_stage": [""],
|
|
385
419
|
},
|
|
386
420
|
|
|
387
421
|
groupKeys: [
|
|
@@ -393,7 +427,7 @@ const config = {
|
|
|
393
427
|
"household_size": u.weighNumRange(1, 6),
|
|
394
428
|
"combined_income": u.weighNumRange(20000, 300000, 0.3, 75000),
|
|
395
429
|
"financial_health_score": u.weighNumRange(1, 100, 1, 65),
|
|
396
|
-
"primary_bank":
|
|
430
|
+
"primary_bank": ["NexBank_only", "multi_bank", "NexBank_only"],
|
|
397
431
|
}
|
|
398
432
|
},
|
|
399
433
|
|
|
@@ -568,48 +602,62 @@ const config = {
|
|
|
568
602
|
const burstCount = chance.integer({ min: 3, max: 5 });
|
|
569
603
|
const fraudEvents = [];
|
|
570
604
|
|
|
605
|
+
// Find template events for cloning
|
|
606
|
+
const txnTemplate = userEvents.find(e => e.event === "transaction completed");
|
|
607
|
+
const cardTemplate = userEvents.find(e => e.event === "card locked");
|
|
608
|
+
const disputeTemplate = userEvents.find(e => e.event === "dispute filed");
|
|
609
|
+
const supportTemplate = userEvents.find(e => e.event === "support contacted");
|
|
610
|
+
|
|
571
611
|
for (let i = 0; i < burstCount; i++) {
|
|
612
|
+
if (txnTemplate) {
|
|
613
|
+
fraudEvents.push({
|
|
614
|
+
...txnTemplate,
|
|
615
|
+
time: midTime.add(i * 10, "minutes").toISOString(),
|
|
616
|
+
user_id: distinctId,
|
|
617
|
+
transaction_type: "purchase",
|
|
618
|
+
amount: chance.integer({ min: 500, max: 3000 }),
|
|
619
|
+
merchant_category: chance.pickone(["online", "retail"]),
|
|
620
|
+
payment_method: "credit",
|
|
621
|
+
fraud_sequence: true,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Card locked after the burst
|
|
627
|
+
if (cardTemplate) {
|
|
572
628
|
fraudEvents.push({
|
|
573
|
-
|
|
574
|
-
time: midTime.add(
|
|
629
|
+
...cardTemplate,
|
|
630
|
+
time: midTime.add(burstCount * 10 + 5, "minutes").toISOString(),
|
|
575
631
|
user_id: distinctId,
|
|
576
|
-
|
|
577
|
-
amount: chance.integer({ min: 500, max: 3000 }),
|
|
578
|
-
merchant_category: chance.pickone(["online", "retail"]),
|
|
579
|
-
payment_method: "credit",
|
|
632
|
+
reason: "suspicious_activity",
|
|
580
633
|
fraud_sequence: true,
|
|
581
634
|
});
|
|
582
635
|
}
|
|
583
636
|
|
|
584
|
-
// Card locked after the burst
|
|
585
|
-
fraudEvents.push({
|
|
586
|
-
event: "card locked",
|
|
587
|
-
time: midTime.add(burstCount * 10 + 5, "minutes").toISOString(),
|
|
588
|
-
user_id: distinctId,
|
|
589
|
-
reason: "suspicious_activity",
|
|
590
|
-
fraud_sequence: true,
|
|
591
|
-
});
|
|
592
|
-
|
|
593
637
|
// Dispute filed shortly after
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
638
|
+
if (disputeTemplate) {
|
|
639
|
+
fraudEvents.push({
|
|
640
|
+
...disputeTemplate,
|
|
641
|
+
time: midTime.add(burstCount * 10 + 30, "minutes").toISOString(),
|
|
642
|
+
user_id: distinctId,
|
|
643
|
+
dispute_amount: chance.integer({ min: 500, max: 3000 }),
|
|
644
|
+
reason: "unauthorized",
|
|
645
|
+
fraud_sequence: true,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
602
648
|
|
|
603
649
|
// Support contacted
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
650
|
+
if (supportTemplate) {
|
|
651
|
+
fraudEvents.push({
|
|
652
|
+
...supportTemplate,
|
|
653
|
+
time: midTime.add(burstCount * 10 + 45, "minutes").toISOString(),
|
|
654
|
+
user_id: distinctId,
|
|
655
|
+
channel: "phone",
|
|
656
|
+
issue_type: "card",
|
|
657
|
+
resolved: true,
|
|
658
|
+
fraud_sequence: true,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
613
661
|
|
|
614
662
|
// Splice all fraud events into the user's timeline
|
|
615
663
|
userEvents.splice(midIdx + 1, 0, ...fraudEvents);
|
|
@@ -674,16 +722,19 @@ const config = {
|
|
|
674
722
|
|
|
675
723
|
// Splice extra savings goal events (budget-conscious users set more goals)
|
|
676
724
|
if (event.event === "budget created" && chance.bool({ likelihood: 50 })) {
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
725
|
+
const savingsTemplate = userEvents.find(e => e.event === "savings goal set");
|
|
726
|
+
if (savingsTemplate) {
|
|
727
|
+
const extraGoal = {
|
|
728
|
+
...savingsTemplate,
|
|
729
|
+
time: eventTime.add(chance.integer({ min: 1, max: 7 }), "days").toISOString(),
|
|
730
|
+
user_id: event.user_id,
|
|
731
|
+
goal_type: chance.pickone(["emergency", "vacation", "car", "home"]),
|
|
732
|
+
target_amount: chance.integer({ min: 1000, max: 20000 }),
|
|
733
|
+
monthly_contribution: chance.integer({ min: 100, max: 800 }),
|
|
734
|
+
budget_discipline: true,
|
|
735
|
+
};
|
|
736
|
+
userEvents.splice(idx + 1, 0, extraGoal);
|
|
737
|
+
}
|
|
687
738
|
}
|
|
688
739
|
});
|
|
689
740
|
}
|