@ak--47/dungeon-master 1.4.5 → 1.5.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/.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 +182 -0
- package/HOOKS.md +1256 -597
- package/README.md +140 -5
- package/dungeons/technical/ad-spend.js +41 -49
- package/dungeons/technical/anonymous-users.js +38 -36
- package/dungeons/technical/array-of-object-lookup.js +136 -153
- package/dungeons/technical/datagen-v15-verify.js +87 -0
- package/dungeons/technical/experiments.js +42 -40
- package/dungeons/technical/foobar.js +114 -118
- package/dungeons/technical/group-analytics.js +42 -40
- package/dungeons/technical/hook-helpers-verify.js +69 -50
- package/dungeons/technical/identity-model-verify.js +22 -12
- package/dungeons/technical/mirror-strategies.js +37 -39
- package/dungeons/technical/nested-objects.js +119 -118
- package/dungeons/technical/pattern-aggregate-by-bin.js +21 -8
- package/dungeons/technical/pattern-attributed-by-source.js +23 -9
- package/dungeons/technical/pattern-frequency-by-frequency.js +21 -8
- package/dungeons/technical/pattern-funnel-frequency.js +30 -15
- package/dungeons/technical/pattern-ttc-by-segment.js +21 -8
- package/dungeons/technical/retention-cadence.js +115 -112
- package/dungeons/technical/sanity.js +86 -80
- package/dungeons/technical/scale-test.js +34 -38
- package/dungeons/technical/scd.js +111 -128
- package/dungeons/technical/simple.js +134 -141
- package/dungeons/technical/simplest.js +111 -65
- package/dungeons/technical/text-generation.js +110 -146
- package/dungeons/vertical/ai-platform.js +300 -333
- package/dungeons/vertical/community.js +290 -255
- package/dungeons/vertical/crypto.js +400 -391
- package/dungeons/vertical/dating.js +421 -375
- package/dungeons/vertical/devtools.js +346 -298
- package/dungeons/vertical/ecommerce.js +322 -394
- package/dungeons/vertical/education.js +380 -325
- package/dungeons/vertical/fintech.js +371 -325
- package/dungeons/vertical/fitness.js +345 -291
- package/dungeons/vertical/food-delivery.js +352 -307
- package/dungeons/vertical/gaming.js +490 -444
- package/dungeons/vertical/healthcare.js +311 -262
- package/dungeons/vertical/insurance-application.js +437 -409
- package/dungeons/vertical/logistics.js +278 -252
- package/dungeons/vertical/marketplace.js +340 -323
- package/dungeons/vertical/media.js +390 -335
- package/dungeons/vertical/real-estate.js +402 -347
- package/dungeons/vertical/sass.js +331 -333
- package/dungeons/vertical/social.js +377 -316
- package/dungeons/vertical/travel.js +302 -295
- package/index.js +64 -7
- package/lib/core/config-validator.js +378 -17
- package/lib/core/dungeon-loader.js +2 -5
- package/lib/generators/events.js +12 -13
- package/lib/generators/funnels.js +76 -2
- package/lib/hook-helpers/index.js +1 -0
- package/lib/hook-helpers/inject.js +95 -0
- package/lib/orchestrators/mixpanel-sender.js +7 -0
- package/lib/orchestrators/user-loop.js +598 -48
- package/lib/templates/defaults.js +59 -59
- package/lib/templates/macro-presets.js +53 -11
- package/lib/utils/dataset-context.js +103 -0
- package/lib/utils/retention-curve.js +140 -0
- package/lib/utils/utils.js +157 -109
- package/lib/verify/counting.js +360 -0
- package/lib/verify/emulate-breakdown.js +531 -108
- package/lib/verify/funnel-engine.js +539 -0
- package/lib/verify/identity.js +78 -0
- package/lib/verify/index.js +20 -0
- package/lib/verify/schema-validator.js +3 -1
- package/lib/verify/verify-dungeon.js +58 -0
- package/package.json +14 -3
- package/scripts/run-dungeon.mjs +12 -1
- package/types.d.ts +353 -4
- package/scripts/smoke-test-all.mjs +0 -162
|
@@ -1,67 +1,71 @@
|
|
|
1
|
-
// ──
|
|
1
|
+
// ── IMPORTS ──
|
|
2
|
+
import Chance from 'chance';
|
|
3
|
+
let chance = new Chance();
|
|
4
|
+
import { pickAWinner, weighNumRange, integer, weighChoices, dateRange, listOf, objectList } from "../../lib/utils/utils.js";
|
|
5
|
+
/** @typedef {import("../../types").Dungeon} Config */
|
|
6
|
+
|
|
7
|
+
// ── OVERVIEW ──
|
|
8
|
+
/*
|
|
9
|
+
* NAME: simplest
|
|
10
|
+
* PURPOSE: Engine-validation baseline — no hooks. Engine + TimeSoup alone produce the trend shape. Used by engine-shape canary + full sweep.
|
|
11
|
+
* SCALE: 2,500 users, ~250K events, 100 days
|
|
12
|
+
* EVENTS (25): page view (10) > view item (9) > view category (8) > login (8) > search (7) > notification received (7) > watch video (6) > add to cart (5) > notification clicked (5) > rate item (4) > add to wishlist (4) > checkout (3) > remove from cart (3) > update profile (3) > compare items (3) > share content (2) > support ticket (2) > apply coupon (2) > leave review (2) > sign up (1) > add payment method (1) > invite friend (1) > save address (1) > subscribe newsletter (1) > redeem reward (1)
|
|
13
|
+
* FUNNELS (11): Signup Funnel, Purchase Funnel, Content Engagement, Review Funnel, Browse to Cart, Notification Engagement, Wishlist to Purchase, Post-Purchase Advocacy, Coupon Purchase Flow, Newsletter to Purchase, Support Recovery
|
|
14
|
+
* USER PROPS: theme, title, spiritAnimal, luckyNumber, emailOptIn, signupDate, favoriteCategories, preferences, recentOrders
|
|
15
|
+
* SUPER PROPS: theme
|
|
16
|
+
* GROUPS: none
|
|
17
|
+
*
|
|
18
|
+
* USE CASES:
|
|
19
|
+
* - Engine sweep harness baseline (`scripts/sweep-engine.mjs`). Strict-bar regression
|
|
20
|
+
* testing across the 184-combo macro/born/rate/active-day matrix.
|
|
21
|
+
* - Reference for "what an average dungeon looks like" — diverse events + funnels +
|
|
22
|
+
* user props with no hook architecting on top.
|
|
23
|
+
* - Starting template for new dungeons before adding bespoke hooks.
|
|
24
|
+
* - At least one property of every Mixpanel data type:
|
|
25
|
+
* string, numeric, boolean, date, list, object, list-of-objects
|
|
26
|
+
* on both event properties and user properties.
|
|
27
|
+
* - No device/location/campaign data — pure event stream.
|
|
28
|
+
* - **No hooks.** This is the engine-validation baseline; engine + TimeSoup alone
|
|
29
|
+
* produce the trend shape. Hook authors should reach for vertical dungeons or
|
|
30
|
+
* write hooks against this template; do NOT add hooks here.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
// ── SCALE ──
|
|
2
34
|
const SEED = "simple is best";
|
|
3
35
|
const num_days = 100;
|
|
4
36
|
const num_users = 2_500;
|
|
5
37
|
const avg_events_per_user_per_day = 1;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// ── env overrides ──
|
|
9
|
-
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
-
|
|
11
|
-
import Chance from 'chance';
|
|
12
|
-
let chance = new Chance();
|
|
13
|
-
import dayjs from "dayjs";
|
|
14
|
-
import utc from "dayjs/plugin/utc.js";
|
|
15
|
-
dayjs.extend(utc);
|
|
16
|
-
import { uid, comma } from 'ak-tools';
|
|
17
|
-
import { pickAWinner, weighNumRange, date, integer, weighChoices } from "../../lib/utils/utils.js";
|
|
38
|
+
const token = process.env.MP_TOKEN || "";
|
|
18
39
|
|
|
19
|
-
|
|
40
|
+
// ── DATA ARRAYS ──
|
|
20
41
|
const itemCategories = ["Books", "Movies", "Music", "Games", "Electronics", "Computers", "Smart Home", "Home", "Garden", "Pet", "Beauty", "Health", "Toys", "Kids", "Baby", "Handmade", "Sports", "Outdoors", "Automotive", "Industrial", "Entertainment", "Art", "Food", "Appliances", "Office", "Wedding", "Software"];
|
|
21
42
|
|
|
22
43
|
const videoCategories = ["funny", "educational", "inspirational", "music", "news", "sports", "cooking", "DIY", "travel", "gaming"];
|
|
23
44
|
|
|
24
|
-
|
|
25
|
-
* ═══════════════════════════════════════════════════════════════
|
|
26
|
-
* DATASET OVERVIEW
|
|
27
|
-
* ═══════════════════════════════════════════════════════════════
|
|
28
|
-
*
|
|
29
|
-
* Simplest E-Commerce App — the minimal dungeon with no hooks.
|
|
30
|
-
* - 2,500 users over 100 days, ~250K events
|
|
31
|
-
* - 25 event types covering browse, search, cart, checkout,
|
|
32
|
-
* notifications, reviews, wishlists, rewards
|
|
33
|
-
* - 11 funnels (signup, purchase, content, browse-to-cart, etc.)
|
|
34
|
-
* - No device/location/campaign data — pure event stream
|
|
35
|
-
*
|
|
36
|
-
* ═══════════════════════════════════════════════════════════════
|
|
37
|
-
* ANALYTICS HOOKS
|
|
38
|
-
* ═══════════════════════════════════════════════════════════════
|
|
39
|
-
*
|
|
40
|
-
* None — this is a baseline dungeon with a no-op hook function.
|
|
41
|
-
* Use it for testing core generation, funnel inference, or as a
|
|
42
|
-
* starting template for new dungeons.
|
|
43
|
-
*/
|
|
44
|
-
|
|
45
|
+
// ── CONFIG ──
|
|
45
46
|
/** @type {import('../types.js').Dungeon} */
|
|
46
47
|
const config = {
|
|
47
|
-
token,
|
|
48
48
|
seed: SEED,
|
|
49
49
|
numDays: num_days,
|
|
50
50
|
avgEventsPerUserPerDay: avg_events_per_user_per_day,
|
|
51
51
|
numUsers: num_users,
|
|
52
52
|
format: 'json', //csv or json
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
credentials: {
|
|
54
|
+
token,
|
|
55
|
+
region: "US",
|
|
56
|
+
},
|
|
57
|
+
switches: {
|
|
58
|
+
hasSessionIds: false, //if true, hasSessionIds are created for each user
|
|
59
|
+
hasAdSpend: false,
|
|
60
|
+
hasLocation: false,
|
|
61
|
+
hasAndroidDevices: false,
|
|
62
|
+
hasIOSDevices: false,
|
|
63
|
+
hasDesktopDevices: false,
|
|
64
|
+
hasBrowser: false,
|
|
65
|
+
hasCampaigns: false,
|
|
66
|
+
isAnonymous: false,
|
|
67
|
+
alsoInferFunnels: false,
|
|
68
|
+
},
|
|
65
69
|
concurrency: 1,
|
|
66
70
|
writeToDisk: false,
|
|
67
71
|
|
|
@@ -69,6 +73,7 @@ const config = {
|
|
|
69
73
|
{
|
|
70
74
|
event: "page view",
|
|
71
75
|
weight: 10,
|
|
76
|
+
isStrictEvent: false,
|
|
72
77
|
properties: {
|
|
73
78
|
page: ["/", "/", "/help", "/account", "/pricing", "/product", "/about", "/blog"],
|
|
74
79
|
utm_source: ["$organic", "$organic", "$organic", "$organic", "google", "google", "google", "facebook", "facebook", "twitter", "linkedin"],
|
|
@@ -77,6 +82,7 @@ const config = {
|
|
|
77
82
|
{
|
|
78
83
|
event: "sign up",
|
|
79
84
|
weight: 1,
|
|
85
|
+
isStrictEvent: false,
|
|
80
86
|
isFirstEvent: true,
|
|
81
87
|
properties: {
|
|
82
88
|
signupMethod: ["email", "google", "facebook", "github"],
|
|
@@ -86,6 +92,7 @@ const config = {
|
|
|
86
92
|
{
|
|
87
93
|
event: "login",
|
|
88
94
|
weight: 8,
|
|
95
|
+
isStrictEvent: false,
|
|
89
96
|
properties: {
|
|
90
97
|
method: ["password", "google", "facebook", "github"],
|
|
91
98
|
}
|
|
@@ -93,6 +100,7 @@ const config = {
|
|
|
93
100
|
{
|
|
94
101
|
event: "search",
|
|
95
102
|
weight: 7,
|
|
103
|
+
isStrictEvent: false,
|
|
96
104
|
properties: {
|
|
97
105
|
query_length: weighNumRange(1, 50),
|
|
98
106
|
resultsReturned: weighNumRange(0, 100, .25),
|
|
@@ -102,16 +110,22 @@ const config = {
|
|
|
102
110
|
{
|
|
103
111
|
event: "view item",
|
|
104
112
|
weight: 9,
|
|
113
|
+
isStrictEvent: false,
|
|
105
114
|
properties: {
|
|
106
115
|
isFeaturedItem: [true, false, false],
|
|
107
116
|
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
108
117
|
price: weighNumRange(5, 500, .25),
|
|
109
118
|
rating: weighNumRange(1, 5),
|
|
119
|
+
// list (array of strings) — Mixpanel "List" property type
|
|
120
|
+
tags: listOf(["new", "sale", "limited", "popular", "trending", "exclusive", "clearance", "preorder"], { min: 1, max: 3 }),
|
|
121
|
+
// date — Mixpanel "Date" property type, default ISO string
|
|
122
|
+
lastRestockedAt: dateRange(),
|
|
110
123
|
}
|
|
111
124
|
},
|
|
112
125
|
{
|
|
113
126
|
event: "add to cart",
|
|
114
127
|
weight: 5,
|
|
128
|
+
isStrictEvent: false,
|
|
115
129
|
properties: {
|
|
116
130
|
amount: weighNumRange(5, 500, .25),
|
|
117
131
|
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
@@ -121,16 +135,27 @@ const config = {
|
|
|
121
135
|
{
|
|
122
136
|
event: "checkout",
|
|
123
137
|
weight: 3,
|
|
138
|
+
isStrictEvent: false,
|
|
124
139
|
properties: {
|
|
125
140
|
amount: weighNumRange(10, 500, .25),
|
|
126
141
|
currency: ["USD", "CAD", "EUR", "JPY"],
|
|
127
142
|
coupon: weighChoices(["none", "none", "none", "none", "10%OFF", "20%OFF", "30%OFF"]),
|
|
128
143
|
numItems: weighNumRange(1, 10),
|
|
144
|
+
// object — Mixpanel "Object" property type (plain object, returned as-is)
|
|
145
|
+
billingAddress: { country: "US", region: "CA", postalCode: "94016" },
|
|
146
|
+
// list of objects — Mixpanel "List of Objects" property type
|
|
147
|
+
lineItems: objectList({
|
|
148
|
+
sku: weighNumRange(10000, 99999),
|
|
149
|
+
name: pickAWinner(itemCategories, integer(0, 27)),
|
|
150
|
+
qty: [1, 1, 1, 2, 2, 3],
|
|
151
|
+
price: weighNumRange(5, 200, .25),
|
|
152
|
+
}, { min: 1, max: 5 }),
|
|
129
153
|
}
|
|
130
154
|
},
|
|
131
155
|
{
|
|
132
156
|
event: "watch video",
|
|
133
157
|
weight: 6,
|
|
158
|
+
isStrictEvent: false,
|
|
134
159
|
properties: {
|
|
135
160
|
videoCategory: pickAWinner(videoCategories, integer(0, 9)),
|
|
136
161
|
watchTimeSec: weighNumRange(10, 600, .25),
|
|
@@ -140,6 +165,7 @@ const config = {
|
|
|
140
165
|
{
|
|
141
166
|
event: "share content",
|
|
142
167
|
weight: 2,
|
|
168
|
+
isStrictEvent: false,
|
|
143
169
|
properties: {
|
|
144
170
|
platform: ["twitter", "facebook", "linkedin", "email", "link"],
|
|
145
171
|
contentType: ["video", "product", "article"],
|
|
@@ -148,6 +174,7 @@ const config = {
|
|
|
148
174
|
{
|
|
149
175
|
event: "rate item",
|
|
150
176
|
weight: 4,
|
|
177
|
+
isStrictEvent: false,
|
|
151
178
|
properties: {
|
|
152
179
|
rating: weighNumRange(1, 5),
|
|
153
180
|
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
@@ -160,6 +187,7 @@ const config = {
|
|
|
160
187
|
{
|
|
161
188
|
event: "support ticket",
|
|
162
189
|
weight: 2,
|
|
190
|
+
isStrictEvent: false,
|
|
163
191
|
properties: {
|
|
164
192
|
priority: weighChoices(["low", "low", "medium", "medium", "medium", "high"]),
|
|
165
193
|
category: ["billing", "technical", "account", "shipping", "returns"],
|
|
@@ -168,6 +196,7 @@ const config = {
|
|
|
168
196
|
{
|
|
169
197
|
event: "add to wishlist",
|
|
170
198
|
weight: 4,
|
|
199
|
+
isStrictEvent: false,
|
|
171
200
|
properties: {
|
|
172
201
|
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
173
202
|
price: weighNumRange(5, 500, .25),
|
|
@@ -176,6 +205,7 @@ const config = {
|
|
|
176
205
|
{
|
|
177
206
|
event: "remove from cart",
|
|
178
207
|
weight: 3,
|
|
208
|
+
isStrictEvent: false,
|
|
179
209
|
properties: {
|
|
180
210
|
reason: weighChoices(["changed mind", "too expensive", "found better", "duplicate", "changed mind", "changed mind"]),
|
|
181
211
|
}
|
|
@@ -183,6 +213,7 @@ const config = {
|
|
|
183
213
|
{
|
|
184
214
|
event: "apply coupon",
|
|
185
215
|
weight: 2,
|
|
216
|
+
isStrictEvent: false,
|
|
186
217
|
properties: {
|
|
187
218
|
couponCode: weighChoices(["SAVE10", "SAVE20", "WELCOME", "FREESHIP", "VIP30", "SAVE10", "SAVE10"]),
|
|
188
219
|
discountPercent: weighNumRange(5, 50),
|
|
@@ -191,6 +222,7 @@ const config = {
|
|
|
191
222
|
{
|
|
192
223
|
event: "notification received",
|
|
193
224
|
weight: 7,
|
|
225
|
+
isStrictEvent: false,
|
|
194
226
|
properties: {
|
|
195
227
|
channel: ["push", "email", "in-app", "sms"],
|
|
196
228
|
type: ["promo", "order update", "recommendation", "reminder"],
|
|
@@ -199,6 +231,7 @@ const config = {
|
|
|
199
231
|
{
|
|
200
232
|
event: "notification clicked",
|
|
201
233
|
weight: 5,
|
|
234
|
+
isStrictEvent: false,
|
|
202
235
|
properties: {
|
|
203
236
|
channel: ["push", "email", "in-app", "sms"],
|
|
204
237
|
type: ["promo", "order update", "recommendation", "reminder"],
|
|
@@ -207,6 +240,7 @@ const config = {
|
|
|
207
240
|
{
|
|
208
241
|
event: "add payment method",
|
|
209
242
|
weight: 1,
|
|
243
|
+
isStrictEvent: false,
|
|
210
244
|
properties: {
|
|
211
245
|
type: ["credit card", "debit card", "paypal", "apple pay", "google pay"],
|
|
212
246
|
}
|
|
@@ -214,6 +248,7 @@ const config = {
|
|
|
214
248
|
{
|
|
215
249
|
event: "update profile",
|
|
216
250
|
weight: 3,
|
|
251
|
+
isStrictEvent: false,
|
|
217
252
|
properties: {
|
|
218
253
|
field: ["avatar", "name", "email", "address", "phone", "preferences"],
|
|
219
254
|
}
|
|
@@ -221,6 +256,7 @@ const config = {
|
|
|
221
256
|
{
|
|
222
257
|
event: "invite friend",
|
|
223
258
|
weight: 1,
|
|
259
|
+
isStrictEvent: false,
|
|
224
260
|
properties: {
|
|
225
261
|
method: ["email", "link", "sms"],
|
|
226
262
|
}
|
|
@@ -228,6 +264,7 @@ const config = {
|
|
|
228
264
|
{
|
|
229
265
|
event: "view category",
|
|
230
266
|
weight: 8,
|
|
267
|
+
isStrictEvent: false,
|
|
231
268
|
properties: {
|
|
232
269
|
category: pickAWinner(itemCategories, integer(0, 27)),
|
|
233
270
|
sortBy: ["popular", "newest", "price low", "price high", "rating"],
|
|
@@ -236,6 +273,7 @@ const config = {
|
|
|
236
273
|
{
|
|
237
274
|
event: "save address",
|
|
238
275
|
weight: 1,
|
|
276
|
+
isStrictEvent: false,
|
|
239
277
|
properties: {
|
|
240
278
|
type: ["home", "work", "other"],
|
|
241
279
|
}
|
|
@@ -243,6 +281,7 @@ const config = {
|
|
|
243
281
|
{
|
|
244
282
|
event: "compare items",
|
|
245
283
|
weight: 3,
|
|
284
|
+
isStrictEvent: false,
|
|
246
285
|
properties: {
|
|
247
286
|
numItems: weighNumRange(2, 5),
|
|
248
287
|
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
@@ -251,6 +290,7 @@ const config = {
|
|
|
251
290
|
{
|
|
252
291
|
event: "subscribe newsletter",
|
|
253
292
|
weight: 1,
|
|
293
|
+
isStrictEvent: false,
|
|
254
294
|
properties: {
|
|
255
295
|
frequency: ["daily", "weekly", "monthly"],
|
|
256
296
|
topics: ["deals", "new arrivals", "recommendations", "deals", "deals"],
|
|
@@ -259,6 +299,7 @@ const config = {
|
|
|
259
299
|
{
|
|
260
300
|
event: "leave review",
|
|
261
301
|
weight: 2,
|
|
302
|
+
isStrictEvent: false,
|
|
262
303
|
properties: {
|
|
263
304
|
rating: weighNumRange(1, 5),
|
|
264
305
|
wordCount: weighNumRange(10, 200, .25),
|
|
@@ -268,6 +309,7 @@ const config = {
|
|
|
268
309
|
{
|
|
269
310
|
event: "redeem reward",
|
|
270
311
|
weight: 1,
|
|
312
|
+
isStrictEvent: false,
|
|
271
313
|
properties: {
|
|
272
314
|
rewardType: ["discount", "free shipping", "free item", "points bonus"],
|
|
273
315
|
pointsUsed: weighNumRange(100, 5000, .25),
|
|
@@ -375,35 +417,39 @@ const config = {
|
|
|
375
417
|
each key should be an array or function reference
|
|
376
418
|
*/
|
|
377
419
|
userProps: {
|
|
420
|
+
// string
|
|
378
421
|
theme: ["light", "dark", "custom", "light", "dark"],
|
|
379
422
|
title: chance.profession.bind(chance),
|
|
423
|
+
spiritAnimal: ["duck", "dog", "otter", "penguin", "cat", "elephant", "lion", "cheetah", "giraffe", "zebra", "rhino", "hippo", "whale", "dolphin", "shark", "octopus", "squid", "jellyfish", "starfish", "seahorse", "crab", "lobster", "shrimp", "clam", "snail", "slug", "butterfly", "moth", "bee", "wasp", "ant", "beetle", "ladybug", "caterpillar", "centipede", "millipede", "scorpion", "spider", "tarantula", "tick", "mite", "mosquito", "fly", "dragonfly", "damselfly", "grasshopper", "cricket", "locust", "mantis", "cockroach", "termite", "praying mantis", "walking stick", "stick bug", "leaf insect", "lacewing", "aphid", "cicada", "thrips", "psyllid", "scale insect", "whitefly", "mealybug", "planthopper", "leafhopper", "treehopper", "flea", "louse", "bedbug", "flea beetle", "weevil", "longhorn beetle", "leaf beetle", "tiger beetle", "ground beetle", "lady beetle", "firefly", "click beetle", "rove beetle", "scarab beetle", "dung beetle", "stag beetle", "rhinoceros beetle", "hercules beetle", "goliath beetle", "jewel beetle", "tortoise beetle"],
|
|
424
|
+
// numeric
|
|
380
425
|
luckyNumber: weighNumRange(42, 420, .3),
|
|
381
|
-
|
|
426
|
+
// boolean
|
|
427
|
+
emailOptIn: [true, true, false],
|
|
428
|
+
// date
|
|
429
|
+
signupDate: dateRange(),
|
|
430
|
+
// list
|
|
431
|
+
favoriteCategories: listOf(itemCategories, { min: 1, max: 4 }),
|
|
432
|
+
// object
|
|
433
|
+
preferences: { notifications: true, currency: "USD", language: "en-US" },
|
|
434
|
+
// list of objects
|
|
435
|
+
recentOrders: objectList({
|
|
436
|
+
orderId: weighNumRange(100000, 999999),
|
|
437
|
+
total: weighNumRange(10, 500, .25),
|
|
438
|
+
itemCount: [1, 1, 2, 2, 3],
|
|
439
|
+
}, { min: 0, max: 3 }),
|
|
382
440
|
},
|
|
383
441
|
scdProps: {},
|
|
384
442
|
mirrorProps: {},
|
|
385
443
|
|
|
386
444
|
/*
|
|
387
|
-
for group analytics keys, we need an array of arrays [[],[],[]]
|
|
445
|
+
for group analytics keys, we need an array of arrays [[],[],[]]
|
|
388
446
|
each pair represents a group_key and the number of profiles for that key
|
|
389
447
|
*/
|
|
390
448
|
groupKeys: [],
|
|
391
449
|
groupProps: {},
|
|
392
450
|
lookupTables: [],
|
|
393
|
-
hook
|
|
394
|
-
|
|
395
|
-
if (type === "everything") {
|
|
396
|
-
const profile = meta.profile;
|
|
397
|
-
record.forEach(e => {
|
|
398
|
-
e.theme = profile.theme;
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
return record;
|
|
403
|
-
}
|
|
451
|
+
// No hook by design — this is the engine-validation baseline. Engine + TimeSoup
|
|
452
|
+
// alone produce the trend shape. To experiment with hooks, fork this file.
|
|
404
453
|
};
|
|
405
454
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
export default config;
|
|
455
|
+
export default config;
|