@ak--47/dungeon-master 1.5.0 → 1.5.2
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/create-dungeon/SKILL.md +139 -46
- package/.claude/skills/verify-dungeon/references/counting-semantics.md +31 -6
- package/.claude/skills/verify-dungeon/references/sql-recipes.md +44 -25
- package/.claude/skills/write-hooks/SKILL.md +31 -3
- package/CHANGELOG.md +85 -0
- package/HOOKS.md +13 -0
- 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 +24 -11
- 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 +54 -62
- package/dungeons/technical/text-generation.js +110 -146
- package/dungeons/vertical/ai-platform.js +296 -333
- package/dungeons/vertical/community.js +284 -255
- package/dungeons/vertical/crypto.js +395 -391
- package/dungeons/vertical/dating.js +411 -378
- package/dungeons/vertical/devtools.js +336 -298
- package/dungeons/vertical/ecommerce.js +316 -394
- package/dungeons/vertical/education.js +369 -325
- package/dungeons/vertical/fintech.js +358 -325
- package/dungeons/vertical/fitness.js +335 -291
- package/dungeons/vertical/food-delivery.js +343 -307
- package/dungeons/vertical/gaming.js +480 -444
- package/dungeons/vertical/healthcare.js +306 -262
- package/dungeons/vertical/insurance-application.js +427 -409
- package/dungeons/vertical/logistics.js +271 -252
- package/dungeons/vertical/marketplace.js +333 -323
- package/dungeons/vertical/media.js +382 -335
- package/dungeons/vertical/real-estate.js +395 -346
- package/dungeons/vertical/sass.js +319 -333
- package/dungeons/vertical/social.js +368 -316
- package/dungeons/vertical/travel.js +297 -295
- package/index.js +46 -4
- package/lib/core/config-validator.js +126 -28
- package/lib/generators/funnels.js +4 -1
- package/lib/orchestrators/mixpanel-sender.js +7 -0
- package/lib/orchestrators/user-loop.js +132 -31
- package/lib/templates/defaults.js +59 -59
- package/lib/templates/macro-presets.js +14 -2
- package/lib/utils/dataset-context.js +103 -0
- package/lib/utils/retention-curve.js +140 -0
- package/lib/utils/utils.js +149 -38
- package/lib/verify/counting.js +40 -0
- package/lib/verify/emulate-breakdown.js +20 -1
- package/lib/verify/index.js +1 -0
- package/lib/verify/schema-validator.js +3 -1
- package/package.json +11 -2
- package/scripts/run-dungeon.mjs +12 -1
- package/types.d.ts +117 -1
|
@@ -128,7 +128,7 @@ const iosDevices = [
|
|
|
128
128
|
screen_height: '2868',
|
|
129
129
|
screen_width: '1320',
|
|
130
130
|
os: 'iOS',
|
|
131
|
-
Platform: 'iOS',
|
|
131
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
132
132
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible'],
|
|
133
133
|
radio: ['4G', 'LTE', '5G', '5G mmWave', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
134
134
|
}, {
|
|
@@ -136,7 +136,7 @@ const iosDevices = [
|
|
|
136
136
|
screen_height: '2868',
|
|
137
137
|
screen_width: '1320',
|
|
138
138
|
os: 'iOS',
|
|
139
|
-
Platform: 'iOS',
|
|
139
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
140
140
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible'],
|
|
141
141
|
radio: ['4G', 'LTE', '5G', '5G mmWave', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
142
142
|
}, {
|
|
@@ -144,7 +144,7 @@ const iosDevices = [
|
|
|
144
144
|
screen_height: '2796',
|
|
145
145
|
screen_width: '1290',
|
|
146
146
|
os: 'iOS',
|
|
147
|
-
Platform: 'iOS',
|
|
147
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
148
148
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible'],
|
|
149
149
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
150
150
|
}, {
|
|
@@ -152,7 +152,7 @@ const iosDevices = [
|
|
|
152
152
|
screen_height: '2556',
|
|
153
153
|
screen_width: '1179',
|
|
154
154
|
os: 'iOS',
|
|
155
|
-
Platform: 'iOS',
|
|
155
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
156
156
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible'],
|
|
157
157
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
158
158
|
},
|
|
@@ -163,7 +163,7 @@ const iosDevices = [
|
|
|
163
163
|
screen_height: '2796',
|
|
164
164
|
screen_width: '1290',
|
|
165
165
|
os: 'iOS',
|
|
166
|
-
Platform: 'iOS',
|
|
166
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
167
167
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile'],
|
|
168
168
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
169
169
|
}, {
|
|
@@ -171,7 +171,7 @@ const iosDevices = [
|
|
|
171
171
|
screen_height: '2556',
|
|
172
172
|
screen_width: '1179',
|
|
173
173
|
os: 'iOS',
|
|
174
|
-
Platform: 'iOS',
|
|
174
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
175
175
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile'],
|
|
176
176
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
177
177
|
}, {
|
|
@@ -179,7 +179,7 @@ const iosDevices = [
|
|
|
179
179
|
screen_height: '2796',
|
|
180
180
|
screen_width: '1290',
|
|
181
181
|
os: 'iOS',
|
|
182
|
-
Platform: 'iOS',
|
|
182
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
183
183
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
184
184
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6']
|
|
185
185
|
}, {
|
|
@@ -187,7 +187,7 @@ const iosDevices = [
|
|
|
187
187
|
screen_height: '2556',
|
|
188
188
|
screen_width: '1179',
|
|
189
189
|
os: 'iOS',
|
|
190
|
-
Platform: 'iOS',
|
|
190
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
191
191
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
192
192
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6']
|
|
193
193
|
},
|
|
@@ -198,7 +198,7 @@ const iosDevices = [
|
|
|
198
198
|
screen_height: '2532',
|
|
199
199
|
screen_width: '1170',
|
|
200
200
|
os: 'iOS',
|
|
201
|
-
Platform: 'iOS',
|
|
201
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
202
202
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
203
203
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6']
|
|
204
204
|
}, {
|
|
@@ -206,7 +206,7 @@ const iosDevices = [
|
|
|
206
206
|
screen_height: '1334',
|
|
207
207
|
screen_width: '750',
|
|
208
208
|
os: 'iOS',
|
|
209
|
-
Platform: 'iOS',
|
|
209
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
210
210
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
211
211
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6']
|
|
212
212
|
},
|
|
@@ -217,7 +217,7 @@ const iosDevices = [
|
|
|
217
217
|
screen_height: '2420',
|
|
218
218
|
screen_width: '1668',
|
|
219
219
|
os: 'iPadOS',
|
|
220
|
-
Platform: 'iOS',
|
|
220
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
221
221
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
222
222
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
223
223
|
}, {
|
|
@@ -225,7 +225,7 @@ const iosDevices = [
|
|
|
225
225
|
screen_height: '2752',
|
|
226
226
|
screen_width: '2064',
|
|
227
227
|
os: 'iPadOS',
|
|
228
|
-
Platform: 'iOS',
|
|
228
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
229
229
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
230
230
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
231
231
|
},
|
|
@@ -236,7 +236,7 @@ const iosDevices = [
|
|
|
236
236
|
screen_height: '2360',
|
|
237
237
|
screen_width: '1640',
|
|
238
238
|
os: 'iPadOS',
|
|
239
|
-
Platform: 'iOS',
|
|
239
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
240
240
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
241
241
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
242
242
|
}, {
|
|
@@ -244,7 +244,7 @@ const iosDevices = [
|
|
|
244
244
|
screen_height: '2752',
|
|
245
245
|
screen_width: '2064',
|
|
246
246
|
os: 'iPadOS',
|
|
247
|
-
Platform: 'iOS',
|
|
247
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
248
248
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
249
249
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
250
250
|
},
|
|
@@ -255,7 +255,7 @@ const iosDevices = [
|
|
|
255
255
|
screen_height: '2360',
|
|
256
256
|
screen_width: '1640',
|
|
257
257
|
os: 'iPadOS',
|
|
258
|
-
Platform: 'iOS',
|
|
258
|
+
// Platform: 'iOS', // Removed in 1.5.1 — see TODO #11 (collided with dungeon-defined Platform props)
|
|
259
259
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
260
260
|
radio: ['4G', 'LTE', 'Wifi', 'WiFi6']
|
|
261
261
|
}
|
|
@@ -268,7 +268,7 @@ const androidDevices = [
|
|
|
268
268
|
screen_height: '2992',
|
|
269
269
|
screen_width: '1344',
|
|
270
270
|
os: 'Android',
|
|
271
|
-
Platform: 'Android',
|
|
271
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
272
272
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible', 'google fi'],
|
|
273
273
|
radio: ['4G', 'LTE', '5G', '5G mmWave', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
274
274
|
}, {
|
|
@@ -276,7 +276,7 @@ const androidDevices = [
|
|
|
276
276
|
screen_height: '2856',
|
|
277
277
|
screen_width: '1280',
|
|
278
278
|
os: 'Android',
|
|
279
|
-
Platform: 'Android',
|
|
279
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
280
280
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible', 'google fi'],
|
|
281
281
|
radio: ['4G', 'LTE', '5G', '5G mmWave', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
282
282
|
}, {
|
|
@@ -284,7 +284,7 @@ const androidDevices = [
|
|
|
284
284
|
screen_height: '2424',
|
|
285
285
|
screen_width: '1080',
|
|
286
286
|
os: 'Android',
|
|
287
|
-
Platform: 'Android',
|
|
287
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
288
288
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible', 'google fi'],
|
|
289
289
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
290
290
|
}, {
|
|
@@ -292,7 +292,7 @@ const androidDevices = [
|
|
|
292
292
|
screen_height: '2400',
|
|
293
293
|
screen_width: '1080',
|
|
294
294
|
os: 'Android',
|
|
295
|
-
Platform: 'Android',
|
|
295
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
296
296
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'google fi'],
|
|
297
297
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
298
298
|
},
|
|
@@ -303,7 +303,7 @@ const androidDevices = [
|
|
|
303
303
|
screen_height: '3120',
|
|
304
304
|
screen_width: '1440',
|
|
305
305
|
os: 'Android',
|
|
306
|
-
Platform: 'Android',
|
|
306
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
307
307
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible'],
|
|
308
308
|
radio: ['4G', 'LTE', '5G', '5G mmWave', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
309
309
|
}, {
|
|
@@ -311,7 +311,7 @@ const androidDevices = [
|
|
|
311
311
|
screen_height: '3120',
|
|
312
312
|
screen_width: '1440',
|
|
313
313
|
os: 'Android',
|
|
314
|
-
Platform: 'Android',
|
|
314
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
315
315
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile', 'visible'],
|
|
316
316
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
317
317
|
}, {
|
|
@@ -319,7 +319,7 @@ const androidDevices = [
|
|
|
319
319
|
screen_height: '2340',
|
|
320
320
|
screen_width: '1080',
|
|
321
321
|
os: 'Android',
|
|
322
|
-
Platform: 'Android',
|
|
322
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
323
323
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile'],
|
|
324
324
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
325
325
|
},
|
|
@@ -330,7 +330,7 @@ const androidDevices = [
|
|
|
330
330
|
screen_height: '2160',
|
|
331
331
|
screen_width: '1856',
|
|
332
332
|
os: 'Android',
|
|
333
|
-
Platform: 'Android',
|
|
333
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
334
334
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
335
335
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
336
336
|
}, {
|
|
@@ -338,7 +338,7 @@ const androidDevices = [
|
|
|
338
338
|
screen_height: '2640',
|
|
339
339
|
screen_width: '1080',
|
|
340
340
|
os: 'Android',
|
|
341
|
-
Platform: 'Android',
|
|
341
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
342
342
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
343
343
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
344
344
|
},
|
|
@@ -349,7 +349,7 @@ const androidDevices = [
|
|
|
349
349
|
screen_height: '3168',
|
|
350
350
|
screen_width: '1440',
|
|
351
351
|
os: 'Android',
|
|
352
|
-
Platform: 'Android',
|
|
352
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
353
353
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile'],
|
|
354
354
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
355
355
|
}, {
|
|
@@ -357,7 +357,7 @@ const androidDevices = [
|
|
|
357
357
|
screen_height: '3168',
|
|
358
358
|
screen_width: '1440',
|
|
359
359
|
os: 'Android',
|
|
360
|
-
Platform: 'Android',
|
|
360
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
361
361
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular', 'mint mobile'],
|
|
362
362
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
363
363
|
},
|
|
@@ -368,7 +368,7 @@ const androidDevices = [
|
|
|
368
368
|
screen_height: '2412',
|
|
369
369
|
screen_width: '1084',
|
|
370
370
|
os: 'Android',
|
|
371
|
-
Platform: 'Android',
|
|
371
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
372
372
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
373
373
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6']
|
|
374
374
|
},
|
|
@@ -379,7 +379,7 @@ const androidDevices = [
|
|
|
379
379
|
screen_height: '3200',
|
|
380
380
|
screen_width: '1440',
|
|
381
381
|
os: 'Android',
|
|
382
|
-
Platform: 'Android',
|
|
382
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
383
383
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
384
384
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E', 'WiFi7']
|
|
385
385
|
}, {
|
|
@@ -387,7 +387,7 @@ const androidDevices = [
|
|
|
387
387
|
screen_height: '2712',
|
|
388
388
|
screen_width: '1220',
|
|
389
389
|
os: 'Android',
|
|
390
|
-
Platform: 'Android',
|
|
390
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
391
391
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
392
392
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6']
|
|
393
393
|
},
|
|
@@ -398,7 +398,7 @@ const androidDevices = [
|
|
|
398
398
|
screen_height: '3840',
|
|
399
399
|
screen_width: '1644',
|
|
400
400
|
os: 'Android',
|
|
401
|
-
Platform: 'Android',
|
|
401
|
+
// Platform: 'Android', // Removed in 1.5.1 — see TODO #11
|
|
402
402
|
carrier: ['verizon', 'at&t', 't-mobile', 'cricket', 'us cellular'],
|
|
403
403
|
radio: ['4G', 'LTE', '5G', 'Wifi', 'WiFi6', 'WiFi6E']
|
|
404
404
|
}
|
|
@@ -411,49 +411,49 @@ const desktopDevices = [
|
|
|
411
411
|
screen_height: '2520',
|
|
412
412
|
screen_width: '4480',
|
|
413
413
|
os: 'macOS',
|
|
414
|
-
Platform: 'Desktop'
|
|
414
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
415
415
|
}, {
|
|
416
416
|
model: 'Mac Studio (M4 Ultra, 2024)',
|
|
417
417
|
screen_height: '2880',
|
|
418
418
|
screen_width: '5120',
|
|
419
419
|
os: 'macOS',
|
|
420
|
-
Platform: 'Desktop'
|
|
420
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
421
421
|
}, {
|
|
422
422
|
model: 'Mac Pro (M3 Ultra, 2024)',
|
|
423
423
|
screen_height: '2160',
|
|
424
424
|
screen_width: '3840',
|
|
425
425
|
os: 'macOS',
|
|
426
|
-
Platform: 'Desktop'
|
|
426
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
427
427
|
}, {
|
|
428
428
|
model: 'Mac Mini (M4, 2024)',
|
|
429
429
|
screen_height: '2160',
|
|
430
430
|
screen_width: '3840',
|
|
431
431
|
os: 'macOS',
|
|
432
|
-
Platform: 'Desktop'
|
|
432
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
433
433
|
}, {
|
|
434
434
|
model: 'MacBook Air 15-inch (M3, 2024)',
|
|
435
435
|
screen_height: '1964',
|
|
436
436
|
screen_width: '2880',
|
|
437
437
|
os: 'macOS',
|
|
438
|
-
Platform: 'Desktop'
|
|
438
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
439
439
|
}, {
|
|
440
440
|
model: 'MacBook Air 13-inch (M3, 2024)',
|
|
441
441
|
screen_height: '1664',
|
|
442
442
|
screen_width: '2560',
|
|
443
443
|
os: 'macOS',
|
|
444
|
-
Platform: 'Desktop'
|
|
444
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
445
445
|
}, {
|
|
446
446
|
model: 'MacBook Pro 14-inch (M4 Pro, 2024)',
|
|
447
447
|
screen_height: '1964',
|
|
448
448
|
screen_width: '3024',
|
|
449
449
|
os: 'macOS',
|
|
450
|
-
Platform: 'Desktop'
|
|
450
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
451
451
|
}, {
|
|
452
452
|
model: 'MacBook Pro 16-inch (M4 Max, 2024)',
|
|
453
453
|
screen_height: '2234',
|
|
454
454
|
screen_width: '3456',
|
|
455
455
|
os: 'macOS',
|
|
456
|
-
Platform: 'Desktop'
|
|
456
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
457
457
|
},
|
|
458
458
|
|
|
459
459
|
// Windows Laptops (2024-2025)
|
|
@@ -462,67 +462,67 @@ const desktopDevices = [
|
|
|
462
462
|
screen_height: '2160',
|
|
463
463
|
screen_width: '2880',
|
|
464
464
|
os: 'Windows',
|
|
465
|
-
Platform: 'Desktop'
|
|
465
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
466
466
|
}, {
|
|
467
467
|
model: 'Dell XPS 15 (Intel Core Ultra 9)',
|
|
468
468
|
screen_height: '2160',
|
|
469
469
|
screen_width: '3840',
|
|
470
470
|
os: 'Windows',
|
|
471
|
-
Platform: 'Desktop'
|
|
471
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
472
472
|
}, {
|
|
473
473
|
model: 'Dell XPS 17 (RTX 4080)',
|
|
474
474
|
screen_height: '2400',
|
|
475
475
|
screen_width: '3840',
|
|
476
476
|
os: 'Windows',
|
|
477
|
-
Platform: 'Desktop'
|
|
477
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
478
478
|
}, {
|
|
479
479
|
model: 'Microsoft Surface Laptop Studio 2',
|
|
480
480
|
screen_height: '1504',
|
|
481
481
|
screen_width: '2256',
|
|
482
482
|
os: 'Windows',
|
|
483
|
-
Platform: 'Desktop'
|
|
483
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
484
484
|
}, {
|
|
485
485
|
model: 'Microsoft Surface Pro 11',
|
|
486
486
|
screen_height: '1944',
|
|
487
487
|
screen_width: '2880',
|
|
488
488
|
os: 'Windows',
|
|
489
|
-
Platform: 'Desktop'
|
|
489
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
490
490
|
}, {
|
|
491
491
|
model: 'HP Spectre x360 16 (Intel Core Ultra)',
|
|
492
492
|
screen_height: '2160',
|
|
493
493
|
screen_width: '3840',
|
|
494
494
|
os: 'Windows',
|
|
495
|
-
Platform: 'Desktop'
|
|
495
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
496
496
|
}, {
|
|
497
497
|
model: 'HP EliteBook 840 G11',
|
|
498
498
|
screen_height: '1200',
|
|
499
499
|
screen_width: '1920',
|
|
500
500
|
os: 'Windows',
|
|
501
|
-
Platform: 'Desktop'
|
|
501
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
502
502
|
}, {
|
|
503
503
|
model: 'Lenovo ThinkPad X1 Carbon Gen 12',
|
|
504
504
|
screen_height: '1200',
|
|
505
505
|
screen_width: '1920',
|
|
506
506
|
os: 'Windows',
|
|
507
|
-
Platform: 'Desktop'
|
|
507
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
508
508
|
}, {
|
|
509
509
|
model: 'Lenovo Yoga Pro 9i (RTX 4070)',
|
|
510
510
|
screen_height: '1600',
|
|
511
511
|
screen_width: '2560',
|
|
512
512
|
os: 'Windows',
|
|
513
|
-
Platform: 'Desktop'
|
|
513
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
514
514
|
}, {
|
|
515
515
|
model: 'ASUS ZenBook Pro 16X OLED',
|
|
516
516
|
screen_height: '2160',
|
|
517
517
|
screen_width: '3840',
|
|
518
518
|
os: 'Windows',
|
|
519
|
-
Platform: 'Desktop'
|
|
519
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
520
520
|
}, {
|
|
521
521
|
model: 'ASUS ROG Zephyrus G16',
|
|
522
522
|
screen_height: '1200',
|
|
523
523
|
screen_width: '1920',
|
|
524
524
|
os: 'Windows',
|
|
525
|
-
Platform: 'Desktop'
|
|
525
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
526
526
|
},
|
|
527
527
|
|
|
528
528
|
// Gaming Desktops (2024-2025)
|
|
@@ -531,25 +531,25 @@ const desktopDevices = [
|
|
|
531
531
|
screen_height: '2160',
|
|
532
532
|
screen_width: '3840',
|
|
533
533
|
os: 'Windows',
|
|
534
|
-
Platform: 'Desktop'
|
|
534
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
535
535
|
}, {
|
|
536
536
|
model: 'HP OMEN 45L (RTX 4080 Super)',
|
|
537
537
|
screen_height: '1440',
|
|
538
538
|
screen_width: '2560',
|
|
539
539
|
os: 'Windows',
|
|
540
|
-
Platform: 'Desktop'
|
|
540
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
541
541
|
}, {
|
|
542
542
|
model: 'Corsair One i500 (RTX 4090)',
|
|
543
543
|
screen_height: '2160',
|
|
544
544
|
screen_width: '3840',
|
|
545
545
|
os: 'Windows',
|
|
546
|
-
Platform: 'Desktop'
|
|
546
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
547
547
|
}, {
|
|
548
548
|
model: 'NZXT BLD H5 Elite',
|
|
549
549
|
screen_height: '1440',
|
|
550
550
|
screen_width: '2560',
|
|
551
551
|
os: 'Windows',
|
|
552
|
-
Platform: 'Desktop'
|
|
552
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
553
553
|
},
|
|
554
554
|
|
|
555
555
|
// Business/Office Desktops
|
|
@@ -558,19 +558,19 @@ const desktopDevices = [
|
|
|
558
558
|
screen_height: '1080',
|
|
559
559
|
screen_width: '1920',
|
|
560
560
|
os: 'Windows',
|
|
561
|
-
Platform: 'Desktop'
|
|
561
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
562
562
|
}, {
|
|
563
563
|
model: 'HP EliteDesk 805 G8',
|
|
564
564
|
screen_height: '1440',
|
|
565
565
|
screen_width: '2560',
|
|
566
566
|
os: 'Windows',
|
|
567
|
-
Platform: 'Desktop'
|
|
567
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
568
568
|
}, {
|
|
569
569
|
model: 'Lenovo ThinkCentre M90a Pro',
|
|
570
570
|
screen_height: '1440',
|
|
571
571
|
screen_width: '2560',
|
|
572
572
|
os: 'Windows',
|
|
573
|
-
Platform: 'Desktop'
|
|
573
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
574
574
|
},
|
|
575
575
|
|
|
576
576
|
// Linux/Alternative OS (growing presence)
|
|
@@ -579,19 +579,19 @@ const desktopDevices = [
|
|
|
579
579
|
screen_height: '2160',
|
|
580
580
|
screen_width: '3840',
|
|
581
581
|
os: 'Pop!_OS',
|
|
582
|
-
Platform: 'Desktop'
|
|
582
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
583
583
|
}, {
|
|
584
584
|
model: 'Framework Laptop 16',
|
|
585
585
|
screen_height: '1600',
|
|
586
586
|
screen_width: '2560',
|
|
587
587
|
os: 'Linux',
|
|
588
|
-
Platform: 'Desktop'
|
|
588
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
589
589
|
}, {
|
|
590
590
|
model: 'Purism Librem 14',
|
|
591
591
|
screen_height: '1080',
|
|
592
592
|
screen_width: '1920',
|
|
593
593
|
os: 'PureOS',
|
|
594
|
-
Platform: 'Desktop'
|
|
594
|
+
// Platform: 'Desktop' // Removed in 1.5.1 — see TODO #11
|
|
595
595
|
}
|
|
596
596
|
];
|
|
597
597
|
|
|
@@ -38,7 +38,15 @@
|
|
|
38
38
|
* achievable with the v1.5 engine fix's per-cluster trapezoidal shape.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* v1.5.1: macro presets carry an optional `avgActiveDaysPerUser` default. The
|
|
43
|
+
* validator merges this default only when the dungeon doesn't set the field
|
|
44
|
+
* explicitly. `flat` deliberately omits it (legacy behavior — every window-day
|
|
45
|
+
* potentially active). Other macros ship sensible-default concentrations so
|
|
46
|
+
* new dungeons get realistic user-activity patterns out of the box.
|
|
47
|
+
*
|
|
48
|
+
* @type {Record<string, {bornRecentBias: number, percentUsersBornInDataset: number, preExistingSpread: 'pinned'|'uniform', avgActiveDaysPerUser?: number}>}
|
|
49
|
+
*/
|
|
42
50
|
export const MACRO_PRESETS = {
|
|
43
51
|
/**
|
|
44
52
|
* flat (DEFAULT) — Mature product, no growth narrative.
|
|
@@ -62,6 +70,7 @@ export const MACRO_PRESETS = {
|
|
|
62
70
|
bornRecentBias: 0.1,
|
|
63
71
|
percentUsersBornInDataset: 12,
|
|
64
72
|
preExistingSpread: 'uniform',
|
|
73
|
+
avgActiveDaysPerUser: 15,
|
|
65
74
|
},
|
|
66
75
|
|
|
67
76
|
/**
|
|
@@ -73,6 +82,7 @@ export const MACRO_PRESETS = {
|
|
|
73
82
|
bornRecentBias: 0.3,
|
|
74
83
|
percentUsersBornInDataset: 30,
|
|
75
84
|
preExistingSpread: 'pinned',
|
|
85
|
+
avgActiveDaysPerUser: 10,
|
|
76
86
|
},
|
|
77
87
|
|
|
78
88
|
/**
|
|
@@ -84,6 +94,7 @@ export const MACRO_PRESETS = {
|
|
|
84
94
|
bornRecentBias: 0.6,
|
|
85
95
|
percentUsersBornInDataset: 55,
|
|
86
96
|
preExistingSpread: 'pinned',
|
|
97
|
+
avgActiveDaysPerUser: 20,
|
|
87
98
|
},
|
|
88
99
|
|
|
89
100
|
/**
|
|
@@ -103,6 +114,7 @@ export const MACRO_PRESETS = {
|
|
|
103
114
|
bornRecentBias: -0.3,
|
|
104
115
|
percentUsersBornInDataset: 5,
|
|
105
116
|
preExistingSpread: 'uniform',
|
|
117
|
+
avgActiveDaysPerUser: 5,
|
|
106
118
|
},
|
|
107
119
|
};
|
|
108
120
|
|
|
@@ -114,7 +126,7 @@ export const MACRO_PRESET_NAMES = Object.keys(MACRO_PRESETS);
|
|
|
114
126
|
* Defaults to "flat" if nothing is provided.
|
|
115
127
|
*
|
|
116
128
|
* @param {string | object | undefined} macro - Macro config from dungeon
|
|
117
|
-
* @returns {{bornRecentBias: number, percentUsersBornInDataset: number, preExistingSpread: 'pinned' | 'uniform'}}
|
|
129
|
+
* @returns {{bornRecentBias: number, percentUsersBornInDataset: number, preExistingSpread: 'pinned' | 'uniform', avgActiveDaysPerUser?: number}}
|
|
118
130
|
*/
|
|
119
131
|
export function resolveMacro(macro) {
|
|
120
132
|
if (!macro) return { ...MACRO_PRESETS.flat };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.5.1: AsyncLocalStorage-scoped dataset-window context.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the legacy module-scoped `DATASET_NOW` / `DATASET_BEGIN` mutable
|
|
5
|
+
* state in `lib/utils/utils.js`. Each `generate()` call wraps the pipeline in
|
|
6
|
+
* `runWithDataset(begin, now, fn)`, and the factory thunks (`date`, `day`,
|
|
7
|
+
* `dateRange`, `TimeSoup`, `validTime`) read from the ALS store via
|
|
8
|
+
* `getDatasetNow()` / `getDatasetBegin()` instead of module globals.
|
|
9
|
+
*
|
|
10
|
+
* This makes concurrent in-process `generate()` calls safe with respect to
|
|
11
|
+
* the dataset-window dimension. RNG scoping is a SEPARATE concurrency hole
|
|
12
|
+
* — see TODOs.md "Considered but punted" for the follow-up plan.
|
|
13
|
+
*
|
|
14
|
+
* Trip-ups (see plans/archived/globals-killplan-1.5.1/kill-globals.md §7):
|
|
15
|
+
* - ALS does NOT propagate across child_process.fork / worker_threads.
|
|
16
|
+
* - Tests that import dungeon configs at top-level evaluate thunks at
|
|
17
|
+
* import time — those thunks fall back to wall-clock if invoked outside
|
|
18
|
+
* a `runWithDataset` scope.
|
|
19
|
+
* - Callbacks scheduled via setImmediate / setTimeout / native event
|
|
20
|
+
* emitters MAY lose context. Audit at the orchestrator level.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
24
|
+
import dayjs from 'dayjs';
|
|
25
|
+
import utc from 'dayjs/plugin/utc.js';
|
|
26
|
+
dayjs.extend(utc);
|
|
27
|
+
|
|
28
|
+
/** @type {AsyncLocalStorage<{ begin: number, now: number }>} */
|
|
29
|
+
const datasetALS = new AsyncLocalStorage();
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Legacy fallback — written by the deprecated `setDatasetNow` / `setDatasetBegin`
|
|
33
|
+
* shims in `lib/utils/utils.js`. Used ONLY when no ALS scope is active. This
|
|
34
|
+
* keeps existing tests that call the setters directly (instead of wrapping in
|
|
35
|
+
* `runWithDataset`) functional through v1.5.1. v1.6 may remove the shims.
|
|
36
|
+
*
|
|
37
|
+
* @type {{ begin: number|null, now: number|null }}
|
|
38
|
+
*/
|
|
39
|
+
const legacyFallback = { begin: null, now: null };
|
|
40
|
+
|
|
41
|
+
/** @internal — used by `setDatasetNow` / `setDatasetBegin` shims. */
|
|
42
|
+
export function _setLegacyDatasetNow(unixSeconds) {
|
|
43
|
+
if (typeof unixSeconds === 'number' && Number.isFinite(unixSeconds)) {
|
|
44
|
+
legacyFallback.now = unixSeconds;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @internal — used by `setDatasetNow` / `setDatasetBegin` shims. */
|
|
49
|
+
export function _setLegacyDatasetBegin(unixSeconds) {
|
|
50
|
+
if (typeof unixSeconds === 'number' && Number.isFinite(unixSeconds)) {
|
|
51
|
+
legacyFallback.begin = unixSeconds;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Run `fn` inside a dataset-window scope. Factory thunks invoked anywhere in
|
|
57
|
+
* the async call chain (sync or via `await`) will read the scoped window
|
|
58
|
+
* instead of the module fallback.
|
|
59
|
+
*
|
|
60
|
+
* @template T
|
|
61
|
+
* @param {number} datasetBeginUnix
|
|
62
|
+
* @param {number} datasetNowUnix
|
|
63
|
+
* @param {() => T} fn
|
|
64
|
+
* @returns {T}
|
|
65
|
+
*/
|
|
66
|
+
export function runWithDataset(datasetBeginUnix, datasetNowUnix, fn) {
|
|
67
|
+
return datasetALS.run({ begin: datasetBeginUnix, now: datasetNowUnix }, fn);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Read the scoped dataset-now value. Resolution order:
|
|
72
|
+
* 1. ALS store (active `runWithDataset` scope) — production pipeline path.
|
|
73
|
+
* 2. Legacy fallback (set via deprecated `setDatasetNow` shim) — for tests.
|
|
74
|
+
* 3. Wall-clock `dayjs.utc()` — last-resort default.
|
|
75
|
+
*
|
|
76
|
+
* @returns {dayjs.Dayjs}
|
|
77
|
+
*/
|
|
78
|
+
export function getDatasetNow() {
|
|
79
|
+
const store = datasetALS.getStore();
|
|
80
|
+
if (store) return dayjs.unix(store.now).utc();
|
|
81
|
+
if (legacyFallback.now !== null) return dayjs.unix(legacyFallback.now).utc();
|
|
82
|
+
return dayjs.utc();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Read the scoped dataset-begin value. Same resolution as `getDatasetNow`,
|
|
87
|
+
* falling back to wall-clock minus 30 days.
|
|
88
|
+
*
|
|
89
|
+
* @returns {dayjs.Dayjs}
|
|
90
|
+
*/
|
|
91
|
+
export function getDatasetBegin() {
|
|
92
|
+
const store = datasetALS.getStore();
|
|
93
|
+
if (store) return dayjs.unix(store.begin).utc();
|
|
94
|
+
if (legacyFallback.begin !== null) return dayjs.unix(legacyFallback.begin).utc();
|
|
95
|
+
return dayjs.utc().subtract(30, 'day');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @returns {boolean} true when called inside a runWithDataset scope.
|
|
100
|
+
*/
|
|
101
|
+
export function hasDatasetScope() {
|
|
102
|
+
return datasetALS.getStore() !== undefined;
|
|
103
|
+
}
|