@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
package/types.d.ts
CHANGED
|
@@ -12,10 +12,66 @@ type Primitives = string | number | boolean | Date | Record<string, any>;
|
|
|
12
12
|
*/
|
|
13
13
|
export type ValueValid = Primitives | ValueValid[] | (() => ValueValid);
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* v1.5.1 — credentials sub-object. Groups Mixpanel project credentials. Top-level
|
|
17
|
+
* `token` / `region` / etc. remain functional as a back-compat alias; when both
|
|
18
|
+
* are set, the top-level value wins with a verbose warning.
|
|
19
|
+
*/
|
|
20
|
+
export interface DungeonCredentials {
|
|
21
|
+
token?: string;
|
|
22
|
+
region?: 'US' | 'EU' | 'IN';
|
|
23
|
+
serviceAccount?: string;
|
|
24
|
+
serviceSecret?: string;
|
|
25
|
+
projectId?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* v1.5.1 — switches sub-object. Groups data-shape booleans. Top-level keys
|
|
30
|
+
* remain functional as a back-compat alias; same precedence rules as
|
|
31
|
+
* `DungeonCredentials`.
|
|
32
|
+
*/
|
|
33
|
+
export interface DungeonSwitches {
|
|
34
|
+
hasLocation?: boolean;
|
|
35
|
+
hasCampaigns?: boolean;
|
|
36
|
+
hasAdSpend?: boolean;
|
|
37
|
+
hasSessionIds?: boolean;
|
|
38
|
+
hasAvatar?: boolean;
|
|
39
|
+
hasIOSDevices?: boolean;
|
|
40
|
+
hasAndroidDevices?: boolean;
|
|
41
|
+
hasDesktopDevices?: boolean;
|
|
42
|
+
hasBrowser?: boolean;
|
|
43
|
+
isAnonymous?: boolean;
|
|
44
|
+
alsoInferFunnels?: boolean;
|
|
45
|
+
hasAttributionFlags?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* v1.5.1 — identity sub-object. Groups identity-model knobs. Top-level
|
|
50
|
+
* `avgDevicePerUser` / `sessionTimeout` remain functional as a back-compat
|
|
51
|
+
* alias.
|
|
52
|
+
*
|
|
53
|
+
* `hasAnonIds` is DEPRECATED — when present here, it maps to
|
|
54
|
+
* `avgDevicePerUser: 1` with a verbose warning. Use `avgDevicePerUser` instead.
|
|
55
|
+
*/
|
|
56
|
+
export interface DungeonIdentity {
|
|
57
|
+
avgDevicePerUser?: number;
|
|
58
|
+
sessionTimeout?: number;
|
|
59
|
+
/** @deprecated v1.5.1 — use `avgDevicePerUser: 1` instead. */
|
|
60
|
+
hasAnonIds?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
15
63
|
/**
|
|
16
64
|
* main config object for the entire data generation
|
|
17
65
|
*/
|
|
18
66
|
export interface Dungeon {
|
|
67
|
+
// ── v1.5.1 sub-object grouping (optional) ──
|
|
68
|
+
/** v1.5.1 — credentials sub-object. See `DungeonCredentials`. */
|
|
69
|
+
credentials?: DungeonCredentials;
|
|
70
|
+
/** v1.5.1 — switches sub-object. See `DungeonSwitches`. */
|
|
71
|
+
switches?: DungeonSwitches;
|
|
72
|
+
/** v1.5.1 — identity sub-object. See `DungeonIdentity`. */
|
|
73
|
+
identity?: DungeonIdentity;
|
|
74
|
+
|
|
19
75
|
// ── Core Parameters ──
|
|
20
76
|
/** Optional dungeon version. Not used by the engine — serves as metadata for tracking revisions when configs are saved/shared. */
|
|
21
77
|
version?: string | number;
|
|
@@ -25,6 +81,19 @@ export interface Dungeon {
|
|
|
25
81
|
token?: string;
|
|
26
82
|
/** RNG seed for reproducible output. Same seed + concurrency=1 = identical data. */
|
|
27
83
|
seed?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Optional separate RNG seed dedicated to `distinct_id` generation.
|
|
86
|
+
*
|
|
87
|
+
* When set, two runs with the same `userSeed` but different `seed` produce
|
|
88
|
+
* the SAME pool of user IDs but DIFFERENT events. Designed for sharded /
|
|
89
|
+
* massively-parallel runs (e.g., Cloud Run Job fan-out) that need cross-shard
|
|
90
|
+
* user identity — every shard generating bucket N pulls from the same 3M
|
|
91
|
+
* user IDs while producing unique events of its own.
|
|
92
|
+
*
|
|
93
|
+
* When unset, the engine falls back to `seed` for user-id generation —
|
|
94
|
+
* existing dungeons stay byte-identical.
|
|
95
|
+
*/
|
|
96
|
+
userSeed?: string;
|
|
28
97
|
/**
|
|
29
98
|
* Number of days the dataset spans. Default: 30.
|
|
30
99
|
*
|
|
@@ -303,6 +372,32 @@ export interface Dungeon {
|
|
|
303
372
|
* purpose; the v1.5 validator strict-clamps to `floor(numDays * 0.5)` with a warning.
|
|
304
373
|
*/
|
|
305
374
|
avgActiveDaysPerUser?: number;
|
|
375
|
+
/**
|
|
376
|
+
* v1.5.1 — target retention shape. Anchor points `day1`, `day7`, `day30`
|
|
377
|
+
* etc. define the per-day-offset weight a user is active. When set, biases
|
|
378
|
+
* `buildActiveDayPlan` toward the curve and the effective
|
|
379
|
+
* `avgActiveDaysPerUser` is derived from the curve's sum across the user's
|
|
380
|
+
* window (curve wins over an explicit `avgActiveDaysPerUser`).
|
|
381
|
+
*
|
|
382
|
+
* - `type`: `'logarithmic'` (default, real-world retention shape) or `'linear'`.
|
|
383
|
+
* - `dayN` keys: fraction active on day N from birth (0..1). Day 0 is
|
|
384
|
+
* implicitly 1.0 (every user is active on their birth day).
|
|
385
|
+
* - Days beyond the largest anchor extrapolate from the last segment.
|
|
386
|
+
*
|
|
387
|
+
* Example: `{ day1: 0.40, day7: 0.20, day30: 0.08 }` produces a curve that
|
|
388
|
+
* approximates a typical product's 30-day retention.
|
|
389
|
+
*/
|
|
390
|
+
retentionCurve?: {
|
|
391
|
+
type?: 'logarithmic' | 'linear';
|
|
392
|
+
day1?: number;
|
|
393
|
+
day3?: number;
|
|
394
|
+
day7?: number;
|
|
395
|
+
day14?: number;
|
|
396
|
+
day30?: number;
|
|
397
|
+
day60?: number;
|
|
398
|
+
day90?: number;
|
|
399
|
+
[dayKey: string]: number | 'logarithmic' | 'linear' | undefined;
|
|
400
|
+
};
|
|
306
401
|
/**
|
|
307
402
|
* Maximum number of UTM-stamped events per user. Matches Mixpanel's `TOUCHPOINTS_LIMIT`
|
|
308
403
|
* (`backend/libquery/properties_over_time/attributed_value_reader.cpp` line 16).
|
|
@@ -1115,6 +1210,15 @@ export interface UserProfile {
|
|
|
1115
1210
|
avatar?: string;
|
|
1116
1211
|
created: string | undefined;
|
|
1117
1212
|
distinct_id: string;
|
|
1213
|
+
/**
|
|
1214
|
+
* v1.5.1: when `true`, the engine considers this profile "anonymous" — the
|
|
1215
|
+
* user never reached an `isAuthEvent` step. Profile still exists in
|
|
1216
|
+
* `userProfilesData` (so hooks and downstream tools can see the full
|
|
1217
|
+
* population), but `mixpanel-sender` filters it out before pushing to
|
|
1218
|
+
* `/engage`. Hooks can rescue by deleting the flag inside the `everything`
|
|
1219
|
+
* hook.
|
|
1220
|
+
*/
|
|
1221
|
+
_drop?: boolean;
|
|
1118
1222
|
[key: string]: ValueValid;
|
|
1119
1223
|
}
|
|
1120
1224
|
|
|
@@ -1200,6 +1304,12 @@ export type Result = {
|
|
|
1200
1304
|
userCount?: number;
|
|
1201
1305
|
groupCount?: number;
|
|
1202
1306
|
avgEPS?: number;
|
|
1307
|
+
/**
|
|
1308
|
+
* v1.5.1: count of profiles eligible for Mixpanel `/engage` push (i.e., not
|
|
1309
|
+
* flagged with `_drop: true`). Anonymous non-converters carry `_drop: true`
|
|
1310
|
+
* so `userProfilesData.length - profilesPushed` = dropped profile count.
|
|
1311
|
+
*/
|
|
1312
|
+
profilesPushed?: number;
|
|
1203
1313
|
/** Progress callback summary. Only present when `onProgress` was provided. */
|
|
1204
1314
|
progress?: ProgressSummary;
|
|
1205
1315
|
};
|
|
@@ -1750,7 +1860,7 @@ declare module '@ak--47/dungeon-master/hook-patterns' {
|
|
|
1750
1860
|
* | `attributedBy` | `conversionEvent`, `attributionEvent`, `attributionProperty` | `model` (default: `'lastTouch'`) |
|
|
1751
1861
|
*/
|
|
1752
1862
|
export interface EmulateOptions {
|
|
1753
|
-
type: 'frequencyByFrequency' | 'funnelFrequency' | 'aggregatePerUser' | 'timeToConvert' | 'attributedBy' | 'sessionMetrics' | 'retention';
|
|
1863
|
+
type: 'frequencyByFrequency' | 'funnelFrequency' | 'aggregatePerUser' | 'timeToConvert' | 'attributedBy' | 'sessionMetrics' | 'retention' | 'distinctCount';
|
|
1754
1864
|
metricEvent?: string;
|
|
1755
1865
|
breakdownByFrequencyOf?: string;
|
|
1756
1866
|
perUser?: boolean;
|
|
@@ -1815,6 +1925,10 @@ export interface EmulateOptions {
|
|
|
1815
1925
|
* pattern requires COMPOUNDED retention which is not supported here).
|
|
1816
1926
|
*/
|
|
1817
1927
|
birthCanRetain?: boolean;
|
|
1928
|
+
|
|
1929
|
+
// v1.5.1 distinctCount extensions
|
|
1930
|
+
/** Optional cap on the number of top-N values returned in `top_values`. Defaults to 25 (matches Mixpanel UI). */
|
|
1931
|
+
topN?: number;
|
|
1818
1932
|
}
|
|
1819
1933
|
|
|
1820
1934
|
/** v1.5.0 — config for `emulateBreakdown({ type: 'retention' })`. */
|
|
@@ -1906,6 +2020,8 @@ declare module '@ak--47/dungeon-master/utils' {
|
|
|
1906
2020
|
export function weighNumRange(min: number, max: number, skew?: number, size?: number): number[];
|
|
1907
2021
|
export function pickAWinner(items: string[], mostChosenIndex?: number): () => string[];
|
|
1908
2022
|
export function initChance(seed?: string): unknown;
|
|
2023
|
+
export function initUserChance(seed?: string): unknown;
|
|
2024
|
+
export function getUserChance(): unknown;
|
|
1909
2025
|
export function TimeSoup(earliestTime: number, latestTime: number, peaks?: number, deviation?: number, mean?: number, dayOfWeekWeights?: number[] | null, hourOfDayWeights?: number[] | null): number;
|
|
1910
2026
|
export function weighArray<T>(items: T[]): T[];
|
|
1911
2027
|
export function generateUser(user_id: string, opts: Record<string, unknown>): Record<string, unknown>;
|