@sentientui/policy 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.cts +163 -14
- package/dist/index.d.ts +163 -14
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -21,9 +21,12 @@ declare const CLUSTER_PRIORITY: Record<Persona, string[]>;
|
|
|
21
21
|
/**
|
|
22
22
|
* Reorders section IDs based on the persona's semantic priority.
|
|
23
23
|
* Sections with no graph entry are treated as 'generic'.
|
|
24
|
-
* Returns the input unchanged for
|
|
24
|
+
* Returns the input unchanged for 'unknown' — and for any custom vocabulary
|
|
25
|
+
* persona (declared/discovered): those have no semantic prior, so they serve
|
|
26
|
+
* the natural order until the layout bandit has learned rows, the same
|
|
27
|
+
* cold-start posture 'unknown' gets.
|
|
25
28
|
*/
|
|
26
|
-
declare function applyClusterHeuristic(sections: string[], sectionTypes: Map<string, string>, persona:
|
|
29
|
+
declare function applyClusterHeuristic(sections: string[], sectionTypes: Map<string, string>, persona: string): string[];
|
|
27
30
|
/**
|
|
28
31
|
* The candidate layout orderings for a page — the distinct section orders
|
|
29
32
|
* produced by every persona's semantic priority (plus the requesting
|
|
@@ -31,7 +34,7 @@ declare function applyClusterHeuristic(sections: string[], sectionTypes: Map<str
|
|
|
31
34
|
* "arms" the layout bandit explores. Returned as hash → order so it joins
|
|
32
35
|
* directly against layout_weights rows keyed by the same hashLayout.
|
|
33
36
|
*/
|
|
34
|
-
declare function candidateLayouts(sections: string[], sectionTypes: Map<string, string>, persona:
|
|
37
|
+
declare function candidateLayouts(sections: string[], sectionTypes: Map<string, string>, persona: string): Map<string, string[]>;
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
40
|
* Stable 16-char SHA-256 prefix for a section order array.
|
|
@@ -62,7 +65,7 @@ type LearnedLayout = {
|
|
|
62
65
|
* NON-DETERMINISTIC. Pass a seeded PRNG when you need a reproducible layout
|
|
63
66
|
* (tests, replayable decisions) — otherwise the sampled order varies per call.
|
|
64
67
|
*/
|
|
65
|
-
declare function chooseLayout(sections: string[], sectionTypes: Map<string, string>, persona:
|
|
68
|
+
declare function chooseLayout(sections: string[], sectionTypes: Map<string, string>, persona: string, learned: Map<string, LearnedLayout>, rand?: () => number): string[];
|
|
66
69
|
|
|
67
70
|
/** Learned Beta(alpha, beta) posterior for one arm. */
|
|
68
71
|
type ArmPosterior = {
|
|
@@ -134,20 +137,49 @@ declare function validateSlotDecl(decl: SlotDecl): {
|
|
|
134
137
|
*/
|
|
135
138
|
declare function slotResultFor(decl: SlotDecl, arm: string): SlotResult;
|
|
136
139
|
|
|
137
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Empirical-Bayes pooling strength, in pseudo-observations. A cell is born
|
|
142
|
+
* holding `m` imaginary trials drawn at its parent's rate, and its own data
|
|
143
|
+
* outvotes them once it has collected more than `m` real ones.
|
|
144
|
+
*/
|
|
138
145
|
declare const SHRINKAGE_M = 20;
|
|
139
146
|
/**
|
|
140
|
-
* Empirical-Bayes
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
147
|
+
* Empirical-Bayes shrinkage toward a parent posterior, at read time.
|
|
148
|
+
* Pinned in CONTRACTS.md §4.
|
|
149
|
+
*
|
|
150
|
+
* A cell is born warm — with no data of its own it sits at the parent's rate —
|
|
151
|
+
* and detaches as its own evidence accumulates.
|
|
152
|
+
*
|
|
153
|
+
* mu = pooled.alpha / (pooled.alpha + pooled.beta) // parent's rate
|
|
154
|
+
* strength = m * mass / (mass + m), mass = pooled.alpha + pooled.beta
|
|
155
|
+
* alpha' = cell.alpha + strength * mu
|
|
156
|
+
* beta' = cell.beta + strength * (1 - mu)
|
|
157
|
+
*
|
|
158
|
+
* The prior contributes a FIXED number of pseudo-observations, never a copy of
|
|
159
|
+
* the parent's counts. That distinction is the whole point of this function.
|
|
160
|
+
* The previous form was `cell.alpha + w * pooled.alpha` with
|
|
161
|
+
* `w = m / (m + cell.exposures)`, which folded the parent's SAMPLE SIZE into
|
|
162
|
+
* the child, and broke in two compounding ways once a project had real traffic:
|
|
163
|
+
*
|
|
164
|
+
* - Because the write path expands every trial into the child, both marginals
|
|
165
|
+
* and the global row (`weightCellsFor`), the parent's counts grow with total
|
|
166
|
+
* project volume. A cell then needed roughly sqrt(m * N_parent) exposures
|
|
167
|
+
* before its own rate mattered — ~1,400 against a 100k-exposure parent, not
|
|
168
|
+
* the ~20 the constant advertises. Personalization effectively never arrived.
|
|
169
|
+
* - Worse, the child inherited the parent's CONFIDENCE along with its rate. A
|
|
170
|
+
* 20-exposure cell emerged with a posterior of pseudo-count ~8,400 and a
|
|
171
|
+
* standard deviation of 0.002 against the ~0.09 its evidence justifies.
|
|
172
|
+
* Thompson Sampling draws from that posterior are effectively deterministic,
|
|
173
|
+
* so exploration collapsed exactly in the thin cells that needed it.
|
|
174
|
+
*
|
|
175
|
+
* `strength` is itself damped by the parent's mass so a parent that has barely
|
|
176
|
+
* any data of its own cannot inject `m` confident pseudo-observations of a rate
|
|
177
|
+
* nobody knows yet: an empty parent (mass 2, the flat Beta(1,1)) contributes
|
|
178
|
+
* ~1.8 pseudo-trials, a well-sampled one contributes the full `m`.
|
|
146
179
|
*/
|
|
147
|
-
declare function shrunkPosterior(
|
|
180
|
+
declare function shrunkPosterior(cell: {
|
|
148
181
|
alpha: number;
|
|
149
182
|
beta: number;
|
|
150
|
-
exposures: number;
|
|
151
183
|
}, pooled: {
|
|
152
184
|
alpha: number;
|
|
153
185
|
beta: number;
|
|
@@ -191,11 +223,45 @@ declare function posteriorOfCounts(c: PoolCounts): {
|
|
|
191
223
|
* Every cell is optional; an absent cell contributes Beta(1,1)-with-0-evidence,
|
|
192
224
|
* which is what lets the same function reproduce the legacy variant (segment-only)
|
|
193
225
|
* and legacy slot (persona-only) behaviors on day one after migration.
|
|
226
|
+
*
|
|
227
|
+
* Only the parent's MEAN crosses each shrink boundary (see shrunkPosterior) —
|
|
228
|
+
* never its sample size. That is what keeps a thin child's posterior as WIDE as
|
|
229
|
+
* its own evidence warrants, so Thompson Sampling still explores it. The blend
|
|
230
|
+
* weight below therefore decides which axis sets the parent's rate; the levels'
|
|
231
|
+
* absolute magnitudes no longer leak into the child's confidence.
|
|
194
232
|
*/
|
|
195
233
|
declare function pooledPosterior(cells: PoolCells, personaKnown: boolean, m?: number): {
|
|
196
234
|
alpha: number;
|
|
197
235
|
beta: number;
|
|
198
236
|
};
|
|
237
|
+
/** A weight row's value-posterior columns, plus the cell it belongs to. */
|
|
238
|
+
type ValueCellRow = {
|
|
239
|
+
segment: string;
|
|
240
|
+
persona: string;
|
|
241
|
+
valueSum: number;
|
|
242
|
+
valueCount: number;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* The value cell for EV ranking: the BROADEST cell present for an arm.
|
|
246
|
+
*
|
|
247
|
+
* Never a sum across cells. `weightCellsFor` writes each trial to the child,
|
|
248
|
+
* both marginals AND the global row, so adding them up counts every real order
|
|
249
|
+
* 2-4x depending on whether the persona was known. The average survives that
|
|
250
|
+
* (numerator and denominator inflate together) but the EB shrinkage weight does
|
|
251
|
+
* not: `valueCount / (valueCount + EV_SHRINK_K)` with K = 20 is meant to give a
|
|
252
|
+
* cell its own voice at ~20 valued orders, and at 4x inflation it happened at
|
|
253
|
+
* 5 — by a factor that varied with the arm's persona mix, so identical arms
|
|
254
|
+
* shrank differently.
|
|
255
|
+
*
|
|
256
|
+
* The broadest cell already holds every trial in its slice exactly once, which
|
|
257
|
+
* makes this correct for both serving views: the pooled hierarchy (up to four
|
|
258
|
+
* rows per arm, global wins) and the legacy marginal view (exactly one row per
|
|
259
|
+
* arm, which is therefore the broadest).
|
|
260
|
+
*/
|
|
261
|
+
declare function broadestValueCell(rows: readonly ValueCellRow[]): {
|
|
262
|
+
valueSum: number;
|
|
263
|
+
valueCount: number;
|
|
264
|
+
};
|
|
199
265
|
/**
|
|
200
266
|
* Write-side cell expansion: which weight rows one trial/credit must bump.
|
|
201
267
|
* Unknown persona bumps ONLY the segment marginal + global — no 'unknown'
|
|
@@ -238,4 +304,87 @@ declare function shrunkAvgValue(cell: ValueCell, reference: number, k?: number):
|
|
|
238
304
|
type EvArm = ArmPosterior & ValueCell;
|
|
239
305
|
declare function sampleArmEv(arms: EvArm[], reference: number, rand?: () => number): string | null;
|
|
240
306
|
|
|
241
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Per-project persona vocabularies (spec: 2026-08-27-declared-personas-design.md).
|
|
309
|
+
*
|
|
310
|
+
* The persona axis stops being the closed global union in `personas.ts` and
|
|
311
|
+
* becomes a per-project member list (persona_sets / persona_set_members,
|
|
312
|
+
* migration 113). This module owns resolution: which persona a decision is
|
|
313
|
+
* keyed on, given what the customer's app declared and what clustering
|
|
314
|
+
* inferred. The weight tables and pooling are already string-generic —
|
|
315
|
+
* resolution is the only place vocabulary rules live.
|
|
316
|
+
*/
|
|
317
|
+
/**
|
|
318
|
+
* Key shape for vocabulary members. Personas are partition labels that land in
|
|
319
|
+
* slot_weights and in customers' CSS selectors — no '@', no spaces, no
|
|
320
|
+
* uppercase, so emails/usernames structurally cannot become partition keys.
|
|
321
|
+
* MUST stay in sync with the CHECK constraint in migration 113.
|
|
322
|
+
*/
|
|
323
|
+
declare const PERSONA_KEY_RE: RegExp;
|
|
324
|
+
/**
|
|
325
|
+
* Keys no vocabulary member may claim. 'unknown' and '__all__' are structural
|
|
326
|
+
* in weightCellsFor / CONTRACTS §4; the plural forms are pre-069 legacy labels
|
|
327
|
+
* that canonicalPersona still remaps, so a member claiming one would be
|
|
328
|
+
* silently rewritten at resolve time. MUST stay in sync with migration 113.
|
|
329
|
+
*/
|
|
330
|
+
declare const RESERVED_PERSONA_KEYS: readonly string[];
|
|
331
|
+
type PersonaVocabularyMember = {
|
|
332
|
+
key: string;
|
|
333
|
+
displayName: string;
|
|
334
|
+
/** Prior keys (renames) that resolve to this member. */
|
|
335
|
+
aliases?: readonly string[];
|
|
336
|
+
/** Retired members stop resolving but their weight rows keep pooling. */
|
|
337
|
+
status?: 'active' | 'retired';
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* The pinned four as a vocabulary — what every project's version-1 default set
|
|
341
|
+
* contains, and the fallback when a project has no active set (a missed
|
|
342
|
+
* app-code insert degrades to today's behaviour, never an error).
|
|
343
|
+
*/
|
|
344
|
+
declare const DEFAULT_PERSONA_VOCABULARY: readonly PersonaVocabularyMember[];
|
|
345
|
+
type PersonaResolution = {
|
|
346
|
+
/** Vocabulary key, or 'unknown'. This is what decisions/weights key on. */
|
|
347
|
+
persona: string;
|
|
348
|
+
/** Which path produced the persona; 'none' means nothing resolved. */
|
|
349
|
+
source: 'declared' | 'inferred' | 'none';
|
|
350
|
+
/** Declared is ground truth from the customer's own app → 1. Otherwise the
|
|
351
|
+
* portrait reliability the caller passed through (0 when absent). */
|
|
352
|
+
confidence: number;
|
|
353
|
+
/** Set when a declared value did not resolve — feeds the dashboard's
|
|
354
|
+
* "your app sent 'staff' 1.2k times, add it?" nudge. Normalized and
|
|
355
|
+
* truncated; never served. */
|
|
356
|
+
unrecognizedDeclared?: string;
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* Resolves the persona a decision is keyed on.
|
|
360
|
+
*
|
|
361
|
+
* Precedence, in order:
|
|
362
|
+
* 1. Declared value matching an active member (directly, via alias, or via a
|
|
363
|
+
* legacy plural label whose canonical form is a member) → that key,
|
|
364
|
+
* confidence 1. Declared skips reliability gating: it is ground truth from
|
|
365
|
+
* the customer's app, the same trust level as everything else the pk_ key
|
|
366
|
+
* sends.
|
|
367
|
+
* 2. Declared present but unrecognized → NOT served (a config gap is not a
|
|
368
|
+
* signal); reported via `unrecognizedDeclared` and resolution falls through
|
|
369
|
+
* to the inferred path, byte-identical to an undeclared session.
|
|
370
|
+
* 3. Inferred cluster label, canonicalized, but only if the active vocabulary
|
|
371
|
+
* still contains it — a retired member must not keep being served just
|
|
372
|
+
* because the nightly refit still emits its label.
|
|
373
|
+
*/
|
|
374
|
+
declare function resolvePersona(input: {
|
|
375
|
+
declared?: string | null;
|
|
376
|
+
clusterLabel?: string | null;
|
|
377
|
+
inferredConfidence?: number | null;
|
|
378
|
+
}, members?: readonly PersonaVocabularyMember[]): PersonaResolution;
|
|
379
|
+
/**
|
|
380
|
+
* Normalizes a DECISION-TIME persona (slot_decisions / layout_decisions rows)
|
|
381
|
+
* for training. Unlike `canonicalPersona`, this trusts the stored value
|
|
382
|
+
* verbatim: it was validated against the project vocabulary when the decision
|
|
383
|
+
* was written, and re-squashing it through the closed global union at close-out
|
|
384
|
+
* silently rerouted every declared-persona trial onto the 'unknown' marginals
|
|
385
|
+
* (the double-squash bug, spec §4.3). Only the legacy plural labels are still
|
|
386
|
+
* remapped — pre-069 rows carry them.
|
|
387
|
+
*/
|
|
388
|
+
declare function decisionPersona(label: string | null | undefined): string;
|
|
389
|
+
|
|
390
|
+
export { type ArmPosterior, CLUSTER_PRIORITY, DEFAULT_PERSONA_VOCABULARY, EV_SHRINK_K, type EvArm, LEGACY_PERSONA_MAP, type LearnedLayout, PERSONAS, PERSONA_DISPLAY, PERSONA_KEY_RE, POOL_ALL, type Persona, type PersonaKey, type PersonaResolution, type PersonaVocabularyMember, type PoolCells, type PoolCounts, RESERVED_PERSONA_KEYS, SHRINKAGE_M, type SlotDecl, type SlotResult, UNKNOWN_PERSONA, type ValueCell, type ValueCellRow, applyClusterHeuristic, broadestValueCell, candidateLayouts, canonicalArm, canonicalPersona, chooseLayout, confidenceBand, decisionPersona, fnv1a, hashLayout, marginalArmKey, parseArm, pickDeterministicArm, pooledPosterior, posteriorOfCounts, resolvePersona, sampleArm, sampleArmEv, sampleBeta, shrunkAvgValue, shrunkPosterior, slotBaselineArm, slotResultFor, validateSlotDecl, weightCellsFor };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,9 +21,12 @@ declare const CLUSTER_PRIORITY: Record<Persona, string[]>;
|
|
|
21
21
|
/**
|
|
22
22
|
* Reorders section IDs based on the persona's semantic priority.
|
|
23
23
|
* Sections with no graph entry are treated as 'generic'.
|
|
24
|
-
* Returns the input unchanged for
|
|
24
|
+
* Returns the input unchanged for 'unknown' — and for any custom vocabulary
|
|
25
|
+
* persona (declared/discovered): those have no semantic prior, so they serve
|
|
26
|
+
* the natural order until the layout bandit has learned rows, the same
|
|
27
|
+
* cold-start posture 'unknown' gets.
|
|
25
28
|
*/
|
|
26
|
-
declare function applyClusterHeuristic(sections: string[], sectionTypes: Map<string, string>, persona:
|
|
29
|
+
declare function applyClusterHeuristic(sections: string[], sectionTypes: Map<string, string>, persona: string): string[];
|
|
27
30
|
/**
|
|
28
31
|
* The candidate layout orderings for a page — the distinct section orders
|
|
29
32
|
* produced by every persona's semantic priority (plus the requesting
|
|
@@ -31,7 +34,7 @@ declare function applyClusterHeuristic(sections: string[], sectionTypes: Map<str
|
|
|
31
34
|
* "arms" the layout bandit explores. Returned as hash → order so it joins
|
|
32
35
|
* directly against layout_weights rows keyed by the same hashLayout.
|
|
33
36
|
*/
|
|
34
|
-
declare function candidateLayouts(sections: string[], sectionTypes: Map<string, string>, persona:
|
|
37
|
+
declare function candidateLayouts(sections: string[], sectionTypes: Map<string, string>, persona: string): Map<string, string[]>;
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
40
|
* Stable 16-char SHA-256 prefix for a section order array.
|
|
@@ -62,7 +65,7 @@ type LearnedLayout = {
|
|
|
62
65
|
* NON-DETERMINISTIC. Pass a seeded PRNG when you need a reproducible layout
|
|
63
66
|
* (tests, replayable decisions) — otherwise the sampled order varies per call.
|
|
64
67
|
*/
|
|
65
|
-
declare function chooseLayout(sections: string[], sectionTypes: Map<string, string>, persona:
|
|
68
|
+
declare function chooseLayout(sections: string[], sectionTypes: Map<string, string>, persona: string, learned: Map<string, LearnedLayout>, rand?: () => number): string[];
|
|
66
69
|
|
|
67
70
|
/** Learned Beta(alpha, beta) posterior for one arm. */
|
|
68
71
|
type ArmPosterior = {
|
|
@@ -134,20 +137,49 @@ declare function validateSlotDecl(decl: SlotDecl): {
|
|
|
134
137
|
*/
|
|
135
138
|
declare function slotResultFor(decl: SlotDecl, arm: string): SlotResult;
|
|
136
139
|
|
|
137
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Empirical-Bayes pooling strength, in pseudo-observations. A cell is born
|
|
142
|
+
* holding `m` imaginary trials drawn at its parent's rate, and its own data
|
|
143
|
+
* outvotes them once it has collected more than `m` real ones.
|
|
144
|
+
*/
|
|
138
145
|
declare const SHRINKAGE_M = 20;
|
|
139
146
|
/**
|
|
140
|
-
* Empirical-Bayes
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
147
|
+
* Empirical-Bayes shrinkage toward a parent posterior, at read time.
|
|
148
|
+
* Pinned in CONTRACTS.md §4.
|
|
149
|
+
*
|
|
150
|
+
* A cell is born warm — with no data of its own it sits at the parent's rate —
|
|
151
|
+
* and detaches as its own evidence accumulates.
|
|
152
|
+
*
|
|
153
|
+
* mu = pooled.alpha / (pooled.alpha + pooled.beta) // parent's rate
|
|
154
|
+
* strength = m * mass / (mass + m), mass = pooled.alpha + pooled.beta
|
|
155
|
+
* alpha' = cell.alpha + strength * mu
|
|
156
|
+
* beta' = cell.beta + strength * (1 - mu)
|
|
157
|
+
*
|
|
158
|
+
* The prior contributes a FIXED number of pseudo-observations, never a copy of
|
|
159
|
+
* the parent's counts. That distinction is the whole point of this function.
|
|
160
|
+
* The previous form was `cell.alpha + w * pooled.alpha` with
|
|
161
|
+
* `w = m / (m + cell.exposures)`, which folded the parent's SAMPLE SIZE into
|
|
162
|
+
* the child, and broke in two compounding ways once a project had real traffic:
|
|
163
|
+
*
|
|
164
|
+
* - Because the write path expands every trial into the child, both marginals
|
|
165
|
+
* and the global row (`weightCellsFor`), the parent's counts grow with total
|
|
166
|
+
* project volume. A cell then needed roughly sqrt(m * N_parent) exposures
|
|
167
|
+
* before its own rate mattered — ~1,400 against a 100k-exposure parent, not
|
|
168
|
+
* the ~20 the constant advertises. Personalization effectively never arrived.
|
|
169
|
+
* - Worse, the child inherited the parent's CONFIDENCE along with its rate. A
|
|
170
|
+
* 20-exposure cell emerged with a posterior of pseudo-count ~8,400 and a
|
|
171
|
+
* standard deviation of 0.002 against the ~0.09 its evidence justifies.
|
|
172
|
+
* Thompson Sampling draws from that posterior are effectively deterministic,
|
|
173
|
+
* so exploration collapsed exactly in the thin cells that needed it.
|
|
174
|
+
*
|
|
175
|
+
* `strength` is itself damped by the parent's mass so a parent that has barely
|
|
176
|
+
* any data of its own cannot inject `m` confident pseudo-observations of a rate
|
|
177
|
+
* nobody knows yet: an empty parent (mass 2, the flat Beta(1,1)) contributes
|
|
178
|
+
* ~1.8 pseudo-trials, a well-sampled one contributes the full `m`.
|
|
146
179
|
*/
|
|
147
|
-
declare function shrunkPosterior(
|
|
180
|
+
declare function shrunkPosterior(cell: {
|
|
148
181
|
alpha: number;
|
|
149
182
|
beta: number;
|
|
150
|
-
exposures: number;
|
|
151
183
|
}, pooled: {
|
|
152
184
|
alpha: number;
|
|
153
185
|
beta: number;
|
|
@@ -191,11 +223,45 @@ declare function posteriorOfCounts(c: PoolCounts): {
|
|
|
191
223
|
* Every cell is optional; an absent cell contributes Beta(1,1)-with-0-evidence,
|
|
192
224
|
* which is what lets the same function reproduce the legacy variant (segment-only)
|
|
193
225
|
* and legacy slot (persona-only) behaviors on day one after migration.
|
|
226
|
+
*
|
|
227
|
+
* Only the parent's MEAN crosses each shrink boundary (see shrunkPosterior) —
|
|
228
|
+
* never its sample size. That is what keeps a thin child's posterior as WIDE as
|
|
229
|
+
* its own evidence warrants, so Thompson Sampling still explores it. The blend
|
|
230
|
+
* weight below therefore decides which axis sets the parent's rate; the levels'
|
|
231
|
+
* absolute magnitudes no longer leak into the child's confidence.
|
|
194
232
|
*/
|
|
195
233
|
declare function pooledPosterior(cells: PoolCells, personaKnown: boolean, m?: number): {
|
|
196
234
|
alpha: number;
|
|
197
235
|
beta: number;
|
|
198
236
|
};
|
|
237
|
+
/** A weight row's value-posterior columns, plus the cell it belongs to. */
|
|
238
|
+
type ValueCellRow = {
|
|
239
|
+
segment: string;
|
|
240
|
+
persona: string;
|
|
241
|
+
valueSum: number;
|
|
242
|
+
valueCount: number;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* The value cell for EV ranking: the BROADEST cell present for an arm.
|
|
246
|
+
*
|
|
247
|
+
* Never a sum across cells. `weightCellsFor` writes each trial to the child,
|
|
248
|
+
* both marginals AND the global row, so adding them up counts every real order
|
|
249
|
+
* 2-4x depending on whether the persona was known. The average survives that
|
|
250
|
+
* (numerator and denominator inflate together) but the EB shrinkage weight does
|
|
251
|
+
* not: `valueCount / (valueCount + EV_SHRINK_K)` with K = 20 is meant to give a
|
|
252
|
+
* cell its own voice at ~20 valued orders, and at 4x inflation it happened at
|
|
253
|
+
* 5 — by a factor that varied with the arm's persona mix, so identical arms
|
|
254
|
+
* shrank differently.
|
|
255
|
+
*
|
|
256
|
+
* The broadest cell already holds every trial in its slice exactly once, which
|
|
257
|
+
* makes this correct for both serving views: the pooled hierarchy (up to four
|
|
258
|
+
* rows per arm, global wins) and the legacy marginal view (exactly one row per
|
|
259
|
+
* arm, which is therefore the broadest).
|
|
260
|
+
*/
|
|
261
|
+
declare function broadestValueCell(rows: readonly ValueCellRow[]): {
|
|
262
|
+
valueSum: number;
|
|
263
|
+
valueCount: number;
|
|
264
|
+
};
|
|
199
265
|
/**
|
|
200
266
|
* Write-side cell expansion: which weight rows one trial/credit must bump.
|
|
201
267
|
* Unknown persona bumps ONLY the segment marginal + global — no 'unknown'
|
|
@@ -238,4 +304,87 @@ declare function shrunkAvgValue(cell: ValueCell, reference: number, k?: number):
|
|
|
238
304
|
type EvArm = ArmPosterior & ValueCell;
|
|
239
305
|
declare function sampleArmEv(arms: EvArm[], reference: number, rand?: () => number): string | null;
|
|
240
306
|
|
|
241
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Per-project persona vocabularies (spec: 2026-08-27-declared-personas-design.md).
|
|
309
|
+
*
|
|
310
|
+
* The persona axis stops being the closed global union in `personas.ts` and
|
|
311
|
+
* becomes a per-project member list (persona_sets / persona_set_members,
|
|
312
|
+
* migration 113). This module owns resolution: which persona a decision is
|
|
313
|
+
* keyed on, given what the customer's app declared and what clustering
|
|
314
|
+
* inferred. The weight tables and pooling are already string-generic —
|
|
315
|
+
* resolution is the only place vocabulary rules live.
|
|
316
|
+
*/
|
|
317
|
+
/**
|
|
318
|
+
* Key shape for vocabulary members. Personas are partition labels that land in
|
|
319
|
+
* slot_weights and in customers' CSS selectors — no '@', no spaces, no
|
|
320
|
+
* uppercase, so emails/usernames structurally cannot become partition keys.
|
|
321
|
+
* MUST stay in sync with the CHECK constraint in migration 113.
|
|
322
|
+
*/
|
|
323
|
+
declare const PERSONA_KEY_RE: RegExp;
|
|
324
|
+
/**
|
|
325
|
+
* Keys no vocabulary member may claim. 'unknown' and '__all__' are structural
|
|
326
|
+
* in weightCellsFor / CONTRACTS §4; the plural forms are pre-069 legacy labels
|
|
327
|
+
* that canonicalPersona still remaps, so a member claiming one would be
|
|
328
|
+
* silently rewritten at resolve time. MUST stay in sync with migration 113.
|
|
329
|
+
*/
|
|
330
|
+
declare const RESERVED_PERSONA_KEYS: readonly string[];
|
|
331
|
+
type PersonaVocabularyMember = {
|
|
332
|
+
key: string;
|
|
333
|
+
displayName: string;
|
|
334
|
+
/** Prior keys (renames) that resolve to this member. */
|
|
335
|
+
aliases?: readonly string[];
|
|
336
|
+
/** Retired members stop resolving but their weight rows keep pooling. */
|
|
337
|
+
status?: 'active' | 'retired';
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* The pinned four as a vocabulary — what every project's version-1 default set
|
|
341
|
+
* contains, and the fallback when a project has no active set (a missed
|
|
342
|
+
* app-code insert degrades to today's behaviour, never an error).
|
|
343
|
+
*/
|
|
344
|
+
declare const DEFAULT_PERSONA_VOCABULARY: readonly PersonaVocabularyMember[];
|
|
345
|
+
type PersonaResolution = {
|
|
346
|
+
/** Vocabulary key, or 'unknown'. This is what decisions/weights key on. */
|
|
347
|
+
persona: string;
|
|
348
|
+
/** Which path produced the persona; 'none' means nothing resolved. */
|
|
349
|
+
source: 'declared' | 'inferred' | 'none';
|
|
350
|
+
/** Declared is ground truth from the customer's own app → 1. Otherwise the
|
|
351
|
+
* portrait reliability the caller passed through (0 when absent). */
|
|
352
|
+
confidence: number;
|
|
353
|
+
/** Set when a declared value did not resolve — feeds the dashboard's
|
|
354
|
+
* "your app sent 'staff' 1.2k times, add it?" nudge. Normalized and
|
|
355
|
+
* truncated; never served. */
|
|
356
|
+
unrecognizedDeclared?: string;
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* Resolves the persona a decision is keyed on.
|
|
360
|
+
*
|
|
361
|
+
* Precedence, in order:
|
|
362
|
+
* 1. Declared value matching an active member (directly, via alias, or via a
|
|
363
|
+
* legacy plural label whose canonical form is a member) → that key,
|
|
364
|
+
* confidence 1. Declared skips reliability gating: it is ground truth from
|
|
365
|
+
* the customer's app, the same trust level as everything else the pk_ key
|
|
366
|
+
* sends.
|
|
367
|
+
* 2. Declared present but unrecognized → NOT served (a config gap is not a
|
|
368
|
+
* signal); reported via `unrecognizedDeclared` and resolution falls through
|
|
369
|
+
* to the inferred path, byte-identical to an undeclared session.
|
|
370
|
+
* 3. Inferred cluster label, canonicalized, but only if the active vocabulary
|
|
371
|
+
* still contains it — a retired member must not keep being served just
|
|
372
|
+
* because the nightly refit still emits its label.
|
|
373
|
+
*/
|
|
374
|
+
declare function resolvePersona(input: {
|
|
375
|
+
declared?: string | null;
|
|
376
|
+
clusterLabel?: string | null;
|
|
377
|
+
inferredConfidence?: number | null;
|
|
378
|
+
}, members?: readonly PersonaVocabularyMember[]): PersonaResolution;
|
|
379
|
+
/**
|
|
380
|
+
* Normalizes a DECISION-TIME persona (slot_decisions / layout_decisions rows)
|
|
381
|
+
* for training. Unlike `canonicalPersona`, this trusts the stored value
|
|
382
|
+
* verbatim: it was validated against the project vocabulary when the decision
|
|
383
|
+
* was written, and re-squashing it through the closed global union at close-out
|
|
384
|
+
* silently rerouted every declared-persona trial onto the 'unknown' marginals
|
|
385
|
+
* (the double-squash bug, spec §4.3). Only the legacy plural labels are still
|
|
386
|
+
* remapped — pre-069 rows carry them.
|
|
387
|
+
*/
|
|
388
|
+
declare function decisionPersona(label: string | null | undefined): string;
|
|
389
|
+
|
|
390
|
+
export { type ArmPosterior, CLUSTER_PRIORITY, DEFAULT_PERSONA_VOCABULARY, EV_SHRINK_K, type EvArm, LEGACY_PERSONA_MAP, type LearnedLayout, PERSONAS, PERSONA_DISPLAY, PERSONA_KEY_RE, POOL_ALL, type Persona, type PersonaKey, type PersonaResolution, type PersonaVocabularyMember, type PoolCells, type PoolCounts, RESERVED_PERSONA_KEYS, SHRINKAGE_M, type SlotDecl, type SlotResult, UNKNOWN_PERSONA, type ValueCell, type ValueCellRow, applyClusterHeuristic, broadestValueCell, candidateLayouts, canonicalArm, canonicalPersona, chooseLayout, confidenceBand, decisionPersona, fnv1a, hashLayout, marginalArmKey, parseArm, pickDeterministicArm, pooledPosterior, posteriorOfCounts, resolvePersona, sampleArm, sampleArmEv, sampleBeta, shrunkAvgValue, shrunkPosterior, slotBaselineArm, slotResultFor, validateSlotDecl, weightCellsFor };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var M=Object.defineProperty,ie=Object.defineProperties,ue=Object.getOwnPropertyDescriptor,ce=Object.getOwnPropertyDescriptors,le=Object.getOwnPropertyNames,Y=Object.getOwnPropertySymbols;var T=Object.prototype.hasOwnProperty,fe=Object.prototype.propertyIsEnumerable;var F=(e,r,t)=>r in e?M(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,O=(e,r)=>{for(var t in r||(r={}))T.call(r,t)&&F(e,t,r[t]);if(Y)for(var t of Y(r))fe.call(r,t)&&F(e,t,r[t]);return e},E=(e,r)=>ie(e,ce(r));var me=(e,r)=>{for(var t in r)M(e,t,{get:r[t],enumerable:!0})},be=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of le(r))!T.call(e,s)&&s!==t&&M(e,s,{get:()=>r[s],enumerable:!(n=ue(r,s))||n.enumerable});return e};var pe=e=>be(M({},"__esModule",{value:!0}),e);var Ce={};me(Ce,{CLUSTER_PRIORITY:()=>Q,EV_SHRINK_K:()=>te,LEGACY_PERSONA_MAP:()=>Z,PERSONAS:()=>H,PERSONA_DISPLAY:()=>xe,POOL_ALL:()=>g,SHRINKAGE_M:()=>ee,UNKNOWN_PERSONA:()=>v,applyClusterHeuristic:()=>N,candidateLayouts:()=>U,canonicalArm:()=>G,canonicalPersona:()=>ge,chooseLayout:()=>ye,confidenceBand:()=>Re,fnv1a:()=>re,hashLayout:()=>I,marginalArmKey:()=>Pe,parseArm:()=>z,pickDeterministicArm:()=>we,pooledPosterior:()=>ve,posteriorOfCounts:()=>R,sampleArm:()=>V,sampleArmEv:()=>_e,sampleBeta:()=>S,shrunkAvgValue:()=>ne,shrunkPosterior:()=>w,slotBaselineArm:()=>X,slotResultFor:()=>Ae,validateSlotDecl:()=>ke,weightCellsFor:()=>Se});module.exports=pe(Ce);var H=["buyer","researcher","deal_seeker","browser"],v="unknown",xe={buyer:"Buyer",researcher:"Researcher",deal_seeker:"Deal seeker",browser:"Browser",unknown:"Unknown"},Z={buyers:"buyer",researchers:"researcher","deal-seekers":"deal_seeker",browsers:"browser",buyer:"buyer",researcher:"researcher",deal_seeker:"deal_seeker",browser:"browser"};function ge(e){var t;if(e==null)return v;let r=e.trim().toLowerCase();return(t=Z[r])!=null?t:v}var de=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function x(e,r){return e>>>r|e<<32-r}function J(e){return(e>>>0).toString(16).padStart(8,"0")}function he(e){let r=new TextEncoder().encode(e),t=r.length,n=t*8,s=(t+8>>6)+1<<6,o=new Uint8Array(s);o.set(r),o[t]=128;let a=new DataView(o.buffer);a.setUint32(s-8,Math.floor(n/4294967296),!1),a.setUint32(s-4,n>>>0,!1);let u=1779033703,c=3144134277,m=1013904242,l=2773480762,p=1359893119,b=2600822924,y=528734635,P=1541459225,f=new Uint32Array(64);for(let L=0;L<s;L+=64){for(let i=0;i<16;i++)f[i]=a.getUint32(L+i*4,!1);for(let i=16;i<64;i++){let $=x(f[i-15],7)^x(f[i-15],18)^f[i-15]>>>3,j=x(f[i-2],17)^x(f[i-2],19)^f[i-2]>>>10;f[i]=f[i-16]+$+f[i-7]+j>>>0}let d=u,k=c,A=m,q=l,h=p,_=b,C=y,D=P;for(let i=0;i<64;i++){let $=x(h,6)^x(h,11)^x(h,25),j=h&_^~h&C,W=D+$+j+de[i]+f[i]>>>0,oe=x(d,2)^x(d,13)^x(d,22),se=d&k^d&A^k&A,ae=oe+se>>>0;D=C,C=_,_=h,h=q+W>>>0,q=A,A=k,k=d,d=W+ae>>>0}u=u+d>>>0,c=c+k>>>0,m=m+A>>>0,l=l+q>>>0,p=p+h>>>0,b=b+_>>>0,y=y+C>>>0,P=P+D>>>0}return J(u)+J(c)}function I(e){return he(e.join("|"))}var Q={buyer:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],researcher:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],deal_seeker:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],browser:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]};function N(e,r,t){let n=t===v?void 0:Q[t];if(!n)return e;let s=n.indexOf("generic"),o=a=>{let u=n.indexOf(a);return u===-1?s:u};return[...e].sort((a,u)=>{var l,p;let c=(l=r.get(a))!=null?l:"generic",m=(p=r.get(u))!=null?p:"generic";return o(c)-o(m)})}function U(e,r,t){let n=new Map;for(let s of[...H,t]){let o=N(e,r,s);n.set(I(o),o)}return n}function B(e,r){if(e<1)return B(1+e,r)*Math.pow(Math.max(1e-15,r()),1/e);let t=e-1/3,n=1/Math.sqrt(9*t);for(;;){let s,o;do{let u=Math.max(1e-15,r()),c=r();s=Math.sqrt(-2*Math.log(u))*Math.cos(2*Math.PI*c),o=1+n*s}while(o<=0);o=o*o*o;let a=r();if(a<1-.0331*s*s*s*s||Math.log(a)<.5*s*s+t*(1-o+Math.log(o)))return t*o}}function S(e,r,t=Math.random){let n=B(e,t),s=B(r,t),o=n+s;return o<=0?e/(e+r):n/o}function V(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=e[0],n=S(t.alpha,t.beta,r);for(let s=1;s<e.length;s++){let o=e[s],a=S(o.alpha,o.beta,r);a>n&&(t=o,n=a)}return t.arm}function ye(e,r,t,n,s=Math.random){var m,l;let o=U(e,r,t),a=[];for(let p of o.keys()){let b=n.get(p);a.push({arm:p,alpha:(m=b==null?void 0:b.alpha)!=null?m:1,beta:(l=b==null?void 0:b.beta)!=null?l:1})}let u=V(a,s),c=u?o.get(u):void 0;return c!=null?c:N(e,r,t)}function G(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function z(e){if(e.length===0)return null;let r={};for(let t of e.split("|")){let n=t.indexOf("=");if(n<=0||n!==t.lastIndexOf("=")||n===t.length-1)return null;let s=t.slice(0,n);if(s in r)return null;r[s]=t.slice(n+1)}return r}function Pe(e,r){return`${e}=${r}`}function X(e){var t,n,s;if(e.arms)return typeof e.baseline=="string"?e.baseline:(t=e.arms[0])!=null?t:"";if(e.baseline!==void 0&&typeof e.baseline=="object")return G(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[o,a]of Object.entries((n=e.dims)!=null?n:{}))r[o]=(s=a[0])!=null?s:"";return G(r)}function ke(e){let r=Array.isArray(e.arms),t=e.dims!=null;if(r&&t)return{ok:!1,reason:"declare exactly one of arms or dims (got both)"};if(!r&&!t)return{ok:!1,reason:"declare exactly one of arms or dims (got neither)"};if(r){let o=e.arms;if(o.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(o.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(o).size!==o.length)return{ok:!1,reason:"arms must be unique"};if(o.some(a=>a.includes("=")))return{ok:!1,reason:"enumerated arm ids may not contain '=' (reserved for dims encoding)"};if(e.baseline!==void 0){if(typeof e.baseline!="string")return{ok:!1,reason:"baseline for an arms slot must be a string"};if(!o.includes(e.baseline))return{ok:!1,reason:"baseline must be one of the declared arms"}}return{ok:!0}}let n=Object.entries(e.dims);if(n.length<1)return{ok:!1,reason:"dims requires at least 1 dimension"};if(n.length>4)return{ok:!1,reason:"dims allows at most 4 dimensions"};let s=1;for(let[o,a]of n){if(a.length<2)return{ok:!1,reason:`dim "${o}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${o}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${o}" has duplicate values`};s*=a.length}if(s>64)return{ok:!1,reason:`declared space of ${s} combinations exceeds the 64 maximum`};if(e.baseline!==void 0){if(typeof e.baseline=="string")return{ok:!1,reason:"baseline for a dims slot must be a per-dim record"};let o=e.baseline,a=n.map(([c])=>c).sort(),u=Object.keys(o).sort();if(a.join(" ")!==u.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[c,m]of n)if(!m.includes(o[c]))return{ok:!1,reason:`baseline value for dim "${c}" is not declared`}}return{ok:!0}}function Ae(e,r){var t,n;return e.dims!=null?(n=(t=z(r))!=null?t:z(X(e)))!=null?n:{}:r}var ee=20;function w(e,r,t=20){let n=t/(t+e.exposures);return{alpha:e.alpha+n*r.alpha,beta:e.beta+n*r.beta}}var g="__all__",K={exposures:0,conversions:0};function R(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function ve(e,r,t=20){var b,y,P,f;let n=(b=e.segment)!=null?b:K,s=(y=e.global)!=null?y:K,o=R(s),a=w(E(O({},R(n)),{exposures:n.exposures}),o,t);if(!r)return a;let u=(P=e.persona)!=null?P:K,c=(f=e.child)!=null?f:K,m=w(E(O({},R(u)),{exposures:u.exposures}),o,t),l=(n.exposures+1)/(n.exposures+u.exposures+2),p={alpha:l*a.alpha+(1-l)*m.alpha,beta:l*a.beta+(1-l)*m.beta};return w(E(O({},R(c)),{exposures:c.exposures}),p,t)}function Se(e,r){return r==="unknown"||r===g||r===""?[{segment:e,persona:g},{segment:g,persona:g}]:[{segment:e,persona:r},{segment:e,persona:g},{segment:g,persona:r},{segment:g,persona:g}]}function re(e){let r=2166136261;for(let t=0;t<e.length;t++)r^=e.charCodeAt(t),r=r+((r<<1)+(r<<4)+(r<<7)+(r<<8)+(r<<24))>>>0;return r}function we(e,r,t){if(t.length===0)throw new Error("pickDeterministicArm requires at least one arm");let n=[...t].sort();return n[re(`${e}:${r}`)%n.length]}function Re(e){return e>=.3?e<.7?"medium":"high":"low"}var te=20;function ne(e,r,t=te){let n=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return n;if(e.valueCount<=0)return r;let s=e.valueCount/(e.valueCount+t);return s*n+(1-s)*r}function _e(e,r,t=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=null,s=-1/0;for(let o of e){let a=S(o.alpha,o.beta,t)*ne(o,r);a>s&&(n=o,s=a)}return n.arm}0&&(module.exports={CLUSTER_PRIORITY,EV_SHRINK_K,LEGACY_PERSONA_MAP,PERSONAS,PERSONA_DISPLAY,POOL_ALL,SHRINKAGE_M,UNKNOWN_PERSONA,applyClusterHeuristic,candidateLayouts,canonicalArm,canonicalPersona,chooseLayout,confidenceBand,fnv1a,hashLayout,marginalArmKey,parseArm,pickDeterministicArm,pooledPosterior,posteriorOfCounts,sampleArm,sampleArmEv,sampleBeta,shrunkAvgValue,shrunkPosterior,slotBaselineArm,slotResultFor,validateSlotDecl,weightCellsFor});
|
|
1
|
+
"use strict";var L=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames,T=Object.getOwnPropertySymbols;var X=Object.prototype.hasOwnProperty,me=Object.prototype.propertyIsEnumerable;var Z=(e,r,n)=>r in e?L(e,r,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[r]=n,$=(e,r)=>{for(var n in r||(r={}))X.call(r,n)&&Z(e,n,r[n]);if(T)for(var n of T(r))me.call(r,n)&&Z(e,n,r[n]);return e};var be=(e,r)=>{for(var n in r)L(e,n,{get:r[n],enumerable:!0})},pe=(e,r,n,t)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of fe(r))!X.call(e,s)&&s!==n&&L(e,s,{get:()=>r[s],enumerable:!(t=ce(r,s))||t.enumerable});return e};var ge=e=>pe(L({},"__esModule",{value:!0}),e);var Oe={};be(Oe,{CLUSTER_PRIORITY:()=>Q,DEFAULT_PERSONA_VOCABULARY:()=>ae,EV_SHRINK_K:()=>te,LEGACY_PERSONA_MAP:()=>M,PERSONAS:()=>S,PERSONA_DISPLAY:()=>j,PERSONA_KEY_RE:()=>we,POOL_ALL:()=>g,RESERVED_PERSONA_KEYS:()=>se,SHRINKAGE_M:()=>re,UNKNOWN_PERSONA:()=>y,applyClusterHeuristic:()=>O,broadestValueCell:()=>Re,candidateLayouts:()=>z,canonicalArm:()=>G,canonicalPersona:()=>N,chooseLayout:()=>he,confidenceBand:()=>_e,decisionPersona:()=>Ne,fnv1a:()=>ne,hashLayout:()=>H,marginalArmKey:()=>ye,parseArm:()=>F,pickDeterministicArm:()=>ve,pooledPosterior:()=>ke,posteriorOfCounts:()=>C,resolvePersona:()=>Me,sampleArm:()=>Y,sampleArmEv:()=>Ce,sampleBeta:()=>v,shrunkAvgValue:()=>oe,shrunkPosterior:()=>_,slotBaselineArm:()=>ee,slotResultFor:()=>Ae,validateSlotDecl:()=>Pe,weightCellsFor:()=>Se});module.exports=ge(Oe);var S=["buyer","researcher","deal_seeker","browser"],y="unknown",j={buyer:"Buyer",researcher:"Researcher",deal_seeker:"Deal seeker",browser:"Browser",unknown:"Unknown"},M={buyers:"buyer",researchers:"researcher","deal-seekers":"deal_seeker",browsers:"browser",buyer:"buyer",researcher:"researcher",deal_seeker:"deal_seeker",browser:"browser"};function N(e){var n;if(e==null)return y;let r=e.trim().toLowerCase();return(n=M[r])!=null?n:y}var de=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function d(e,r){return e>>>r|e<<32-r}function J(e){return(e>>>0).toString(16).padStart(8,"0")}function xe(e){let r=new TextEncoder().encode(e),n=r.length,t=n*8,s=(n+8>>6)+1<<6,o=new Uint8Array(s);o.set(r),o[n]=128;let a=new DataView(o.buffer);a.setUint32(s-8,Math.floor(t/4294967296),!1),a.setUint32(s-4,t>>>0,!1);let i=1779033703,u=3144134277,f=1013904242,c=2773480762,p=1359893119,m=2600822924,P=528734635,A=1541459225,b=new Uint32Array(64);for(let K=0;K<s;K+=64){for(let l=0;l<16;l++)b[l]=a.getUint32(K+l*4,!1);for(let l=16;l<64;l++){let q=d(b[l-15],7)^d(b[l-15],18)^b[l-15]>>>3,I=d(b[l-2],17)^d(b[l-2],19)^b[l-2]>>>10;b[l]=b[l-16]+q+b[l-7]+I>>>0}let x=i,k=u,R=f,V=c,h=p,w=m,E=P,U=A;for(let l=0;l<64;l++){let q=d(h,6)^d(h,11)^d(h,25),I=h&w^~h&E,W=U+q+I+de[l]+b[l]>>>0,ie=d(x,2)^d(x,13)^d(x,22),ue=x&k^x&R^k&R,le=ie+ue>>>0;U=E,E=w,w=h,h=V+W>>>0,V=R,R=k,k=x,x=W+le>>>0}i=i+x>>>0,u=u+k>>>0,f=f+R>>>0,c=c+V>>>0,p=p+h>>>0,m=m+w>>>0,P=P+E>>>0,A=A+U>>>0}return J(i)+J(u)}function H(e){return xe(e.join("|"))}var Q={buyer:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],researcher:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],deal_seeker:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],browser:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]};function O(e,r,n){let t=Q[n];if(!t)return e;let s=t.indexOf("generic"),o=a=>{let i=t.indexOf(a);return i===-1?s:i};return[...e].sort((a,i)=>{var c,p;let u=(c=r.get(a))!=null?c:"generic",f=(p=r.get(i))!=null?p:"generic";return o(u)-o(f)})}function z(e,r,n){let t=new Map;for(let s of[...S,n]){let o=O(e,r,s);t.set(H(o),o)}return t}function B(e,r){if(e<1)return B(1+e,r)*Math.pow(Math.max(1e-15,r()),1/e);let n=e-1/3,t=1/Math.sqrt(9*n);for(;;){let s,o;do{let i=Math.max(1e-15,r()),u=r();s=Math.sqrt(-2*Math.log(i))*Math.cos(2*Math.PI*u),o=1+t*s}while(o<=0);o=o*o*o;let a=r();if(a<1-.0331*s*s*s*s||Math.log(a)<.5*s*s+n*(1-o+Math.log(o)))return n*o}}function v(e,r,n=Math.random){let t=B(e,n),s=B(r,n),o=t+s;return o<=0?e/(e+r):t/o}function Y(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=e[0],t=v(n.alpha,n.beta,r);for(let s=1;s<e.length;s++){let o=e[s],a=v(o.alpha,o.beta,r);a>t&&(n=o,t=a)}return n.arm}function he(e,r,n,t,s=Math.random){var f,c;let o=z(e,r,n),a=[];for(let p of o.keys()){let m=t.get(p);a.push({arm:p,alpha:(f=m==null?void 0:m.alpha)!=null?f:1,beta:(c=m==null?void 0:m.beta)!=null?c:1})}let i=Y(a,s),u=i?o.get(i):void 0;return u!=null?u:O(e,r,n)}function G(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function F(e){if(e.length===0)return null;let r={};for(let n of e.split("|")){let t=n.indexOf("=");if(t<=0||t!==n.lastIndexOf("=")||t===n.length-1)return null;let s=n.slice(0,t);if(s in r)return null;r[s]=n.slice(t+1)}return r}function ye(e,r){return`${e}=${r}`}function ee(e){var n,t,s;if(e.arms)return typeof e.baseline=="string"?e.baseline:(n=e.arms[0])!=null?n:"";if(e.baseline!==void 0&&typeof e.baseline=="object")return G(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[o,a]of Object.entries((t=e.dims)!=null?t:{}))r[o]=(s=a[0])!=null?s:"";return G(r)}function Pe(e){let r=Array.isArray(e.arms),n=e.dims!=null;if(r&&n)return{ok:!1,reason:"declare exactly one of arms or dims (got both)"};if(!r&&!n)return{ok:!1,reason:"declare exactly one of arms or dims (got neither)"};if(r){let o=e.arms;if(o.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(o.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(o).size!==o.length)return{ok:!1,reason:"arms must be unique"};if(o.some(a=>a.includes("=")))return{ok:!1,reason:"enumerated arm ids may not contain '=' (reserved for dims encoding)"};if(e.baseline!==void 0){if(typeof e.baseline!="string")return{ok:!1,reason:"baseline for an arms slot must be a string"};if(!o.includes(e.baseline))return{ok:!1,reason:"baseline must be one of the declared arms"}}return{ok:!0}}let t=Object.entries(e.dims);if(t.length<1)return{ok:!1,reason:"dims requires at least 1 dimension"};if(t.length>4)return{ok:!1,reason:"dims allows at most 4 dimensions"};let s=1;for(let[o,a]of t){if(a.length<2)return{ok:!1,reason:`dim "${o}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${o}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${o}" has duplicate values`};s*=a.length}if(s>64)return{ok:!1,reason:`declared space of ${s} combinations exceeds the 64 maximum`};if(e.baseline!==void 0){if(typeof e.baseline=="string")return{ok:!1,reason:"baseline for a dims slot must be a per-dim record"};let o=e.baseline,a=t.map(([u])=>u).sort(),i=Object.keys(o).sort();if(a.join(" ")!==i.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[u,f]of t)if(!f.includes(o[u]))return{ok:!1,reason:`baseline value for dim "${u}" is not declared`}}return{ok:!0}}function Ae(e,r){var n,t;return e.dims!=null?(t=(n=F(r))!=null?n:F(ee(e)))!=null?t:{}:r}var re=20;function _(e,r,n=20){let t=r.alpha+r.beta;if(t<=0||n<=0)return{alpha:e.alpha,beta:e.beta};let s=r.alpha/t,o=n*t/(t+n);return{alpha:e.alpha+o*s,beta:e.beta+o*(1-s)}}var g="__all__",D={exposures:0,conversions:0};function C(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function ke(e,r,n=20){var m,P,A,b;let t=(m=e.segment)!=null?m:D,s=(P=e.global)!=null?P:D,o=C(s),a=_(C(t),o,n);if(!r)return a;let i=(A=e.persona)!=null?A:D,u=(b=e.child)!=null?b:D,f=_(C(i),o,n),c=(t.exposures+1)/(t.exposures+i.exposures+2),p={alpha:c*a.alpha+(1-c)*f.alpha,beta:c*a.beta+(1-c)*f.beta};return _(C(u),p,n)}function Re(e){var t,s;let r=null,n=-1;for(let o of e){let a=o.segment===g,i=o.persona===g,u=a&&i?3:a||i?2:1;u>n&&(n=u,r=o)}return{valueSum:(t=r==null?void 0:r.valueSum)!=null?t:0,valueCount:(s=r==null?void 0:r.valueCount)!=null?s:0}}function Se(e,r){return r==="unknown"||r===g||r===""?[{segment:e,persona:g},{segment:g,persona:g}]:[{segment:e,persona:r},{segment:e,persona:g},{segment:g,persona:r},{segment:g,persona:g}]}function ne(e){let r=2166136261;for(let n=0;n<e.length;n++)r^=e.charCodeAt(n),r=r+((r<<1)+(r<<4)+(r<<7)+(r<<8)+(r<<24))>>>0;return r}function ve(e,r,n){if(n.length===0)throw new Error("pickDeterministicArm requires at least one arm");let t=[...n].sort();return t[ne(`${e}:${r}`)%t.length]}function _e(e){return e>=.3?e<.7?"medium":"high":"low"}var te=20;function oe(e,r,n=te){let t=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return t;if(e.valueCount<=0)return r;let s=e.valueCount/(e.valueCount+n);return s*t+(1-s)*r}function Ce(e,r,n=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=null,s=-1/0;for(let o of e){let a=v(o.alpha,o.beta,n)*oe(o,r);a>s&&(t=o,s=a)}return t.arm}var we=/^[a-z0-9][a-z0-9_-]{0,31}$/,se=["unknown","__all__","buyers","researchers","deal-seekers","browsers"],ae=S.map(e=>({key:e,displayName:j[e]})),Ee=64;function Le(e){var n;let r=new Map;for(let t of e)if(t.status!=="retired"){r.set(t.key,t.key);for(let s of(n=t.aliases)!=null?n:[])se.includes(s)||r.set(s,t.key)}return r}function Me(e,r=ae){var i,u,f;let n=Le(r),t=(i=e.inferredConfidence)!=null?i:0,s,o=(f=(u=e.declared)==null?void 0:u.trim().toLowerCase())!=null?f:"";if(o!==""){let c=n.get(o),p=c===void 0?n.get(N(o)):void 0,m=c!=null?c:p;if(m!==void 0)return{persona:m,source:"declared",confidence:1};s=o.slice(0,Ee)}let a=N(e.clusterLabel);return a!==y&&n.has(a)?$({persona:n.get(a),source:"inferred",confidence:t},s!==void 0&&{unrecognizedDeclared:s}):$({persona:y,source:"none",confidence:t},s!==void 0&&{unrecognizedDeclared:s})}function Ne(e){var n;if(e==null)return y;let r=e.trim().toLowerCase();return r===""?y:(n=M[r])!=null?n:r}0&&(module.exports={CLUSTER_PRIORITY,DEFAULT_PERSONA_VOCABULARY,EV_SHRINK_K,LEGACY_PERSONA_MAP,PERSONAS,PERSONA_DISPLAY,PERSONA_KEY_RE,POOL_ALL,RESERVED_PERSONA_KEYS,SHRINKAGE_M,UNKNOWN_PERSONA,applyClusterHeuristic,broadestValueCell,candidateLayouts,canonicalArm,canonicalPersona,chooseLayout,confidenceBand,decisionPersona,fnv1a,hashLayout,marginalArmKey,parseArm,pickDeterministicArm,pooledPosterior,posteriorOfCounts,resolvePersona,sampleArm,sampleArmEv,sampleBeta,shrunkAvgValue,shrunkPosterior,slotBaselineArm,slotResultFor,validateSlotDecl,weightCellsFor});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var X=Object.defineProperty,ee=Object.defineProperties;var re=Object.getOwnPropertyDescriptors;var I=Object.getOwnPropertySymbols;var te=Object.prototype.hasOwnProperty,ne=Object.prototype.propertyIsEnumerable;var U=(e,r,t)=>r in e?X(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,w=(e,r)=>{for(var t in r||(r={}))te.call(r,t)&&U(e,t,r[t]);if(I)for(var t of I(r))ne.call(r,t)&&U(e,t,r[t]);return e},R=(e,r)=>ee(e,re(r));var B=["buyer","researcher","deal_seeker","browser"],_="unknown",be={buyer:"Buyer",researcher:"Researcher",deal_seeker:"Deal seeker",browser:"Browser",unknown:"Unknown"},oe={buyers:"buyer",researchers:"researcher","deal-seekers":"deal_seeker",browsers:"browser",buyer:"buyer",researcher:"researcher",deal_seeker:"deal_seeker",browser:"browser"};function pe(e){var t;if(e==null)return _;let r=e.trim().toLowerCase();return(t=oe[r])!=null?t:_}var se=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function x(e,r){return e>>>r|e<<32-r}function V(e){return(e>>>0).toString(16).padStart(8,"0")}function ae(e){let r=new TextEncoder().encode(e),t=r.length,n=t*8,s=(t+8>>6)+1<<6,o=new Uint8Array(s);o.set(r),o[t]=128;let a=new DataView(o.buffer);a.setUint32(s-8,Math.floor(n/4294967296),!1),a.setUint32(s-4,n>>>0,!1);let u=1779033703,c=3144134277,m=1013904242,l=2773480762,p=1359893119,b=2600822924,y=528734635,P=1541459225,f=new Uint32Array(64);for(let N=0;N<s;N+=64){for(let i=0;i<16;i++)f[i]=a.getUint32(N+i*4,!1);for(let i=16;i<64;i++){let q=x(f[i-15],7)^x(f[i-15],18)^f[i-15]>>>3,D=x(f[i-2],17)^x(f[i-2],19)^f[i-2]>>>10;f[i]=f[i-16]+q+f[i-7]+D>>>0}let g=u,k=c,A=m,K=l,d=p,v=b,S=y,L=P;for(let i=0;i<64;i++){let q=x(d,6)^x(d,11)^x(d,25),D=d&v^~d&S,H=L+q+D+se[i]+f[i]>>>0,Z=x(g,2)^x(g,13)^x(g,22),J=g&k^g&A^k&A,Q=Z+J>>>0;L=S,S=v,v=d,d=K+H>>>0,K=A,A=k,k=g,g=H+Q>>>0}u=u+g>>>0,c=c+k>>>0,m=m+A>>>0,l=l+K>>>0,p=p+d>>>0,b=b+v>>>0,y=y+S>>>0,P=P+L>>>0}return V(u)+V(c)}function G(e){return ae(e.join("|"))}var ie={buyer:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],researcher:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],deal_seeker:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],browser:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]};function $(e,r,t){let n=t===_?void 0:ie[t];if(!n)return e;let s=n.indexOf("generic"),o=a=>{let u=n.indexOf(a);return u===-1?s:u};return[...e].sort((a,u)=>{var l,p;let c=(l=r.get(a))!=null?l:"generic",m=(p=r.get(u))!=null?p:"generic";return o(c)-o(m)})}function z(e,r,t){let n=new Map;for(let s of[...B,t]){let o=$(e,r,s);n.set(G(o),o)}return n}function j(e,r){if(e<1)return j(1+e,r)*Math.pow(Math.max(1e-15,r()),1/e);let t=e-1/3,n=1/Math.sqrt(9*t);for(;;){let s,o;do{let u=Math.max(1e-15,r()),c=r();s=Math.sqrt(-2*Math.log(u))*Math.cos(2*Math.PI*c),o=1+n*s}while(o<=0);o=o*o*o;let a=r();if(a<1-.0331*s*s*s*s||Math.log(a)<.5*s*s+t*(1-o+Math.log(o)))return t*o}}function C(e,r,t=Math.random){let n=j(e,t),s=j(r,t),o=n+s;return o<=0?e/(e+r):n/o}function W(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=e[0],n=C(t.alpha,t.beta,r);for(let s=1;s<e.length;s++){let o=e[s],a=C(o.alpha,o.beta,r);a>n&&(t=o,n=a)}return t.arm}function ve(e,r,t,n,s=Math.random){var m,l;let o=z(e,r,t),a=[];for(let p of o.keys()){let b=n.get(p);a.push({arm:p,alpha:(m=b==null?void 0:b.alpha)!=null?m:1,beta:(l=b==null?void 0:b.beta)!=null?l:1})}let u=W(a,s),c=u?o.get(u):void 0;return c!=null?c:$(e,r,t)}function Y(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function F(e){if(e.length===0)return null;let r={};for(let t of e.split("|")){let n=t.indexOf("=");if(n<=0||n!==t.lastIndexOf("=")||n===t.length-1)return null;let s=t.slice(0,n);if(s in r)return null;r[s]=t.slice(n+1)}return r}function we(e,r){return`${e}=${r}`}function ue(e){var t,n,s;if(e.arms)return typeof e.baseline=="string"?e.baseline:(t=e.arms[0])!=null?t:"";if(e.baseline!==void 0&&typeof e.baseline=="object")return Y(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[o,a]of Object.entries((n=e.dims)!=null?n:{}))r[o]=(s=a[0])!=null?s:"";return Y(r)}function Re(e){let r=Array.isArray(e.arms),t=e.dims!=null;if(r&&t)return{ok:!1,reason:"declare exactly one of arms or dims (got both)"};if(!r&&!t)return{ok:!1,reason:"declare exactly one of arms or dims (got neither)"};if(r){let o=e.arms;if(o.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(o.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(o).size!==o.length)return{ok:!1,reason:"arms must be unique"};if(o.some(a=>a.includes("=")))return{ok:!1,reason:"enumerated arm ids may not contain '=' (reserved for dims encoding)"};if(e.baseline!==void 0){if(typeof e.baseline!="string")return{ok:!1,reason:"baseline for an arms slot must be a string"};if(!o.includes(e.baseline))return{ok:!1,reason:"baseline must be one of the declared arms"}}return{ok:!0}}let n=Object.entries(e.dims);if(n.length<1)return{ok:!1,reason:"dims requires at least 1 dimension"};if(n.length>4)return{ok:!1,reason:"dims allows at most 4 dimensions"};let s=1;for(let[o,a]of n){if(a.length<2)return{ok:!1,reason:`dim "${o}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${o}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${o}" has duplicate values`};s*=a.length}if(s>64)return{ok:!1,reason:`declared space of ${s} combinations exceeds the 64 maximum`};if(e.baseline!==void 0){if(typeof e.baseline=="string")return{ok:!1,reason:"baseline for a dims slot must be a per-dim record"};let o=e.baseline,a=n.map(([c])=>c).sort(),u=Object.keys(o).sort();if(a.join(" ")!==u.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[c,m]of n)if(!m.includes(o[c]))return{ok:!1,reason:`baseline value for dim "${c}" is not declared`}}return{ok:!0}}function _e(e,r){var t,n;return e.dims!=null?(n=(t=F(r))!=null?t:F(ue(e)))!=null?n:{}:r}var T=20;function M(e,r,t=20){let n=t/(t+e.exposures);return{alpha:e.alpha+n*r.alpha,beta:e.beta+n*r.beta}}var h="__all__",O={exposures:0,conversions:0};function E(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function Ee(e,r,t=20){var b,y,P,f;let n=(b=e.segment)!=null?b:O,s=(y=e.global)!=null?y:O,o=E(s),a=M(R(w({},E(n)),{exposures:n.exposures}),o,t);if(!r)return a;let u=(P=e.persona)!=null?P:O,c=(f=e.child)!=null?f:O,m=M(R(w({},E(u)),{exposures:u.exposures}),o,t),l=(n.exposures+1)/(n.exposures+u.exposures+2),p={alpha:l*a.alpha+(1-l)*m.alpha,beta:l*a.beta+(1-l)*m.beta};return M(R(w({},E(c)),{exposures:c.exposures}),p,t)}function Ne(e,r){return r==="unknown"||r===h||r===""?[{segment:e,persona:h},{segment:h,persona:h}]:[{segment:e,persona:r},{segment:e,persona:h},{segment:h,persona:r},{segment:h,persona:h}]}function ce(e){let r=2166136261;for(let t=0;t<e.length;t++)r^=e.charCodeAt(t),r=r+((r<<1)+(r<<4)+(r<<7)+(r<<8)+(r<<24))>>>0;return r}function qe(e,r,t){if(t.length===0)throw new Error("pickDeterministicArm requires at least one arm");let n=[...t].sort();return n[ce(`${e}:${r}`)%n.length]}function De(e){return e>=.3?e<.7?"medium":"high":"low"}var le=20;function fe(e,r,t=le){let n=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return n;if(e.valueCount<=0)return r;let s=e.valueCount/(e.valueCount+t);return s*n+(1-s)*r}function He(e,r,t=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=null,s=-1/0;for(let o of e){let a=C(o.alpha,o.beta,t)*fe(o,r);a>s&&(n=o,s=a)}return n.arm}export{ie as CLUSTER_PRIORITY,le as EV_SHRINK_K,oe as LEGACY_PERSONA_MAP,B as PERSONAS,be as PERSONA_DISPLAY,h as POOL_ALL,T as SHRINKAGE_M,_ as UNKNOWN_PERSONA,$ as applyClusterHeuristic,z as candidateLayouts,Y as canonicalArm,pe as canonicalPersona,ve as chooseLayout,De as confidenceBand,ce as fnv1a,G as hashLayout,we as marginalArmKey,F as parseArm,qe as pickDeterministicArm,Ee as pooledPosterior,E as posteriorOfCounts,W as sampleArm,He as sampleArmEv,C as sampleBeta,fe as shrunkAvgValue,M as shrunkPosterior,ue as slotBaselineArm,_e as slotResultFor,Re as validateSlotDecl,Ne as weightCellsFor};
|
|
1
|
+
var re=Object.defineProperty;var H=Object.getOwnPropertySymbols;var ne=Object.prototype.hasOwnProperty,te=Object.prototype.propertyIsEnumerable;var z=(e,r,n)=>r in e?re(e,r,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[r]=n,V=(e,r)=>{for(var n in r||(r={}))ne.call(r,n)&&z(e,n,r[n]);if(H)for(var n of H(r))te.call(r,n)&&z(e,n,r[n]);return e};var _=["buyer","researcher","deal_seeker","browser"],y="unknown",B={buyer:"Buyer",researcher:"Researcher",deal_seeker:"Deal seeker",browser:"Browser",unknown:"Unknown"},U={buyers:"buyer",researchers:"researcher","deal-seekers":"deal_seeker",browsers:"browser",buyer:"buyer",researcher:"researcher",deal_seeker:"deal_seeker",browser:"browser"};function q(e){var n;if(e==null)return y;let r=e.trim().toLowerCase();return(n=U[r])!=null?n:y}var oe=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function g(e,r){return e>>>r|e<<32-r}function Y(e){return(e>>>0).toString(16).padStart(8,"0")}function se(e){let r=new TextEncoder().encode(e),n=r.length,t=n*8,s=(n+8>>6)+1<<6,o=new Uint8Array(s);o.set(r),o[n]=128;let a=new DataView(o.buffer);a.setUint32(s-8,Math.floor(t/4294967296),!1),a.setUint32(s-4,t>>>0,!1);let i=1779033703,u=3144134277,f=1013904242,c=2773480762,p=1359893119,m=2600822924,P=528734635,A=1541459225,b=new Uint32Array(64);for(let M=0;M<s;M+=64){for(let l=0;l<16;l++)b[l]=a.getUint32(M+l*4,!1);for(let l=16;l<64;l++){let D=g(b[l-15],7)^g(b[l-15],18)^b[l-15]>>>3,K=g(b[l-2],17)^g(b[l-2],19)^b[l-2]>>>10;b[l]=b[l-16]+D+b[l-7]+K>>>0}let x=i,k=u,R=f,N=c,h=p,S=m,v=P,O=A;for(let l=0;l<64;l++){let D=g(h,6)^g(h,11)^g(h,25),K=h&S^~h&v,j=O+D+K+oe[l]+b[l]>>>0,J=g(x,2)^g(x,13)^g(x,22),Q=x&k^x&R^k&R,ee=J+Q>>>0;O=v,v=S,S=h,h=N+j>>>0,N=R,R=k,k=x,x=j+ee>>>0}i=i+x>>>0,u=u+k>>>0,f=f+R>>>0,c=c+N>>>0,p=p+h>>>0,m=m+S>>>0,P=P+v>>>0,A=A+O>>>0}return Y(i)+Y(u)}function G(e){return se(e.join("|"))}var ae={buyer:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],researcher:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],deal_seeker:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],browser:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]};function I(e,r,n){let t=ae[n];if(!t)return e;let s=t.indexOf("generic"),o=a=>{let i=t.indexOf(a);return i===-1?s:i};return[...e].sort((a,i)=>{var c,p;let u=(c=r.get(a))!=null?c:"generic",f=(p=r.get(i))!=null?p:"generic";return o(u)-o(f)})}function F(e,r,n){let t=new Map;for(let s of[..._,n]){let o=I(e,r,s);t.set(G(o),o)}return t}function $(e,r){if(e<1)return $(1+e,r)*Math.pow(Math.max(1e-15,r()),1/e);let n=e-1/3,t=1/Math.sqrt(9*n);for(;;){let s,o;do{let i=Math.max(1e-15,r()),u=r();s=Math.sqrt(-2*Math.log(i))*Math.cos(2*Math.PI*u),o=1+t*s}while(o<=0);o=o*o*o;let a=r();if(a<1-.0331*s*s*s*s||Math.log(a)<.5*s*s+n*(1-o+Math.log(o)))return n*o}}function C(e,r,n=Math.random){let t=$(e,n),s=$(r,n),o=t+s;return o<=0?e/(e+r):t/o}function W(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=e[0],t=C(n.alpha,n.beta,r);for(let s=1;s<e.length;s++){let o=e[s],a=C(o.alpha,o.beta,r);a>t&&(n=o,t=a)}return n.arm}function Se(e,r,n,t,s=Math.random){var f,c;let o=F(e,r,n),a=[];for(let p of o.keys()){let m=t.get(p);a.push({arm:p,alpha:(f=m==null?void 0:m.alpha)!=null?f:1,beta:(c=m==null?void 0:m.beta)!=null?c:1})}let i=W(a,s),u=i?o.get(i):void 0;return u!=null?u:I(e,r,n)}function T(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function Z(e){if(e.length===0)return null;let r={};for(let n of e.split("|")){let t=n.indexOf("=");if(t<=0||t!==n.lastIndexOf("=")||t===n.length-1)return null;let s=n.slice(0,t);if(s in r)return null;r[s]=n.slice(t+1)}return r}function _e(e,r){return`${e}=${r}`}function ie(e){var n,t,s;if(e.arms)return typeof e.baseline=="string"?e.baseline:(n=e.arms[0])!=null?n:"";if(e.baseline!==void 0&&typeof e.baseline=="object")return T(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[o,a]of Object.entries((t=e.dims)!=null?t:{}))r[o]=(s=a[0])!=null?s:"";return T(r)}function Ce(e){let r=Array.isArray(e.arms),n=e.dims!=null;if(r&&n)return{ok:!1,reason:"declare exactly one of arms or dims (got both)"};if(!r&&!n)return{ok:!1,reason:"declare exactly one of arms or dims (got neither)"};if(r){let o=e.arms;if(o.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(o.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(o).size!==o.length)return{ok:!1,reason:"arms must be unique"};if(o.some(a=>a.includes("=")))return{ok:!1,reason:"enumerated arm ids may not contain '=' (reserved for dims encoding)"};if(e.baseline!==void 0){if(typeof e.baseline!="string")return{ok:!1,reason:"baseline for an arms slot must be a string"};if(!o.includes(e.baseline))return{ok:!1,reason:"baseline must be one of the declared arms"}}return{ok:!0}}let t=Object.entries(e.dims);if(t.length<1)return{ok:!1,reason:"dims requires at least 1 dimension"};if(t.length>4)return{ok:!1,reason:"dims allows at most 4 dimensions"};let s=1;for(let[o,a]of t){if(a.length<2)return{ok:!1,reason:`dim "${o}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${o}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${o}" has duplicate values`};s*=a.length}if(s>64)return{ok:!1,reason:`declared space of ${s} combinations exceeds the 64 maximum`};if(e.baseline!==void 0){if(typeof e.baseline=="string")return{ok:!1,reason:"baseline for a dims slot must be a per-dim record"};let o=e.baseline,a=t.map(([u])=>u).sort(),i=Object.keys(o).sort();if(a.join(" ")!==i.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[u,f]of t)if(!f.includes(o[u]))return{ok:!1,reason:`baseline value for dim "${u}" is not declared`}}return{ok:!0}}function we(e,r){var n,t;return e.dims!=null?(t=(n=Z(r))!=null?n:Z(ie(e)))!=null?t:{}:r}var X=20;function w(e,r,n=20){let t=r.alpha+r.beta;if(t<=0||n<=0)return{alpha:e.alpha,beta:e.beta};let s=r.alpha/t,o=n*t/(t+n);return{alpha:e.alpha+o*s,beta:e.beta+o*(1-s)}}var d="__all__",E={exposures:0,conversions:0};function L(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function Ne(e,r,n=20){var m,P,A,b;let t=(m=e.segment)!=null?m:E,s=(P=e.global)!=null?P:E,o=L(s),a=w(L(t),o,n);if(!r)return a;let i=(A=e.persona)!=null?A:E,u=(b=e.child)!=null?b:E,f=w(L(i),o,n),c=(t.exposures+1)/(t.exposures+i.exposures+2),p={alpha:c*a.alpha+(1-c)*f.alpha,beta:c*a.beta+(1-c)*f.beta};return w(L(u),p,n)}function Oe(e){var t,s;let r=null,n=-1;for(let o of e){let a=o.segment===d,i=o.persona===d,u=a&&i?3:a||i?2:1;u>n&&(n=u,r=o)}return{valueSum:(t=r==null?void 0:r.valueSum)!=null?t:0,valueCount:(s=r==null?void 0:r.valueCount)!=null?s:0}}function De(e,r){return r==="unknown"||r===d||r===""?[{segment:e,persona:d},{segment:d,persona:d}]:[{segment:e,persona:r},{segment:e,persona:d},{segment:d,persona:r},{segment:d,persona:d}]}function ue(e){let r=2166136261;for(let n=0;n<e.length;n++)r^=e.charCodeAt(n),r=r+((r<<1)+(r<<4)+(r<<7)+(r<<8)+(r<<24))>>>0;return r}function Ve(e,r,n){if(n.length===0)throw new Error("pickDeterministicArm requires at least one arm");let t=[...n].sort();return t[ue(`${e}:${r}`)%t.length]}function Ue(e){return e>=.3?e<.7?"medium":"high":"low"}var le=20;function ce(e,r,n=le){let t=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return t;if(e.valueCount<=0)return r;let s=e.valueCount/(e.valueCount+n);return s*t+(1-s)*r}function $e(e,r,n=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=null,s=-1/0;for(let o of e){let a=C(o.alpha,o.beta,n)*ce(o,r);a>s&&(t=o,s=a)}return t.arm}var ze=/^[a-z0-9][a-z0-9_-]{0,31}$/,fe=["unknown","__all__","buyers","researchers","deal-seekers","browsers"],me=_.map(e=>({key:e,displayName:B[e]})),be=64;function pe(e){var n;let r=new Map;for(let t of e)if(t.status!=="retired"){r.set(t.key,t.key);for(let s of(n=t.aliases)!=null?n:[])fe.includes(s)||r.set(s,t.key)}return r}function Be(e,r=me){var i,u,f;let n=pe(r),t=(i=e.inferredConfidence)!=null?i:0,s,o=(f=(u=e.declared)==null?void 0:u.trim().toLowerCase())!=null?f:"";if(o!==""){let c=n.get(o),p=c===void 0?n.get(q(o)):void 0,m=c!=null?c:p;if(m!==void 0)return{persona:m,source:"declared",confidence:1};s=o.slice(0,be)}let a=q(e.clusterLabel);return a!==y&&n.has(a)?V({persona:n.get(a),source:"inferred",confidence:t},s!==void 0&&{unrecognizedDeclared:s}):V({persona:y,source:"none",confidence:t},s!==void 0&&{unrecognizedDeclared:s})}function Ye(e){var n;if(e==null)return y;let r=e.trim().toLowerCase();return r===""?y:(n=U[r])!=null?n:r}export{ae as CLUSTER_PRIORITY,me as DEFAULT_PERSONA_VOCABULARY,le as EV_SHRINK_K,U as LEGACY_PERSONA_MAP,_ as PERSONAS,B as PERSONA_DISPLAY,ze as PERSONA_KEY_RE,d as POOL_ALL,fe as RESERVED_PERSONA_KEYS,X as SHRINKAGE_M,y as UNKNOWN_PERSONA,I as applyClusterHeuristic,Oe as broadestValueCell,F as candidateLayouts,T as canonicalArm,q as canonicalPersona,Se as chooseLayout,Ue as confidenceBand,Ye as decisionPersona,ue as fnv1a,G as hashLayout,_e as marginalArmKey,Z as parseArm,Ve as pickDeterministicArm,Ne as pooledPosterior,L as posteriorOfCounts,Be as resolvePersona,W as sampleArm,$e as sampleArmEv,C as sampleBeta,ce as shrunkAvgValue,w as shrunkPosterior,ie as slotBaselineArm,we as slotResultFor,Ce as validateSlotDecl,De as weightCellsFor};
|