@ak--47/dungeon-master 1.4.4 → 1.5.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/.claude/skills/analyze-soup/SKILL.md +158 -0
- package/.claude/skills/create-dungeon/SKILL.md +464 -0
- package/.claude/skills/verify-dungeon/SKILL.md +157 -0
- package/.claude/skills/verify-dungeon/references/counting-semantics.md +161 -0
- package/.claude/skills/verify-dungeon/references/report-format.md +216 -0
- package/.claude/skills/verify-dungeon/references/sql-recipes.md +857 -0
- package/.claude/skills/write-hooks/SKILL.md +468 -0
- package/CHANGELOG.md +147 -0
- package/HOOKS.md +1243 -597
- package/README.md +140 -5
- package/dungeons/technical/ad-spend.js +1 -1
- package/dungeons/technical/anonymous-users.js +1 -1
- package/dungeons/technical/array-of-object-lookup.js +1 -1
- package/dungeons/technical/datagen-v15-verify.js +74 -0
- package/dungeons/technical/experiments.js +1 -1
- package/dungeons/technical/foobar.js +1 -1
- package/dungeons/technical/group-analytics.js +1 -1
- package/dungeons/technical/mirror-strategies.js +1 -1
- package/dungeons/technical/nested-objects.js +1 -1
- package/dungeons/technical/retention-cadence.js +1 -1
- package/dungeons/technical/sanity.js +1 -1
- package/dungeons/technical/scale-test.js +1 -1
- package/dungeons/technical/scd.js +1 -1
- package/dungeons/technical/simple.js +1 -1
- package/dungeons/technical/simplest.js +74 -20
- package/dungeons/technical/text-generation.js +1 -1
- package/dungeons/vertical/ai-platform.js +4 -0
- package/dungeons/vertical/community.js +9 -3
- package/dungeons/vertical/crypto.js +5 -0
- package/dungeons/vertical/dating.js +23 -10
- package/dungeons/vertical/devtools.js +10 -0
- package/dungeons/vertical/ecommerce.js +6 -0
- package/dungeons/vertical/education.js +11 -0
- package/dungeons/vertical/fintech.js +13 -0
- package/dungeons/vertical/fitness.js +10 -0
- package/dungeons/vertical/food-delivery.js +9 -0
- package/dungeons/vertical/gaming.js +10 -0
- package/dungeons/vertical/healthcare.js +5 -0
- package/dungeons/vertical/insurance-application.js +10 -0
- package/dungeons/vertical/logistics.js +8 -1
- package/dungeons/vertical/marketplace.js +7 -0
- package/dungeons/vertical/media.js +8 -0
- package/dungeons/vertical/real-estate.js +7 -1
- package/dungeons/vertical/sass.js +12 -0
- package/dungeons/vertical/social.js +9 -0
- package/dungeons/vertical/travel.js +5 -0
- package/index.js +45 -7
- package/lib/core/config-validator.js +270 -7
- package/lib/core/context.js +58 -0
- package/lib/core/dungeon-loader.js +2 -5
- package/lib/generators/events.js +12 -13
- package/lib/generators/funnels.js +72 -1
- package/lib/hook-helpers/index.js +1 -0
- package/lib/hook-helpers/inject.js +95 -0
- package/lib/orchestrators/mixpanel-sender.js +27 -1
- package/lib/orchestrators/user-loop.js +488 -29
- package/lib/templates/macro-presets.js +39 -9
- package/lib/utils/utils.js +16 -79
- package/lib/verify/counting.js +320 -0
- package/lib/verify/emulate-breakdown.js +512 -108
- package/lib/verify/funnel-engine.js +539 -0
- package/lib/verify/identity.js +78 -0
- package/lib/verify/index.js +19 -0
- package/lib/verify/verify-dungeon.js +58 -0
- package/package.json +4 -2
- package/types.d.ts +314 -4
- package/scripts/smoke-test-all.mjs +0 -162
|
@@ -416,6 +416,7 @@ const config = {
|
|
|
416
416
|
{
|
|
417
417
|
event: "content selected",
|
|
418
418
|
weight: 15,
|
|
419
|
+
isStrictEvent: false,
|
|
419
420
|
properties: {
|
|
420
421
|
"content_type": ["movie", "series", "documentary", "special"],
|
|
421
422
|
"genre": ["action", "comedy", "drama", "documentary", "horror", "sci_fi", "animation", "thriller", "romance"],
|
|
@@ -425,6 +426,7 @@ const config = {
|
|
|
425
426
|
{
|
|
426
427
|
event: "playback started",
|
|
427
428
|
weight: 18,
|
|
429
|
+
isStrictEvent: false,
|
|
428
430
|
properties: {
|
|
429
431
|
"content_id": contentIds,
|
|
430
432
|
"content_type": ["movie", "series", "documentary", "special"],
|
|
@@ -436,6 +438,7 @@ const config = {
|
|
|
436
438
|
{
|
|
437
439
|
event: "playback completed",
|
|
438
440
|
weight: 12,
|
|
441
|
+
isStrictEvent: false,
|
|
439
442
|
properties: {
|
|
440
443
|
"content_id": contentIds,
|
|
441
444
|
"content_type": ["movie", "series", "documentary", "special"],
|
|
@@ -446,6 +449,7 @@ const config = {
|
|
|
446
449
|
{
|
|
447
450
|
event: "playback paused",
|
|
448
451
|
weight: 10,
|
|
452
|
+
isStrictEvent: false,
|
|
449
453
|
properties: {
|
|
450
454
|
"content_id": contentIds,
|
|
451
455
|
"pause_reason": ["manual", "ad_break", "buffering", "notification"],
|
|
@@ -454,6 +458,7 @@ const config = {
|
|
|
454
458
|
{
|
|
455
459
|
event: "content rated",
|
|
456
460
|
weight: 6,
|
|
461
|
+
isStrictEvent: false,
|
|
457
462
|
properties: {
|
|
458
463
|
"content_id": contentIds,
|
|
459
464
|
"rating": u.weighNumRange(1, 5, 2, 4),
|
|
@@ -489,6 +494,7 @@ const config = {
|
|
|
489
494
|
{
|
|
490
495
|
event: "recommendation clicked",
|
|
491
496
|
weight: 9,
|
|
497
|
+
isStrictEvent: false,
|
|
492
498
|
properties: {
|
|
493
499
|
"algorithm": ["collaborative_filtering", "content_based", "trending", "editorial"],
|
|
494
500
|
"position": u.weighNumRange(1, 20),
|
|
@@ -504,6 +510,7 @@ const config = {
|
|
|
504
510
|
{
|
|
505
511
|
event: "ad impression",
|
|
506
512
|
weight: 8,
|
|
513
|
+
isStrictEvent: false,
|
|
507
514
|
properties: {
|
|
508
515
|
"ad_type": ["pre_roll", "mid_roll", "banner", "interstitial"],
|
|
509
516
|
"ad_duration_sec": u.weighNumRange(5, 30),
|
|
@@ -539,6 +546,7 @@ const config = {
|
|
|
539
546
|
{
|
|
540
547
|
event: "subtitle toggled",
|
|
541
548
|
weight: 4,
|
|
549
|
+
isStrictEvent: false,
|
|
542
550
|
properties: {
|
|
543
551
|
"subtitle_language": ["none", "english", "spanish", "french", "japanese", "korean"],
|
|
544
552
|
"action": ["enabled", "disabled", "changed"],
|
|
@@ -344,7 +344,8 @@ const config = {
|
|
|
344
344
|
conversionRate: 40,
|
|
345
345
|
timeToConvert: 24,
|
|
346
346
|
weight: 5,
|
|
347
|
-
name: "Tour Funnel"
|
|
347
|
+
name: "Tour Funnel",
|
|
348
|
+
reentry: true,
|
|
348
349
|
},
|
|
349
350
|
{
|
|
350
351
|
sequence: ["property listed", "open house attended", "property sold"],
|
|
@@ -379,6 +380,7 @@ const config = {
|
|
|
379
380
|
{
|
|
380
381
|
event: "property viewed",
|
|
381
382
|
weight: 12,
|
|
383
|
+
isStrictEvent: false,
|
|
382
384
|
properties: {
|
|
383
385
|
listing_id: () => `LST-${chance.integer({ min: 10000, max: 99999 })}`,
|
|
384
386
|
listing_price: u.weighNumRange(150000, 1500000, 0.4, 60),
|
|
@@ -422,6 +424,7 @@ const config = {
|
|
|
422
424
|
{
|
|
423
425
|
event: "tour scheduled",
|
|
424
426
|
weight: 4,
|
|
427
|
+
isStrictEvent: false,
|
|
425
428
|
properties: {
|
|
426
429
|
listing_id: () => `LST-${chance.integer({ min: 10000, max: 99999 })}`,
|
|
427
430
|
agent_id: () => `AGT-${chance.integer({ min: 1000, max: 9999 })}`,
|
|
@@ -440,6 +443,7 @@ const config = {
|
|
|
440
443
|
{
|
|
441
444
|
event: "offer submitted",
|
|
442
445
|
weight: 2,
|
|
446
|
+
isStrictEvent: false,
|
|
443
447
|
properties: {
|
|
444
448
|
listing_id: () => `LST-${chance.integer({ min: 10000, max: 99999 })}`,
|
|
445
449
|
offer_price: u.weighNumRange(200000, 1500000, 0.4, 40),
|
|
@@ -465,6 +469,7 @@ const config = {
|
|
|
465
469
|
{
|
|
466
470
|
event: "property listed",
|
|
467
471
|
weight: 3,
|
|
472
|
+
isStrictEvent: false,
|
|
468
473
|
properties: {
|
|
469
474
|
listing_price: u.weighNumRange(200000, 1500000, 0.4, 50),
|
|
470
475
|
property_type: ["Single Family", "Condo", "Townhouse", "Multi-Family"],
|
|
@@ -475,6 +480,7 @@ const config = {
|
|
|
475
480
|
{
|
|
476
481
|
event: "property sold",
|
|
477
482
|
weight: 1,
|
|
483
|
+
isStrictEvent: false,
|
|
478
484
|
properties: {
|
|
479
485
|
sale_price: u.weighNumRange(200000, 1500000, 0.4, 40),
|
|
480
486
|
days_on_market: u.weighNumRange(5, 180, 0.4, 30),
|
|
@@ -568,6 +568,7 @@ const config = {
|
|
|
568
568
|
{
|
|
569
569
|
event: "service deployed",
|
|
570
570
|
weight: 10,
|
|
571
|
+
isStrictEvent: false,
|
|
571
572
|
properties: {
|
|
572
573
|
service_id: serviceIds,
|
|
573
574
|
service_type: ["web_app", "api", "database", "cache", "queue", "ml_model"],
|
|
@@ -578,6 +579,7 @@ const config = {
|
|
|
578
579
|
{
|
|
579
580
|
event: "dashboard viewed",
|
|
580
581
|
weight: 20,
|
|
582
|
+
isStrictEvent: false,
|
|
581
583
|
properties: {
|
|
582
584
|
dashboard_type: ["overview", "cost", "performance", "security", "custom"],
|
|
583
585
|
time_range: ["1h", "6h", "24h", "7d", "30d"],
|
|
@@ -586,6 +588,7 @@ const config = {
|
|
|
586
588
|
{
|
|
587
589
|
event: "alert triggered",
|
|
588
590
|
weight: 12,
|
|
591
|
+
isStrictEvent: false,
|
|
589
592
|
properties: {
|
|
590
593
|
alert_id: alertIds,
|
|
591
594
|
severity: ["info", "warning", "critical", "emergency"],
|
|
@@ -609,6 +612,7 @@ const config = {
|
|
|
609
612
|
{
|
|
610
613
|
event: "alert acknowledged",
|
|
611
614
|
weight: 8,
|
|
615
|
+
isStrictEvent: false,
|
|
612
616
|
properties: {
|
|
613
617
|
alert_id: alertIds,
|
|
614
618
|
response_time_mins: u.weighNumRange(1, 120),
|
|
@@ -618,6 +622,7 @@ const config = {
|
|
|
618
622
|
{
|
|
619
623
|
event: "alert resolved",
|
|
620
624
|
weight: 7,
|
|
625
|
+
isStrictEvent: false,
|
|
621
626
|
properties: {
|
|
622
627
|
alert_id: alertIds,
|
|
623
628
|
resolution_time_mins: u.weighNumRange(5, 1440),
|
|
@@ -627,6 +632,7 @@ const config = {
|
|
|
627
632
|
{
|
|
628
633
|
event: "deployment pipeline run",
|
|
629
634
|
weight: 9,
|
|
635
|
+
isStrictEvent: false,
|
|
630
636
|
properties: {
|
|
631
637
|
pipeline_id: pipelineIds,
|
|
632
638
|
status: ["success", "failed", "cancelled"],
|
|
@@ -637,6 +643,7 @@ const config = {
|
|
|
637
643
|
{
|
|
638
644
|
event: "infrastructure scaled",
|
|
639
645
|
weight: 5,
|
|
646
|
+
isStrictEvent: false,
|
|
640
647
|
properties: {
|
|
641
648
|
service_id: serviceIds,
|
|
642
649
|
scale_direction: ["up", "up", "up", "down"],
|
|
@@ -648,6 +655,7 @@ const config = {
|
|
|
648
655
|
{
|
|
649
656
|
event: "cost report generated",
|
|
650
657
|
weight: 4,
|
|
658
|
+
isStrictEvent: false,
|
|
651
659
|
properties: {
|
|
652
660
|
report_period: ["daily", "weekly", "monthly"],
|
|
653
661
|
total_cost: u.weighNumRange(100, 50000),
|
|
@@ -657,6 +665,7 @@ const config = {
|
|
|
657
665
|
{
|
|
658
666
|
event: "team member invited",
|
|
659
667
|
weight: 3,
|
|
668
|
+
isStrictEvent: false,
|
|
660
669
|
properties: {
|
|
661
670
|
role: ["admin", "editor", "viewer", "billing"],
|
|
662
671
|
invitation_method: ["email", "sso", "slack"],
|
|
@@ -665,6 +674,7 @@ const config = {
|
|
|
665
674
|
{
|
|
666
675
|
event: "integration configured",
|
|
667
676
|
weight: 4,
|
|
677
|
+
isStrictEvent: false,
|
|
668
678
|
properties: {
|
|
669
679
|
integration_type: ["slack", "pagerduty", "jira", "github", "datadog", "terraform"],
|
|
670
680
|
status: ["active", "paused", "error"],
|
|
@@ -691,6 +701,7 @@ const config = {
|
|
|
691
701
|
{
|
|
692
702
|
event: "billing event",
|
|
693
703
|
weight: 3,
|
|
704
|
+
isStrictEvent: false,
|
|
694
705
|
properties: {
|
|
695
706
|
event_type: ["invoice_generated", "invoice_generated", "payment_received", "payment_received", "payment_received", "payment_failed", "plan_upgraded", "plan_downgraded"],
|
|
696
707
|
amount: u.weighNumRange(99, 25000),
|
|
@@ -718,6 +729,7 @@ const config = {
|
|
|
718
729
|
{
|
|
719
730
|
event: "documentation viewed",
|
|
720
731
|
weight: 7,
|
|
732
|
+
isStrictEvent: false,
|
|
721
733
|
properties: {
|
|
722
734
|
doc_section: ["getting_started", "api_reference", "best_practices", "troubleshooting", "changelog"],
|
|
723
735
|
time_on_page_sec: u.weighNumRange(5, 600),
|
|
@@ -415,6 +415,7 @@ const config = {
|
|
|
415
415
|
{
|
|
416
416
|
event: "post created",
|
|
417
417
|
weight: 12,
|
|
418
|
+
isStrictEvent: false,
|
|
418
419
|
properties: {
|
|
419
420
|
"post_type": ["text", "image", "video", "poll", "link"],
|
|
420
421
|
"character_count": u.weighNumRange(1, 280),
|
|
@@ -425,6 +426,7 @@ const config = {
|
|
|
425
426
|
{
|
|
426
427
|
event: "post viewed",
|
|
427
428
|
weight: 30,
|
|
429
|
+
isStrictEvent: false,
|
|
428
430
|
properties: {
|
|
429
431
|
"post_type": ["text", "image", "video", "poll", "link"],
|
|
430
432
|
"view_duration_sec": u.weighNumRange(1, 120, 0.3, 5),
|
|
@@ -434,6 +436,7 @@ const config = {
|
|
|
434
436
|
{
|
|
435
437
|
event: "post liked",
|
|
436
438
|
weight: 18,
|
|
439
|
+
isStrictEvent: false,
|
|
437
440
|
properties: {
|
|
438
441
|
"post_type": ["text", "image", "video", "poll", "link"],
|
|
439
442
|
}
|
|
@@ -441,6 +444,7 @@ const config = {
|
|
|
441
444
|
{
|
|
442
445
|
event: "post shared",
|
|
443
446
|
weight: 6,
|
|
447
|
+
isStrictEvent: false,
|
|
444
448
|
properties: {
|
|
445
449
|
"share_destination": ["repost", "dm", "external", "copy_link"],
|
|
446
450
|
}
|
|
@@ -448,6 +452,7 @@ const config = {
|
|
|
448
452
|
{
|
|
449
453
|
event: "comment posted",
|
|
450
454
|
weight: 10,
|
|
455
|
+
isStrictEvent: false,
|
|
451
456
|
properties: {
|
|
452
457
|
"comment_length": u.weighNumRange(1, 500, 0.3, 20),
|
|
453
458
|
"has_mention": [true, false, false],
|
|
@@ -456,6 +461,7 @@ const config = {
|
|
|
456
461
|
{
|
|
457
462
|
event: "user followed",
|
|
458
463
|
weight: 8,
|
|
464
|
+
isStrictEvent: false,
|
|
459
465
|
properties: {
|
|
460
466
|
"discovery_source": ["suggested", "search", "post", "profile", "mutual"],
|
|
461
467
|
}
|
|
@@ -470,6 +476,7 @@ const config = {
|
|
|
470
476
|
{
|
|
471
477
|
event: "story viewed",
|
|
472
478
|
weight: 15,
|
|
479
|
+
isStrictEvent: false,
|
|
473
480
|
properties: {
|
|
474
481
|
"story_type": ["photo", "video", "text"],
|
|
475
482
|
"view_duration_sec": u.weighNumRange(1, 30, 0.5, 5),
|
|
@@ -479,6 +486,7 @@ const config = {
|
|
|
479
486
|
{
|
|
480
487
|
event: "story created",
|
|
481
488
|
weight: 5,
|
|
489
|
+
isStrictEvent: false,
|
|
482
490
|
properties: {
|
|
483
491
|
"story_type": ["photo", "video", "text"],
|
|
484
492
|
"has_filter": [true, false],
|
|
@@ -504,6 +512,7 @@ const config = {
|
|
|
504
512
|
{
|
|
505
513
|
event: "dm sent",
|
|
506
514
|
weight: 8,
|
|
515
|
+
isStrictEvent: false,
|
|
507
516
|
properties: {
|
|
508
517
|
"message_type": ["text", "image", "voice", "link"],
|
|
509
518
|
"conversation_length": u.weighNumRange(1, 100),
|
|
@@ -342,6 +342,7 @@ const config = {
|
|
|
342
342
|
{
|
|
343
343
|
event: "hotel viewed",
|
|
344
344
|
weight: 7,
|
|
345
|
+
isStrictEvent: false,
|
|
345
346
|
properties: {
|
|
346
347
|
hotel_id: chance.pickone.bind(chance, hotelIds),
|
|
347
348
|
destination: chance.pickone.bind(chance, destinationCities),
|
|
@@ -364,6 +365,7 @@ const config = {
|
|
|
364
365
|
{
|
|
365
366
|
event: "booking completed",
|
|
366
367
|
weight: 3,
|
|
368
|
+
isStrictEvent: false,
|
|
367
369
|
properties: {
|
|
368
370
|
hotel_id: chance.pickone.bind(chance, hotelIds),
|
|
369
371
|
destination: chance.pickone.bind(chance, destinationCities),
|
|
@@ -379,6 +381,7 @@ const config = {
|
|
|
379
381
|
{
|
|
380
382
|
event: "room upgrade selected",
|
|
381
383
|
weight: 2,
|
|
384
|
+
isStrictEvent: false,
|
|
382
385
|
properties: {
|
|
383
386
|
upgrade_type: ["suite", "ocean_view", "executive_floor", "club_lounge", "premium_king"],
|
|
384
387
|
upgrade_cost: u.weighNumRange(25, 200, 0.4, 75),
|
|
@@ -415,6 +418,7 @@ const config = {
|
|
|
415
418
|
{
|
|
416
419
|
event: "review submitted",
|
|
417
420
|
weight: 2,
|
|
421
|
+
isStrictEvent: false,
|
|
418
422
|
properties: {
|
|
419
423
|
hotel_id: chance.pickone.bind(chance, hotelIds),
|
|
420
424
|
stay_rating: u.weighNumRange(1, 5, 0.7, 4),
|
|
@@ -504,6 +508,7 @@ const config = {
|
|
|
504
508
|
order: "sequential",
|
|
505
509
|
timeToConvert: 48,
|
|
506
510
|
weight: 5,
|
|
511
|
+
reentry: true,
|
|
507
512
|
},
|
|
508
513
|
{
|
|
509
514
|
name: "Full Stay Journey",
|
package/index.js
CHANGED
|
@@ -157,31 +157,49 @@ async function runDungeon(config) {
|
|
|
157
157
|
|
|
158
158
|
// Step 4: Generate ad spend data (if enabled)
|
|
159
159
|
if (validatedConfig.hasAdSpend) {
|
|
160
|
+
context.reportProgress({ phase: "step", step: "adspend", status: "start" });
|
|
161
|
+
const _t4 = Date.now();
|
|
160
162
|
await generateAdSpendData(context);
|
|
163
|
+
context.reportProgress({ phase: "step", step: "adspend", status: "complete", duration: Date.now() - _t4 });
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
if (context.config.verbose) logger.info('Starting user and event generation...');
|
|
164
167
|
// Step 5: Main user and event generation
|
|
168
|
+
context.reportProgress({ phase: "step", step: "users", status: "start" });
|
|
169
|
+
const _t5 = Date.now();
|
|
165
170
|
await userLoop(context);
|
|
171
|
+
context.reportProgress({ phase: "step", step: "users", status: "complete", duration: Date.now() - _t5 });
|
|
166
172
|
|
|
167
173
|
// Step 6: Generate group profiles (if configured)
|
|
168
174
|
if (validatedConfig.groupKeys && validatedConfig.groupKeys.length > 0) {
|
|
175
|
+
context.reportProgress({ phase: "step", step: "group-profiles", status: "start" });
|
|
176
|
+
const _t6 = Date.now();
|
|
169
177
|
await generateGroupProfiles(context);
|
|
178
|
+
context.reportProgress({ phase: "step", step: "group-profiles", status: "complete", duration: Date.now() - _t6 });
|
|
170
179
|
}
|
|
171
180
|
|
|
172
181
|
// Step 7: Generate group SCDs (if configured)
|
|
173
182
|
if (validatedConfig.scdProps && validatedConfig.groupKeys && validatedConfig.groupKeys.length > 0) {
|
|
183
|
+
context.reportProgress({ phase: "step", step: "group-scds", status: "start" });
|
|
184
|
+
const _t7 = Date.now();
|
|
174
185
|
await generateGroupSCDs(context);
|
|
186
|
+
context.reportProgress({ phase: "step", step: "group-scds", status: "complete", duration: Date.now() - _t7 });
|
|
175
187
|
}
|
|
176
188
|
|
|
177
189
|
// Step 8: Generate lookup tables (if configured)
|
|
178
190
|
if (validatedConfig.lookupTables && validatedConfig.lookupTables.length > 0) {
|
|
191
|
+
context.reportProgress({ phase: "step", step: "lookups", status: "start" });
|
|
192
|
+
const _t8 = Date.now();
|
|
179
193
|
await generateLookupTables(context);
|
|
194
|
+
context.reportProgress({ phase: "step", step: "lookups", status: "complete", duration: Date.now() - _t8 });
|
|
180
195
|
}
|
|
181
196
|
|
|
182
197
|
// Step 9: Generate mirror datasets (if configured)
|
|
183
198
|
if (validatedConfig.mirrorProps && Object.keys(validatedConfig.mirrorProps).length > 0) {
|
|
199
|
+
context.reportProgress({ phase: "step", step: "mirrors", status: "start" });
|
|
200
|
+
const _t9 = Date.now();
|
|
184
201
|
await makeMirror(context);
|
|
202
|
+
context.reportProgress({ phase: "step", step: "mirrors", status: "complete", duration: Date.now() - _t9 });
|
|
185
203
|
}
|
|
186
204
|
|
|
187
205
|
if (context.config.verbose) logger.info('Data generation completed successfully');
|
|
@@ -191,21 +209,38 @@ async function runDungeon(config) {
|
|
|
191
209
|
// Flush when writeToDisk is enabled OR batch mode activated (to capture tail data)
|
|
192
210
|
const shouldFlush = validatedConfig.writeToDisk || context.isBatchMode();
|
|
193
211
|
|
|
194
|
-
// Step 10: Flush
|
|
212
|
+
// Step 10-11: Flush to disk
|
|
195
213
|
if (shouldFlush) {
|
|
214
|
+
context.reportProgress({ phase: "step", step: "flush", status: "start" });
|
|
215
|
+
const _tFlush = Date.now();
|
|
196
216
|
await flushLookupTablesToDisk(storage, validatedConfig);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Step 11: Flush other storage containers to disk
|
|
200
|
-
if (shouldFlush) {
|
|
201
217
|
await flushStorageToDisk(storage, validatedConfig);
|
|
218
|
+
context.reportProgress({ phase: "step", step: "flush", status: "complete", duration: Date.now() - _tFlush });
|
|
202
219
|
}
|
|
203
220
|
|
|
204
221
|
// Step 12: Send to Mixpanel (if token provided)
|
|
205
222
|
// Now happens AFTER disk flush so batch files are available for import
|
|
206
223
|
let importResults;
|
|
207
224
|
if (validatedConfig.token) {
|
|
208
|
-
|
|
225
|
+
// Defensive guard: real Mixpanel project tokens are 32-char hex.
|
|
226
|
+
// Placeholder strings ("your-mixpanel-token", "test-token", "hello token!", etc.)
|
|
227
|
+
// trigger mixpanel-import's infinite retry loop and hang the entire
|
|
228
|
+
// process — historically a brutal source of silent test timeouts.
|
|
229
|
+
// If the token doesn't look like a real project token, warn loudly and skip the send.
|
|
230
|
+
// Set MP_BYPASS_TOKEN_CHECK=1 to override (e.g., legitimate non-standard tokens).
|
|
231
|
+
const looksReal = /^[0-9a-f]{32}$/i.test(String(validatedConfig.token).trim());
|
|
232
|
+
if (looksReal || process.env.MP_BYPASS_TOKEN_CHECK === '1') {
|
|
233
|
+
context.reportProgress({ phase: "step", step: "import", status: "start" });
|
|
234
|
+
const _t12 = Date.now();
|
|
235
|
+
importResults = await sendToMixpanel(context);
|
|
236
|
+
context.reportProgress({ phase: "step", step: "import", status: "complete", duration: Date.now() - _t12 });
|
|
237
|
+
} else {
|
|
238
|
+
console.warn(
|
|
239
|
+
`⚠️ Skipping Mixpanel import: token "${validatedConfig.token}" does not look like a real Mixpanel project token ` +
|
|
240
|
+
`(expected 32-char hex). Set a real token or pass empty string to skip. ` +
|
|
241
|
+
`Override with MP_BYPASS_TOKEN_CHECK=1 if your token is legitimately non-standard.`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
209
244
|
}
|
|
210
245
|
|
|
211
246
|
// Step 13: Compile results
|
|
@@ -214,6 +249,8 @@ async function runDungeon(config) {
|
|
|
214
249
|
|
|
215
250
|
const extractedData = extractStorageData(storage);
|
|
216
251
|
|
|
252
|
+
const progressSummary = context.getProgressSummary();
|
|
253
|
+
|
|
217
254
|
return {
|
|
218
255
|
...extractedData,
|
|
219
256
|
importResults,
|
|
@@ -221,7 +258,8 @@ async function runDungeon(config) {
|
|
|
221
258
|
time: { start, end, delta, human },
|
|
222
259
|
operations: context.getOperations(),
|
|
223
260
|
eventCount: context.getStoredEventCount(),
|
|
224
|
-
userCount: context.getUserCount()
|
|
261
|
+
userCount: context.getUserCount(),
|
|
262
|
+
...(progressSummary.updates > 0 || progressSummary.errors > 0 ? { progress: progressSummary } : {})
|
|
225
263
|
};
|
|
226
264
|
|
|
227
265
|
} catch (error) {
|