@ak--47/dungeon-master 1.3.0 → 1.3.1
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/dungeons/technical/array-of-object-lookup.js +0 -2
- package/dungeons/technical/simple.js +3 -4
- package/dungeons/technical/simplest-schema.json +5 -0
- package/dungeons/technical/text-generation.js +1 -1
- package/dungeons/vertical/ai-platform.js +192 -133
- package/dungeons/vertical/community.js +64 -34
- package/dungeons/vertical/crypto.js +333 -224
- package/dungeons/vertical/dating.js +228 -282
- package/dungeons/vertical/devtools.js +164 -62
- package/dungeons/vertical/ecommerce.js +240 -91
- package/dungeons/vertical/education.js +328 -310
- package/dungeons/vertical/fintech.js +437 -311
- package/dungeons/vertical/fitness.js +141 -58
- package/dungeons/vertical/food-delivery.js +298 -318
- package/dungeons/vertical/gaming.js +378 -231
- package/dungeons/vertical/healthcare.js +140 -60
- package/dungeons/vertical/insurance-application.js +168 -73
- package/dungeons/vertical/logistics.js +95 -6
- package/dungeons/vertical/marketplace.js +137 -51
- package/dungeons/vertical/media.js +241 -386
- package/dungeons/vertical/real-estate.js +322 -315
- package/dungeons/vertical/sass.js +253 -263
- package/dungeons/vertical/social.js +262 -206
- package/dungeons/vertical/travel.js +59 -16
- package/index.js +17 -17
- package/lib/core/config-validator.js +93 -21
- package/lib/core/context.js +10 -24
- package/lib/core/storage.js +6 -1
- package/lib/generators/events.js +11 -14
- package/lib/generators/funnels.js +12 -4
- package/lib/generators/mirror.js +3 -2
- package/lib/generators/product-names.js +1 -1
- package/lib/generators/scd.js +2 -1
- package/lib/generators/text.js +1 -1
- package/lib/orchestrators/user-loop.js +47 -47
- package/lib/utils/utils.js +71 -39
- package/package.json +1 -1
- package/scripts/smoke-test-all.mjs +162 -0
- package/scripts/verify-runner.mjs +72 -24
- package/types.d.ts +38 -15
- package/dungeons/technical/ad-spend-schema.json +0 -128
- package/dungeons/technical/anonymous-users-schema.json +0 -92
- package/dungeons/technical/array-of-object-lookup-schema.json +0 -191
- package/dungeons/technical/experiments-schema.json +0 -203
- package/dungeons/technical/foobar-schema.json +0 -362
- package/dungeons/technical/group-analytics-schema.json +0 -241
- package/dungeons/technical/mirror-strategies-schema.json +0 -84
- package/dungeons/technical/nested-objects-schema.json +0 -145
- package/dungeons/technical/retention-cadence-schema.json +0 -37
- package/dungeons/technical/sanity-schema.json +0 -185
- package/dungeons/technical/scale-test-schema.json +0 -70
- package/dungeons/technical/scd-schema.json +0 -467
- package/dungeons/technical/simple-schema.json +0 -362
- package/dungeons/technical/text-generation-schema.json +0 -1062
- package/dungeons/vertical/ai-platform-schema.json +0 -617
- package/dungeons/vertical/community-schema.json +0 -579
- package/dungeons/vertical/crypto-schema.json +0 -546
- package/dungeons/vertical/dating-schema.json +0 -401
- package/dungeons/vertical/devtools-schema.json +0 -601
- package/dungeons/vertical/ecommerce-schema.json +0 -604
- package/dungeons/vertical/education-schema.json +0 -5686
- package/dungeons/vertical/fintech-schema.json +0 -630
- package/dungeons/vertical/fitness-schema.json +0 -530
- package/dungeons/vertical/food-delivery-schema.json +0 -36728
- package/dungeons/vertical/gaming-schema.json +0 -2703
- package/dungeons/vertical/healthcare-schema.json +0 -549
- package/dungeons/vertical/insurance-application-schema.json +0 -485
- package/dungeons/vertical/logistics-schema.json +0 -574
- package/dungeons/vertical/marketplace-schema.json +0 -533
- package/dungeons/vertical/media-schema.json +0 -4749
- package/dungeons/vertical/real-estate-schema.json +0 -527
- package/dungeons/vertical/sass-schema.json +0 -3128
- package/dungeons/vertical/social-schema.json +0 -620
- package/dungeons/vertical/travel-schema.json +0 -580
|
@@ -16,9 +16,6 @@ import * as v from "ak-tools";
|
|
|
16
16
|
|
|
17
17
|
dayjs.extend(utc);
|
|
18
18
|
const chance = u.initChance(SEED);
|
|
19
|
-
const NOW = dayjs();
|
|
20
|
-
const DATASET_START = NOW.subtract(num_days, "days");
|
|
21
|
-
|
|
22
19
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
23
20
|
|
|
24
21
|
// Generate consistent warehouse/supplier IDs at module level
|
|
@@ -56,7 +53,12 @@ const supplierIds = v.range(1, 150).map(() => `SUP_${v.uid(6)}`);
|
|
|
56
53
|
|
|
57
54
|
/**
|
|
58
55
|
* ===================================================================
|
|
59
|
-
* ANALYTICS HOOKS (
|
|
56
|
+
* ANALYTICS HOOKS (10 hooks)
|
|
57
|
+
*
|
|
58
|
+
* Adds 10. ONBOARDING TIME-TO-CONVERT: enterprise 0.71x faster, small_business
|
|
59
|
+
* 1.3x slower (funnel-post). Discover via Onboarding funnel median TTC by company_tier.
|
|
60
|
+
* NOTE (funnel-post measurement): visible only via Mixpanel funnel median TTC.
|
|
61
|
+
* Cross-event MIN→MIN SQL queries on raw events do NOT show this.
|
|
60
62
|
* ===================================================================
|
|
61
63
|
*
|
|
62
64
|
* -------------------------------------------------------------------
|
|
@@ -123,6 +125,15 @@ const supplierIds = v.range(1, 150).map(() => `SUP_${v.uid(6)}`);
|
|
|
123
125
|
* - Breakdown: user property "company_tier"
|
|
124
126
|
* - Expected: enterprise ratio ~0.9x vs small_business baseline
|
|
125
127
|
*
|
|
128
|
+
* Report 3: Stockout-to-Inventory-Check Ratio (NORMALIZED — recommended)
|
|
129
|
+
* - Report type: Insights (formula)
|
|
130
|
+
* - A = "stockout alert" total, B = "inventory checked" total
|
|
131
|
+
* - Formula: A / B
|
|
132
|
+
* - Breakdown: user property "company_tier"
|
|
133
|
+
* - Expected: enterprise ratio ~ 0.9x SMB ratio (10% reduction visible)
|
|
134
|
+
* - WHY THIS METRIC: per-user counts are dominated by persona event multipliers
|
|
135
|
+
* (enterprise has 5x baseline activity); ratio normalizes that out.
|
|
136
|
+
*
|
|
126
137
|
* REAL-WORLD ANALOGUE: Enterprise operations have dedicated
|
|
127
138
|
* procurement teams and predictive analytics reducing stockouts.
|
|
128
139
|
*
|
|
@@ -243,6 +254,41 @@ const supplierIds = v.range(1, 150).map(() => `SUP_${v.uid(6)}`);
|
|
|
243
254
|
* REAL-WORLD ANALOGUE: Small businesses lack dedicated IT teams,
|
|
244
255
|
* leading to incomplete integration setup and lower alert adoption.
|
|
245
256
|
*
|
|
257
|
+
* -------------------------------------------------------------------
|
|
258
|
+
* 9. INVENTORY-CHECK MAGIC NUMBER (everything hook)
|
|
259
|
+
* -------------------------------------------------------------------
|
|
260
|
+
*
|
|
261
|
+
* PATTERN: Users with 5-15 "inventory checked" events sit in the
|
|
262
|
+
* "engaged-but-focused" sweet spot — every "purchase order created"
|
|
263
|
+
* event gets quantity boosted ~25%. Users with 16 or more inventory
|
|
264
|
+
* checks are over-engaged (paralysis); ~30% of their "purchase order
|
|
265
|
+
* created" events are dropped. No flag is stamped — discoverable only
|
|
266
|
+
* by binning users on inventory-check COUNT and comparing PO totals.
|
|
267
|
+
*
|
|
268
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
269
|
+
*
|
|
270
|
+
* Report 1: PO Quantity by Inventory-Check Bucket
|
|
271
|
+
* - Report type: Insights (with cohort)
|
|
272
|
+
* - Cohort A: users with 5-15 "inventory checked" events
|
|
273
|
+
* - Cohort B: users with 0-4 "inventory checked" events
|
|
274
|
+
* - Event: "purchase order created"
|
|
275
|
+
* - Measure: Average of "quantity"
|
|
276
|
+
* - Compare cohort A vs cohort B
|
|
277
|
+
* - Expected: cohort A ~ 1.25x higher quantity than B
|
|
278
|
+
*
|
|
279
|
+
* Report 2: POs per User by Browse Intensity
|
|
280
|
+
* - Report type: Insights (with cohort)
|
|
281
|
+
* - Cohort C: users with >= 16 "inventory checked" events
|
|
282
|
+
* - Cohort A: users with 5-15 "inventory checked" events
|
|
283
|
+
* - Event: "purchase order created"
|
|
284
|
+
* - Measure: Total events per user
|
|
285
|
+
* - Compare cohort C vs cohort A
|
|
286
|
+
* - Expected: cohort C has ~ 30% fewer POs per user
|
|
287
|
+
*
|
|
288
|
+
* REAL-WORLD ANALOGUE: A focused operations team that monitors
|
|
289
|
+
* stock just enough places larger, more confident orders; an
|
|
290
|
+
* obsessive checker is paralysed and orders less.
|
|
291
|
+
*
|
|
246
292
|
* ===================================================================
|
|
247
293
|
* EXPECTED METRICS SUMMARY
|
|
248
294
|
* ===================================================================
|
|
@@ -256,14 +302,18 @@ const supplierIds = v.range(1, 150).map(() => `SUP_${v.uid(6)}`);
|
|
|
256
302
|
* Alert Fatigue | response_time_hours | 4h | 8-12h | 2-3x
|
|
257
303
|
* Trial Churn | events after wk 1 | 5 | 2.5 | 0.5x
|
|
258
304
|
* Enterprise Profiles | warehouse_count | 3 | 10 | 3.3x
|
|
259
|
-
* Small-Biz Conversion Drop
|
|
305
|
+
* Small-Biz Conversion Drop | funnel conversion | 30% | 20% | 0.65x
|
|
306
|
+
* Inventory-Check Magic Num | sweet PO quantity | 1x | 1.25x | 1.25x
|
|
307
|
+
* Inventory-Check Magic Num | over POs/user | 1x | 0.7x | -30%
|
|
260
308
|
*/
|
|
261
309
|
|
|
262
310
|
/** @type {Config} */
|
|
263
311
|
const config = {
|
|
264
312
|
token,
|
|
265
313
|
seed: SEED,
|
|
266
|
-
|
|
314
|
+
datasetStart: "2026-01-01T00:00:00Z",
|
|
315
|
+
datasetEnd: "2026-04-28T23:59:59Z",
|
|
316
|
+
// numDays: num_days,
|
|
267
317
|
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
268
318
|
numUsers: num_users,
|
|
269
319
|
hasAnonIds: false,
|
|
@@ -691,6 +741,27 @@ const config = {
|
|
|
691
741
|
|
|
692
742
|
// -- Hook Function ------------------------------------------------
|
|
693
743
|
hook: function (record, type, meta) {
|
|
744
|
+
// HOOK 10 (T2C): ONBOARDING TIME-TO-CONVERT (funnel-post)
|
|
745
|
+
// Enterprise tier completes Onboarding funnel 1.4x faster (factor 0.71);
|
|
746
|
+
// small_business 1.3x slower (factor 1.3).
|
|
747
|
+
if (type === "funnel-post") {
|
|
748
|
+
const segment = meta?.profile?.company_tier;
|
|
749
|
+
if (Array.isArray(record) && record.length > 1) {
|
|
750
|
+
const factor = (
|
|
751
|
+
segment === "enterprise" ? 0.71 :
|
|
752
|
+
segment === "small_business" || segment === "trial" ? 1.3 :
|
|
753
|
+
1.0
|
|
754
|
+
);
|
|
755
|
+
if (factor !== 1.0) {
|
|
756
|
+
for (let i = 1; i < record.length; i++) {
|
|
757
|
+
const prev = dayjs(record[i - 1].time);
|
|
758
|
+
const newGap = Math.round(dayjs(record[i].time).diff(prev) * factor);
|
|
759
|
+
record[i].time = prev.add(newGap, "milliseconds").toISOString();
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
694
765
|
// -- HOOK 7: ENTERPRISE PROFILES (user) -----------------------
|
|
695
766
|
// Enterprise ops get large warehouse_count and employee_count.
|
|
696
767
|
if (type === "user") {
|
|
@@ -823,6 +894,24 @@ const config = {
|
|
|
823
894
|
}
|
|
824
895
|
}
|
|
825
896
|
|
|
897
|
+
// -- HOOK 9: INVENTORY-CHECK MAGIC NUMBER (no flags) ------
|
|
898
|
+
// Sweet 5-15 inventory checks → +25% PO quantity.
|
|
899
|
+
// Over 16+ → drop 30% of PO created events.
|
|
900
|
+
const invCheckCount = record.filter(e => e.event === 'inventory checked').length;
|
|
901
|
+
if (invCheckCount >= 5 && invCheckCount <= 15) {
|
|
902
|
+
record.forEach(e => {
|
|
903
|
+
if (e.event === 'purchase order created' && typeof e.quantity === 'number') {
|
|
904
|
+
e.quantity = Math.round(e.quantity * 1.25);
|
|
905
|
+
}
|
|
906
|
+
});
|
|
907
|
+
} else if (invCheckCount >= 16) {
|
|
908
|
+
for (let i = record.length - 1; i >= 0; i--) {
|
|
909
|
+
if (record[i].event === 'purchase order created' && chance.bool({ likelihood: 30 })) {
|
|
910
|
+
record.splice(i, 1);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
826
915
|
return record;
|
|
827
916
|
}
|
|
828
917
|
|
|
@@ -16,9 +16,6 @@ import * as v from "ak-tools";
|
|
|
16
16
|
|
|
17
17
|
dayjs.extend(utc);
|
|
18
18
|
const chance = u.initChance(SEED);
|
|
19
|
-
const NOW = dayjs();
|
|
20
|
-
const DATASET_START = NOW.subtract(num_days, "days");
|
|
21
|
-
|
|
22
19
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
23
20
|
|
|
24
21
|
// Generate consistent seller store and listing IDs at module level
|
|
@@ -56,33 +53,33 @@ const listingIds = v.range(1, 500).map(() => `LST_${v.uid(8)}`);
|
|
|
56
53
|
|
|
57
54
|
/**
|
|
58
55
|
* ═══════════════════════════════════════════════════════════════
|
|
59
|
-
* ANALYTICS HOOKS (
|
|
56
|
+
* ANALYTICS HOOKS (10 hooks)
|
|
57
|
+
*
|
|
58
|
+
* NOTE: All cohort effects are HIDDEN — no flag stamping. Discoverable via
|
|
59
|
+
* raw-prop breakdowns (segment, day, category) or behavioral cohorts.
|
|
60
|
+
*
|
|
61
|
+
* Adds 9. BROWSE TO PURCHASE TIME-TO-CONVERT and 10. MESSAGE-COUNT MAGIC
|
|
62
|
+
* NUMBER on top of original 8.
|
|
60
63
|
* ═══════════════════════════════════════════════════════════════
|
|
61
64
|
*
|
|
62
65
|
* ───────────────────────────────────────────────────────────────
|
|
63
|
-
* 1. FEE CHANGE IMPACT (
|
|
66
|
+
* 1. FEE CHANGE IMPACT (everything hook)
|
|
64
67
|
* ───────────────────────────────────────────────────────────────
|
|
65
68
|
*
|
|
66
69
|
* PATTERN: After day 45 (permanent marketplace fee increase), all
|
|
67
70
|
* "listing created" events get listing_fee multiplied by 1.3x.
|
|
68
|
-
* Simulates the revenue impact of a platform fee adjustment.
|
|
71
|
+
* Simulates the revenue impact of a platform fee adjustment. No flag —
|
|
72
|
+
* discover via line chart of avg listing_fee over time.
|
|
69
73
|
*
|
|
70
74
|
* HOW TO FIND IT IN MIXPANEL:
|
|
71
75
|
*
|
|
72
|
-
* Report 1: Listing Fee
|
|
76
|
+
* Report 1: Listing Fee Over Time
|
|
73
77
|
* • Report type: Insights
|
|
74
78
|
* • Event: "listing created"
|
|
75
79
|
* • Measure: Average of "listing_fee"
|
|
76
80
|
* • Line chart by week
|
|
77
81
|
* • Expected: Clear step-up around day 45 from ~$15 avg to ~$20 avg
|
|
78
82
|
*
|
|
79
|
-
* Report 2: Fee Change Flag Distribution
|
|
80
|
-
* • Report type: Insights
|
|
81
|
-
* • Event: "listing created"
|
|
82
|
-
* • Measure: Total
|
|
83
|
-
* • Breakdown: "fee_change"
|
|
84
|
-
* • Expected: "increased" appears only after day 45
|
|
85
|
-
*
|
|
86
83
|
* REAL-WORLD ANALOGUE: Marketplace platforms periodically adjust
|
|
87
84
|
* commission/listing fees, impacting seller economics and behavior.
|
|
88
85
|
*
|
|
@@ -238,27 +235,79 @@ const listingIds = v.range(1, 500).map(() => `LST_${v.uid(8)}`);
|
|
|
238
235
|
* REAL-WORLD ANALOGUE: Returning buyers have established trust
|
|
239
236
|
* and familiarity with the platform, converting at higher rates.
|
|
240
237
|
*
|
|
238
|
+
* ───────────────────────────────────────────────────────────────
|
|
239
|
+
* 9. BROWSE TO PURCHASE TIME-TO-CONVERT (funnel-post)
|
|
240
|
+
*
|
|
241
|
+
* PATTERN: Power_seller and frequent_buyer users complete the
|
|
242
|
+
* Browse to Purchase funnel 1.4x faster (factor 0.71); window_shopper
|
|
243
|
+
* 1.4x slower (factor 1.4).
|
|
244
|
+
*
|
|
245
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
246
|
+
*
|
|
247
|
+
* Report 1: Browse to Purchase Median Time-to-Convert by Segment
|
|
248
|
+
* - Funnels > "item searched" -> "item viewed" -> "add to cart" -> "purchase completed"
|
|
249
|
+
* - Measure: Median time to convert
|
|
250
|
+
* - Breakdown: segment
|
|
251
|
+
* - Expected: power/frequent ~ 0.71x; window ~ 1.4x
|
|
252
|
+
*
|
|
253
|
+
* NOTE (funnel-post measurement): visible only via Mixpanel funnel
|
|
254
|
+
* median TTC. Cross-event MIN→MIN SQL queries on raw events do NOT
|
|
255
|
+
* show this — funnel-post adjusts gaps within funnel instances, not
|
|
256
|
+
* across the user's full event history.
|
|
257
|
+
*
|
|
258
|
+
* ───────────────────────────────────────────────────────────────
|
|
259
|
+
* 10. MESSAGE-COUNT MAGIC NUMBER (in-funnel, everything)
|
|
260
|
+
*
|
|
261
|
+
* PATTERN: Sweet 2-5 message-sent events between item-viewed and
|
|
262
|
+
* offer-received → +35% on offer_amount of offer-received events.
|
|
263
|
+
* Over 6+ → drop 25% of purchase-completed events (haggling deadlock).
|
|
264
|
+
* No flag.
|
|
265
|
+
*
|
|
266
|
+
* HOW TO FIND IT IN MIXPANEL:
|
|
267
|
+
*
|
|
268
|
+
* Report 1: Avg Offer Amount by Message Bucket
|
|
269
|
+
* - Cohort A: users with 2-5 messages between item-viewed and offer-received
|
|
270
|
+
* - Cohort B: users with 0-1
|
|
271
|
+
* - Event: "offer received"
|
|
272
|
+
* - Measure: Average of "offer_amount"
|
|
273
|
+
* - Expected: A ~ 1.35x B
|
|
274
|
+
*
|
|
275
|
+
* Report 2: Purchase Rate on Heavy Messengers
|
|
276
|
+
* - Cohort C: users with >= 6 messages
|
|
277
|
+
* - Cohort A: users with 2-5
|
|
278
|
+
* - Event: "purchase completed"
|
|
279
|
+
* - Measure: Total per user
|
|
280
|
+
* - Expected: C ~ 25% fewer purchases per user
|
|
281
|
+
*
|
|
282
|
+
* REAL-WORLD ANALOGUE: A few quick clarifying messages close deals;
|
|
283
|
+
* extended haggling kills conversion.
|
|
284
|
+
*
|
|
241
285
|
* ═══════════════════════════════════════════════════════════════
|
|
242
286
|
* EXPECTED METRICS SUMMARY
|
|
243
287
|
* ═══════════════════════════════════════════════════════════════
|
|
244
288
|
*
|
|
245
|
-
* Hook | Metric | Baseline | Effect
|
|
246
|
-
*
|
|
247
|
-
* Fee Change Impact | listing_fee
|
|
248
|
-
* Weekend Shopping Surge | total_amount
|
|
249
|
-
* Seller Success → Trust | purchases/user |
|
|
250
|
-
* Electronics Category Lift | electronics purch. |
|
|
251
|
-
* Response Time → Conversion | offer_accepted/user |
|
|
252
|
-
* New Seller Churn | events post-
|
|
253
|
-
* Power Seller Profiles | total_transactions | 0 | 100-500
|
|
254
|
-
* Frequent Buyer Funnel | funnel conversion | 30% | 39%
|
|
289
|
+
* Hook | Metric | Baseline | Effect | Ratio
|
|
290
|
+
* ----------------------------|---------------------|----------|-----------|------
|
|
291
|
+
* Fee Change Impact | listing_fee post-D45| 1x | 1.3x | 1.3x
|
|
292
|
+
* Weekend Shopping Surge | total_amount Sat/Sun| 1x | 1.2x | 1.2x
|
|
293
|
+
* Seller Success → Trust | purchases/user | 1x | 2x | 2x
|
|
294
|
+
* Electronics Category Lift | electronics purch. | 1x | 1.5x | 1.5x
|
|
295
|
+
* Response Time → Conversion | offer_accepted/user | 1x | 2x | 2x
|
|
296
|
+
* New Seller Churn | events post-D14 | 1x | 0.6x | -40%
|
|
297
|
+
* Power Seller Profiles | total_transactions | 0 | 100-500 | --
|
|
298
|
+
* Frequent Buyer Funnel | funnel conversion | 30% | 39% | 1.3x
|
|
299
|
+
* Browse to Purchase T2C | median min by segment| 1x | 0.71/1.4x | ~ 2x range
|
|
300
|
+
* Message Magic Number | sweet offer_amount | 1x | 1.35x | 1.35x
|
|
301
|
+
* Message Magic Number | over purchases/user | 1x | 0.75x | -25%
|
|
255
302
|
*/
|
|
256
303
|
|
|
257
304
|
/** @type {Config} */
|
|
258
305
|
const config = {
|
|
259
306
|
token,
|
|
260
307
|
seed: SEED,
|
|
261
|
-
|
|
308
|
+
datasetStart: "2026-01-01T00:00:00Z",
|
|
309
|
+
datasetEnd: "2026-04-28T23:59:59Z",
|
|
310
|
+
// numDays: num_days,
|
|
262
311
|
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
263
312
|
numUsers: num_users,
|
|
264
313
|
hasAnonIds: false,
|
|
@@ -336,7 +385,6 @@ const config = {
|
|
|
336
385
|
item_count: u.weighNumRange(1, 5, 0.3),
|
|
337
386
|
payment_method: ["credit_card", "credit_card", "paypal", "apple_pay", "debit"],
|
|
338
387
|
shipping_method: ["standard", "standard", "express", "pickup"],
|
|
339
|
-
is_whale_purchase: [false],
|
|
340
388
|
},
|
|
341
389
|
},
|
|
342
390
|
{
|
|
@@ -348,7 +396,6 @@ const config = {
|
|
|
348
396
|
asking_price: u.weighNumRange(5, 500, 0.3, 50),
|
|
349
397
|
condition: ["new", "new", "like_new", "good", "fair"],
|
|
350
398
|
listing_fee: u.weighNumRange(5, 30, 0.5, 15),
|
|
351
|
-
fee_change: ["none"],
|
|
352
399
|
},
|
|
353
400
|
},
|
|
354
401
|
{
|
|
@@ -728,31 +775,34 @@ const config = {
|
|
|
728
775
|
}
|
|
729
776
|
}
|
|
730
777
|
|
|
731
|
-
//
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
778
|
+
// HOOK 9 (T2C): BROWSE TO PURCHASE TIME-TO-CONVERT (funnel-post)
|
|
779
|
+
// Power_seller users complete Browse to Purchase funnel 1.4x faster
|
|
780
|
+
// (factor 0.71); window_shopper 1.4x slower (factor 1.4).
|
|
781
|
+
if (type === "funnel-post") {
|
|
782
|
+
const segment = meta?.profile?.segment;
|
|
783
|
+
if (Array.isArray(record) && record.length > 1) {
|
|
784
|
+
const factor = (
|
|
785
|
+
segment === "power_seller" || segment === "frequent_buyer" ? 0.71 :
|
|
786
|
+
segment === "window_shopper" ? 1.4 :
|
|
787
|
+
1.0
|
|
788
|
+
);
|
|
789
|
+
if (factor !== 1.0) {
|
|
790
|
+
for (let i = 1; i < record.length; i++) {
|
|
791
|
+
const prev = dayjs(record[i - 1].time);
|
|
792
|
+
const newGap = Math.round(dayjs(record[i].time).diff(prev) * factor);
|
|
793
|
+
record[i].time = prev.add(newGap, "milliseconds").toISOString();
|
|
794
|
+
}
|
|
746
795
|
}
|
|
747
796
|
}
|
|
748
|
-
|
|
749
|
-
// ── HOOK 2: WEEKEND SHOPPING SURGE ───────────────
|
|
750
|
-
// Moved to the everything hook (after purchase cloning)
|
|
751
|
-
// so the 1.2x boost applies to both original AND cloned purchases.
|
|
752
797
|
}
|
|
753
798
|
|
|
799
|
+
// HOOK 1: FEE CHANGE IMPACT — moved to everything hook below.
|
|
800
|
+
// (event hook fires before bunchIntoSessions reshuffles timestamps)
|
|
801
|
+
|
|
754
802
|
// ── EVERYTHING HOOKS ─────────────────────────────────
|
|
755
803
|
if (type === "everything") {
|
|
804
|
+
const datasetStart = dayjs.unix(meta.datasetStart);
|
|
805
|
+
const FEE_CHANGE_DAY = datasetStart.add(45, "days");
|
|
756
806
|
let events = record;
|
|
757
807
|
if (!events.length) return record;
|
|
758
808
|
|
|
@@ -767,6 +817,14 @@ const config = {
|
|
|
767
817
|
});
|
|
768
818
|
}
|
|
769
819
|
|
|
820
|
+
// HOOK 1: FEE CHANGE IMPACT — listings after d45 get listing_fee 1.3x.
|
|
821
|
+
// In everything hook so timestamp comparison sees post-bunchIntoSessions times.
|
|
822
|
+
events.forEach(e => {
|
|
823
|
+
if (e.event === "listing created" && dayjs(e.time).isAfter(FEE_CHANGE_DAY)) {
|
|
824
|
+
e.listing_fee = Math.floor((e.listing_fee || 15) * 1.3);
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
|
|
770
828
|
// ── HOOK 8: FREQUENT BUYER CONVERSION FILTER ────
|
|
771
829
|
// Non-frequent-buyer users drop ~25% of "purchase completed"
|
|
772
830
|
// (last step of Browse to Purchase funnel) to simulate lower conversion.
|
|
@@ -851,7 +909,7 @@ const config = {
|
|
|
851
909
|
// ── HOOK 6: NEW SELLER CHURN ─────────────────────
|
|
852
910
|
// New sellers with <10 events lose 40% of events after day 14.
|
|
853
911
|
if (profile && profile.segment === "new_seller" && events.length < 10) {
|
|
854
|
-
const DAY_14 =
|
|
912
|
+
const DAY_14 = datasetStart.add(14, "days");
|
|
855
913
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
856
914
|
const eventTime = dayjs(events[i].time);
|
|
857
915
|
if (eventTime.isAfter(DAY_14) && chance.bool({ likelihood: 40 })) {
|
|
@@ -860,19 +918,47 @@ const config = {
|
|
|
860
918
|
}
|
|
861
919
|
}
|
|
862
920
|
|
|
863
|
-
//
|
|
864
|
-
//
|
|
865
|
-
// 1.2x boost hits both original and injected purchases.
|
|
921
|
+
// HOOK 2: WEEKEND SHOPPING SURGE — Sat/Sun purchases get
|
|
922
|
+
// total_amount 1.2x. Mutates raw prop. No flag.
|
|
866
923
|
events.forEach(e => {
|
|
867
924
|
if (e.event === "purchase completed") {
|
|
868
925
|
const dow = new Date(e.time).getUTCDay();
|
|
869
|
-
// Saturday=6, Sunday=0
|
|
870
926
|
if (dow === 0 || dow === 6) {
|
|
871
927
|
e.total_amount = Math.floor((e.total_amount || 60) * 1.2);
|
|
872
928
|
}
|
|
873
929
|
}
|
|
874
930
|
});
|
|
875
931
|
|
|
932
|
+
// HOOK 10: MESSAGE-COUNT MAGIC NUMBER (in-funnel, no flags)
|
|
933
|
+
// Sweet 2-5 message-sent events between item-viewed and
|
|
934
|
+
// offer-received → +35% on offer-received offer_amount/asking_price.
|
|
935
|
+
// Over 6+ → drop 25% of purchase-completed events (over-message
|
|
936
|
+
// signals haggling deadlock).
|
|
937
|
+
const itemViewed = events.find(e => e.event === "item viewed");
|
|
938
|
+
const offerReceived = events.find(e => e.event === "offer received");
|
|
939
|
+
if (itemViewed && offerReceived) {
|
|
940
|
+
const aTime = dayjs(itemViewed.time);
|
|
941
|
+
const bTime = dayjs(offerReceived.time);
|
|
942
|
+
const msgBetween = events.filter(e =>
|
|
943
|
+
e.event === "message sent" &&
|
|
944
|
+
dayjs(e.time).isAfter(aTime) &&
|
|
945
|
+
dayjs(e.time).isBefore(bTime)
|
|
946
|
+
).length;
|
|
947
|
+
if (msgBetween >= 2 && msgBetween <= 5) {
|
|
948
|
+
events.forEach(e => {
|
|
949
|
+
if (e.event === "offer received" && typeof e.offer_amount === "number") {
|
|
950
|
+
e.offer_amount = Math.round(e.offer_amount * 1.35);
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
} else if (msgBetween >= 6) {
|
|
954
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
955
|
+
if (events[i].event === "purchase completed" && chance.bool({ likelihood: 25 })) {
|
|
956
|
+
events.splice(i, 1);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
876
962
|
return record;
|
|
877
963
|
}
|
|
878
964
|
|