@sentientui/policy 0.10.0 → 0.11.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/README.md CHANGED
@@ -34,12 +34,12 @@ replayable decisions.
34
34
  - `LAYOUT_ARCHETYPES` / `orderByArchetype(sections, sectionTypes, archetype, sectionRoles?)` — a catalogue of orderings (`conversion_led`, `evidence_led`, `price_led`, `discovery_led`). Not a persona taxonomy.
35
35
  - `previewOrderForPersona(sections, sectionTypes, persona, sectionRoles?)` — **keyless local mode only.** Maps any persona key onto an archetype so `?sentient_persona=<anything>` visibly rearranges a page with no server. Never use it for serving.
36
36
  - `chooseLayout(sections, sectionTypes, persona, learned, rand?)` — Thompson-samples the learned layout posteriors over the candidates. The authored order is always among them, so "leave the page alone" can win.
37
- - *Deprecated:* `CLUSTER_PRIORITY` (use `LAYOUT_ARCHETYPES`), `applyClusterHeuristic` (use `orderByArchetype` on the server, `previewOrderForPersona` locally).
37
+ - *Deprecated:* `applyClusterHeuristic` (use `orderByArchetype` on the server, `previewOrderForPersona` locally).
38
38
  - `hashLayout(order)` — stable hash of a section order (the `layoutHash` key).
39
39
 
40
40
  **Personas** (`personas.ts`)
41
- - `PERSONAS`, `PersonaKey`, `UNKNOWN_PERSONA`, `PERSONA_DISPLAY` — the canonical persona set and display names.
42
- - `canonicalPersona(label)` — normalize an arbitrary/legacy label to a `PersonaKey`.
41
+ - `UNKNOWN_PERSONA`, `UNKNOWN_PERSONA_DISPLAY` — the only persona key the package defines. There is no built-in persona list: every persona comes from the project's own vocabulary (declared by the app, or promoted by discovery).
42
+ - `canonicalPersona(label)` — normalize any label to a persona key (trimmed, lowercased, key-shaped), or `'unknown'`. Says nothing about vocabulary membership.
43
43
 
44
44
  **Deterministic helpers** (`deterministic.ts`)
45
45
  - `fnv1a(input)` — FNV-1a hash.
@@ -67,7 +67,7 @@ const chosenSeeded = sampleArm(arms, mySeededRng);
67
67
  import { chooseLayout, hashLayout, type LearnedLayout } from '@sentientui/policy';
68
68
 
69
69
  const learned = new Map<string, LearnedLayout>(); // from your layout_weights store
70
- const order = chooseLayout(sections, sectionTypes, 'buyer', learned);
70
+ const order = chooseLayout(sections, sectionTypes, 'evaluator', learned); // a key from the project's own vocabulary
71
71
  const key = hashLayout(order);
72
72
  ```
73
73
 
package/dist/index.d.cts CHANGED
@@ -1,50 +1,33 @@
1
1
  import { SectionRole } from './taxonomy.cjs';
2
2
 
3
3
  /**
4
- * The four labels this product used to ship as a default vocabulary.
4
+ * The one persona key the product itself defines: "we don't know".
5
5
  *
6
- * RETAINED FOR HISTORY ONLY, and deliberately no longer a default: see
7
- * `DEFAULT_PERSONA_VOCABULARY`, which is now empty. `slot_weights`,
8
- * `variant_weights` and `slot_decisions` rows written before 2026-09-13 are
9
- * keyed on these strings, and `LEGACY_PERSONA_MAP` still has to canonicalize
10
- * the pre-069 plural spellings, so deleting them would orphan real posteriors
11
- * and break the read path for anything already stored.
12
- *
13
- * A project may still END UP with one of these keys — by declaring it, or by
14
- * discovery promoting a segment someone chose to name `buyer`. What can no
15
- * longer happen is the product asserting them on a customer's behalf.
6
+ * There is deliberately no persona LIST here. Until 2026-09-13 this module
7
+ * exported a hardcoded four-persona vocabulary (with display names and a
8
+ * plural-label alias map) that every project inherited, and the product
9
+ * presented those names as if it knew the customer's audience. Every persona
10
+ * now comes from the project's own vocabulary declared by the app or
11
+ * promoted by discovery (see `vocabulary.ts`) and anything else is
12
+ * `unknown`, which is where the pooled bandit does the actual work.
16
13
  */
17
- declare const PERSONAS: readonly ["buyer", "researcher", "deal_seeker", "browser"];
18
- type Persona = (typeof PERSONAS)[number];
19
14
  declare const UNKNOWN_PERSONA: "unknown";
20
- type PersonaKey = Persona | typeof UNKNOWN_PERSONA;
21
- /** Human-facing names dashboard/devtools copy must use these, never raw keys. */
22
- declare const PERSONA_DISPLAY: Record<PersonaKey, string>;
23
- /**
24
- * Every label ever written for a persona, mapped to its canonical form. The
25
- * plural/hyphen labels are the pre-069 cluster seed labels
26
- * ('buyers'/'deal-seekers'/…); identity mappings make canonical input a no-op.
27
- */
28
- declare const LEGACY_PERSONA_MAP: Record<string, Persona>;
29
- /**
30
- * Canonicalizes any persona/cluster label to the pinned vocabulary.
31
- * Null, undefined, empty, and unrecognized labels all become 'unknown' —
32
- * "we don't know" is always a safe answer; a guessed persona is not.
33
- */
34
- declare function canonicalPersona(label: string | null | undefined): PersonaKey;
15
+ /** Human-facing name of `UNKNOWN_PERSONA`. Every other persona's display name
16
+ * comes from its vocabulary member, never from a table in this package. */
17
+ declare const UNKNOWN_PERSONA_DISPLAY = "Unknown";
35
18
 
36
19
  /**
37
20
  * A catalogue of plausible page orderings — NOT a persona taxonomy.
38
21
  *
39
- * These four orderings were keyed by the seeded personas (`buyer`,
40
- * `researcher`, `deal_seeker`, `browser`) until 2026-09-13. Those personas were
41
- * removed, but the deeper problem was that keying orderings by persona NAME was
22
+ * These four orderings were keyed by the four seeded persona names until
23
+ * 2026-09-13 (the table was exported as `CLUSTER_PRIORITY`, now removed).
24
+ * Those personas were removed, but the deeper problem was that keying orderings by persona NAME was
42
25
  * wrong even while they existed, in two ways that were invisible until a
43
26
  * customer declared a persona of their own:
44
27
  *
45
28
  * 1. THE ARM SPACE DEPENDED ON WHAT THE CUSTOMER NAMED THEIR PERSONA. A
46
29
  * project that declared `admin` got five candidate orders including the
47
- * page exactly as authored; a project that declared `buyer` got four, and
30
+ * page exactly as authored; a project that declared one of the seeded names got four, and
48
31
  * the authored order was NOT among them — so its own page order could never
49
32
  * be served to that persona, and there was no control arm to lose to.
50
33
  * Renaming a persona silently changed which layouts were reachable.
@@ -52,7 +35,7 @@ declare function canonicalPersona(label: string | null | undefined): PersonaKey;
52
35
  * 2. THE FEASIBILITY GATE SERVED THE COLLIDING ARCHETYPE DETERMINISTICALLY.
53
36
  * `routes/decide.ts` serves a heuristic order (never explored, never
54
37
  * learned) when layout feasibility is `infeasible` — the state every new
55
- * project is in. A customer who declared `buyer` had pricing hoisted above
38
+ * project is in. A customer who declared the seeded conversion persona had pricing hoisted above
56
39
  * everything on every visit, permanently, because of a table written in
57
40
  * May; a customer who declared `admin` correctly kept their own page.
58
41
  *
@@ -68,11 +51,6 @@ declare const LAYOUT_ARCHETYPES: Record<string, readonly string[]>;
68
51
  * insertion order, so it must not depend on object-key enumeration luck. */
69
52
  declare const LAYOUT_ARCHETYPE_NAMES: readonly ["conversion_led", "evidence_led", "price_led", "discovery_led"];
70
53
  type LayoutArchetype = (typeof LAYOUT_ARCHETYPE_NAMES)[number];
71
- /**
72
- * @deprecated Use `LAYOUT_ARCHETYPES`. Retained so the published surface does
73
- * not break; the keys are the four retired personas and mean nothing now.
74
- */
75
- declare const CLUSTER_PRIORITY: Record<Persona, string[]>;
76
54
  /**
77
55
  * Reorders section IDs by one archetype's semantic priority.
78
56
  * Sections with no graph entry are treated as 'generic'.
@@ -92,7 +70,7 @@ declare function orderByArchetype(sections: string[], sectionTypes: Map<string,
92
70
  * Maps an arbitrary persona string to one archetype so that
93
71
  * `?sentient_persona=<anything>` visibly rearranges a page with no API key and
94
72
  * no server. It used to look the key up in the four-persona table, so only
95
- * those four literal strings did anything and every other key silently no-oped;
73
+ * the four seeded names did anything and every other key silently no-oped;
96
74
  * now any key previews an arrangement, which is what the docs promise.
97
75
  *
98
76
  * DO NOT USE THIS ON THE SERVER. The mapping is a hash, not a belief: it
@@ -121,7 +99,7 @@ declare const applyClusterHeuristic: typeof previewOrderForPersona;
121
99
  * something, and there is nothing for a holdout comparison to mean. Before
122
100
  * 2026-09-13 the authored order was included only by accident, when the
123
101
  * requesting persona's name happened to miss the archetype table; a persona
124
- * named `buyer` had it excluded entirely.
102
+ * whose name matched the table had it excluded entirely.
125
103
  *
126
104
  * It no longer takes a persona. The set of orderings a page COULD be shown in
127
105
  * is a property of the page, not of who is looking at it — what the persona
@@ -625,8 +603,7 @@ declare function sampleArmEv(arms: EvArm[], reference: number, rand?: () => numb
625
603
  /**
626
604
  * Per-project persona vocabularies (spec: 2026-08-27-declared-personas-design.md).
627
605
  *
628
- * The persona axis stops being the closed global union in `personas.ts` and
629
- * becomes a per-project member list (persona_sets / persona_set_members,
606
+ * The persona axis is a per-project member list (persona_sets / persona_set_members,
630
607
  * migration 113). This module owns resolution: which persona a decision is
631
608
  * keyed on, given what the customer's app declared and what clustering
632
609
  * inferred. The weight tables and pooling are already string-generic —
@@ -657,12 +634,30 @@ declare const PERSONA_KEY_RE: RegExp;
657
634
  */
658
635
  declare function normalizeDeclaredPersona(raw: string | null | undefined): string | null;
659
636
  /**
660
- * Keys no vocabulary member may claim. 'unknown' and '__all__' are structural
661
- * in weightCellsFor / CONTRACTS §4; the plural forms are pre-069 legacy labels
662
- * that canonicalPersona still remaps, so a member claiming one would be
663
- * silently rewritten at resolve time. MUST stay in sync with migration 113.
637
+ * Keys no vocabulary member may claim: 'unknown' and '__all__' are structural
638
+ * in weightCellsFor / CONTRACTS §4. MUST stay in sync with the CHECK constraint
639
+ * on persona_set_members.key (migration 113, relaxed by 153).
640
+ *
641
+ * This also reserved four plural labels until 2026-09-13, because the
642
+ * name-specific alias map that remapped them at resolve time would have
643
+ * silently rewritten a member claiming one. That map went with the seeded
644
+ * personas, so those strings are ordinary keys now.
664
645
  */
665
646
  declare const RESERVED_PERSONA_KEYS: readonly string[];
647
+ /**
648
+ * Canonicalizes any persona/cluster label to a persona KEY: trimmed,
649
+ * lowercased, and shaped like one (`PERSONA_KEY_RE`). Null, empty, and
650
+ * anything that could never be a key become 'unknown' — "we don't know" is
651
+ * always a safe answer.
652
+ *
653
+ * Generic on purpose. This used to be a lookup in a table of four seeded
654
+ * persona names, so every OTHER label — including every key a customer
655
+ * declared — folded to 'unknown': a registry pin scoped to `admin` was stored
656
+ * under 'unknown' and then applied to every unidentified visitor. It says
657
+ * nothing about membership; callers that serve must still check the project's
658
+ * vocabulary (resolvePersona does).
659
+ */
660
+ declare function canonicalPersona(label: string | null | undefined): string;
666
661
  type PersonaVocabularyMember = {
667
662
  key: string;
668
663
  displayName: string;
@@ -671,16 +666,11 @@ type PersonaVocabularyMember = {
671
666
  /** Retired members stop resolving but their weight rows keep pooling. */
672
667
  status?: 'active' | 'retired';
673
668
  };
674
- /**
675
- * The pinned four as a vocabulary — what every project's version-1 default set
676
- * contains, and the fallback when a project has no active set (a missed
677
- * app-code insert degrades to today's behaviour, never an error).
678
- */
679
669
  /**
680
670
  * The vocabulary a project has when it has declared nothing: EMPTY.
681
671
  *
682
- * This shipped as a hardcoded four buyer / researcher / deal_seeker / browser
683
- * — which the product then presented as if it knew the customer's audience.
672
+ * This shipped as a hardcoded four seeded personas, which the product then
673
+ * presented as if it knew the customer's audience.
684
674
  * Earned rows (2026-09-12) demoted them to a `starter` state; this removes them.
685
675
  *
686
676
  * The measurement that settled it, across all of production history:
@@ -724,8 +714,7 @@ type PersonaResolution = {
724
714
  * Resolves the persona a decision is keyed on.
725
715
  *
726
716
  * Precedence, in order:
727
- * 1. Declared value matching an active member (directly, via alias, or via a
728
- * legacy plural label whose canonical form is a member) → that key,
717
+ * 1. Declared value matching an active member (directly or via alias) that key,
729
718
  * confidence 1. Declared skips reliability gating: it is ground truth from
730
719
  * the customer's app, the same trust level as everything else the pk_ key
731
720
  * sends.
@@ -745,11 +734,14 @@ declare function resolvePersona(input: {
745
734
  * Normalizes a DECISION-TIME persona (slot_decisions / layout_decisions rows)
746
735
  * for training. Unlike `canonicalPersona`, this trusts the stored value
747
736
  * verbatim: it was validated against the project vocabulary when the decision
748
- * was written, and re-squashing it through the closed global union at close-out
737
+ * was written, and re-squashing it through a closed global union at close-out
749
738
  * silently rerouted every declared-persona trial onto the 'unknown' marginals
750
- * (the double-squash bug, spec §4.3). Only the legacy plural labels are still
751
- * remapped — pre-069 rows carry them.
739
+ * (the double-squash bug, spec §4.3).
740
+ *
741
+ * It also remapped four pre-069 plural labels until 2026-09-13; migration 069
742
+ * had already rewritten those rows, and the remap was keyed on the retired
743
+ * seeded names, so it went with them.
752
744
  */
753
745
  declare function decisionPersona(label: string | null | undefined): string;
754
746
 
755
- export { type ArmPosterior, CLUSTER_PRIORITY, DEFAULT_PERSONA_VOCABULARY, EV_SHRINK_K, type EvArm, type FactoredSlotChoice, GLOBAL_FACTOR_LEVEL, GLOBAL_FACTOR_PERSONA, LAYOUT_ARCHETYPES, LAYOUT_ARCHETYPE_NAMES, LAYOUT_FACTOR_BUCKETS, LEGACY_PERSONA_MAP, type LayoutArchetype, type LayoutFactorCell, 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, SLOT_FACTORS, type SlotDecl, type SlotFactor, type SlotFactorCell, type SlotFactorContext, type SlotResult, UNKNOWN_PERSONA, type ValueCell, type ValueCellRow, WEIGHTS_FALLBACK_PRIOR_PULLS, type WeightsFallbackArm, applyClusterHeuristic, broadestValueCell, candidateLayouts, canonicalArm, canonicalPersona, chooseLayout, chooseLayoutFactored, chooseSlotArmFactored, confidenceBand, decisionPersona, factorCellsForOrder, factorCellsForTrial, factorLevelsFor, fnv1a, hashLayout, layoutBucketOf, marginalArmKey, normalizeDeclaredPersona, orderByArchetype, parseArm, pickDeterministicArm, pickFromWeights, pooledPosterior, posteriorOfCounts, previewOrderForPersona, resolvePersona, sampleArm, sampleArmEv, sampleBeta, shrunkAvgValue, shrunkPosterior, slotBaselineArm, slotResultFor, validateSlotDecl, visitLevel, weightCellsFor };
747
+ export { type ArmPosterior, DEFAULT_PERSONA_VOCABULARY, EV_SHRINK_K, type EvArm, type FactoredSlotChoice, GLOBAL_FACTOR_LEVEL, GLOBAL_FACTOR_PERSONA, LAYOUT_ARCHETYPES, LAYOUT_ARCHETYPE_NAMES, LAYOUT_FACTOR_BUCKETS, type LayoutArchetype, type LayoutFactorCell, type LearnedLayout, PERSONA_KEY_RE, POOL_ALL, type PersonaResolution, type PersonaVocabularyMember, type PoolCells, type PoolCounts, RESERVED_PERSONA_KEYS, SHRINKAGE_M, SLOT_FACTORS, type SlotDecl, type SlotFactor, type SlotFactorCell, type SlotFactorContext, type SlotResult, UNKNOWN_PERSONA, UNKNOWN_PERSONA_DISPLAY, type ValueCell, type ValueCellRow, WEIGHTS_FALLBACK_PRIOR_PULLS, type WeightsFallbackArm, applyClusterHeuristic, broadestValueCell, candidateLayouts, canonicalArm, canonicalPersona, chooseLayout, chooseLayoutFactored, chooseSlotArmFactored, confidenceBand, decisionPersona, factorCellsForOrder, factorCellsForTrial, factorLevelsFor, fnv1a, hashLayout, layoutBucketOf, marginalArmKey, normalizeDeclaredPersona, orderByArchetype, parseArm, pickDeterministicArm, pickFromWeights, pooledPosterior, posteriorOfCounts, previewOrderForPersona, resolvePersona, sampleArm, sampleArmEv, sampleBeta, shrunkAvgValue, shrunkPosterior, slotBaselineArm, slotResultFor, validateSlotDecl, visitLevel, weightCellsFor };
package/dist/index.d.ts CHANGED
@@ -1,50 +1,33 @@
1
1
  import { SectionRole } from './taxonomy.js';
2
2
 
3
3
  /**
4
- * The four labels this product used to ship as a default vocabulary.
4
+ * The one persona key the product itself defines: "we don't know".
5
5
  *
6
- * RETAINED FOR HISTORY ONLY, and deliberately no longer a default: see
7
- * `DEFAULT_PERSONA_VOCABULARY`, which is now empty. `slot_weights`,
8
- * `variant_weights` and `slot_decisions` rows written before 2026-09-13 are
9
- * keyed on these strings, and `LEGACY_PERSONA_MAP` still has to canonicalize
10
- * the pre-069 plural spellings, so deleting them would orphan real posteriors
11
- * and break the read path for anything already stored.
12
- *
13
- * A project may still END UP with one of these keys — by declaring it, or by
14
- * discovery promoting a segment someone chose to name `buyer`. What can no
15
- * longer happen is the product asserting them on a customer's behalf.
6
+ * There is deliberately no persona LIST here. Until 2026-09-13 this module
7
+ * exported a hardcoded four-persona vocabulary (with display names and a
8
+ * plural-label alias map) that every project inherited, and the product
9
+ * presented those names as if it knew the customer's audience. Every persona
10
+ * now comes from the project's own vocabulary declared by the app or
11
+ * promoted by discovery (see `vocabulary.ts`) and anything else is
12
+ * `unknown`, which is where the pooled bandit does the actual work.
16
13
  */
17
- declare const PERSONAS: readonly ["buyer", "researcher", "deal_seeker", "browser"];
18
- type Persona = (typeof PERSONAS)[number];
19
14
  declare const UNKNOWN_PERSONA: "unknown";
20
- type PersonaKey = Persona | typeof UNKNOWN_PERSONA;
21
- /** Human-facing names dashboard/devtools copy must use these, never raw keys. */
22
- declare const PERSONA_DISPLAY: Record<PersonaKey, string>;
23
- /**
24
- * Every label ever written for a persona, mapped to its canonical form. The
25
- * plural/hyphen labels are the pre-069 cluster seed labels
26
- * ('buyers'/'deal-seekers'/…); identity mappings make canonical input a no-op.
27
- */
28
- declare const LEGACY_PERSONA_MAP: Record<string, Persona>;
29
- /**
30
- * Canonicalizes any persona/cluster label to the pinned vocabulary.
31
- * Null, undefined, empty, and unrecognized labels all become 'unknown' —
32
- * "we don't know" is always a safe answer; a guessed persona is not.
33
- */
34
- declare function canonicalPersona(label: string | null | undefined): PersonaKey;
15
+ /** Human-facing name of `UNKNOWN_PERSONA`. Every other persona's display name
16
+ * comes from its vocabulary member, never from a table in this package. */
17
+ declare const UNKNOWN_PERSONA_DISPLAY = "Unknown";
35
18
 
36
19
  /**
37
20
  * A catalogue of plausible page orderings — NOT a persona taxonomy.
38
21
  *
39
- * These four orderings were keyed by the seeded personas (`buyer`,
40
- * `researcher`, `deal_seeker`, `browser`) until 2026-09-13. Those personas were
41
- * removed, but the deeper problem was that keying orderings by persona NAME was
22
+ * These four orderings were keyed by the four seeded persona names until
23
+ * 2026-09-13 (the table was exported as `CLUSTER_PRIORITY`, now removed).
24
+ * Those personas were removed, but the deeper problem was that keying orderings by persona NAME was
42
25
  * wrong even while they existed, in two ways that were invisible until a
43
26
  * customer declared a persona of their own:
44
27
  *
45
28
  * 1. THE ARM SPACE DEPENDED ON WHAT THE CUSTOMER NAMED THEIR PERSONA. A
46
29
  * project that declared `admin` got five candidate orders including the
47
- * page exactly as authored; a project that declared `buyer` got four, and
30
+ * page exactly as authored; a project that declared one of the seeded names got four, and
48
31
  * the authored order was NOT among them — so its own page order could never
49
32
  * be served to that persona, and there was no control arm to lose to.
50
33
  * Renaming a persona silently changed which layouts were reachable.
@@ -52,7 +35,7 @@ declare function canonicalPersona(label: string | null | undefined): PersonaKey;
52
35
  * 2. THE FEASIBILITY GATE SERVED THE COLLIDING ARCHETYPE DETERMINISTICALLY.
53
36
  * `routes/decide.ts` serves a heuristic order (never explored, never
54
37
  * learned) when layout feasibility is `infeasible` — the state every new
55
- * project is in. A customer who declared `buyer` had pricing hoisted above
38
+ * project is in. A customer who declared the seeded conversion persona had pricing hoisted above
56
39
  * everything on every visit, permanently, because of a table written in
57
40
  * May; a customer who declared `admin` correctly kept their own page.
58
41
  *
@@ -68,11 +51,6 @@ declare const LAYOUT_ARCHETYPES: Record<string, readonly string[]>;
68
51
  * insertion order, so it must not depend on object-key enumeration luck. */
69
52
  declare const LAYOUT_ARCHETYPE_NAMES: readonly ["conversion_led", "evidence_led", "price_led", "discovery_led"];
70
53
  type LayoutArchetype = (typeof LAYOUT_ARCHETYPE_NAMES)[number];
71
- /**
72
- * @deprecated Use `LAYOUT_ARCHETYPES`. Retained so the published surface does
73
- * not break; the keys are the four retired personas and mean nothing now.
74
- */
75
- declare const CLUSTER_PRIORITY: Record<Persona, string[]>;
76
54
  /**
77
55
  * Reorders section IDs by one archetype's semantic priority.
78
56
  * Sections with no graph entry are treated as 'generic'.
@@ -92,7 +70,7 @@ declare function orderByArchetype(sections: string[], sectionTypes: Map<string,
92
70
  * Maps an arbitrary persona string to one archetype so that
93
71
  * `?sentient_persona=<anything>` visibly rearranges a page with no API key and
94
72
  * no server. It used to look the key up in the four-persona table, so only
95
- * those four literal strings did anything and every other key silently no-oped;
73
+ * the four seeded names did anything and every other key silently no-oped;
96
74
  * now any key previews an arrangement, which is what the docs promise.
97
75
  *
98
76
  * DO NOT USE THIS ON THE SERVER. The mapping is a hash, not a belief: it
@@ -121,7 +99,7 @@ declare const applyClusterHeuristic: typeof previewOrderForPersona;
121
99
  * something, and there is nothing for a holdout comparison to mean. Before
122
100
  * 2026-09-13 the authored order was included only by accident, when the
123
101
  * requesting persona's name happened to miss the archetype table; a persona
124
- * named `buyer` had it excluded entirely.
102
+ * whose name matched the table had it excluded entirely.
125
103
  *
126
104
  * It no longer takes a persona. The set of orderings a page COULD be shown in
127
105
  * is a property of the page, not of who is looking at it — what the persona
@@ -625,8 +603,7 @@ declare function sampleArmEv(arms: EvArm[], reference: number, rand?: () => numb
625
603
  /**
626
604
  * Per-project persona vocabularies (spec: 2026-08-27-declared-personas-design.md).
627
605
  *
628
- * The persona axis stops being the closed global union in `personas.ts` and
629
- * becomes a per-project member list (persona_sets / persona_set_members,
606
+ * The persona axis is a per-project member list (persona_sets / persona_set_members,
630
607
  * migration 113). This module owns resolution: which persona a decision is
631
608
  * keyed on, given what the customer's app declared and what clustering
632
609
  * inferred. The weight tables and pooling are already string-generic —
@@ -657,12 +634,30 @@ declare const PERSONA_KEY_RE: RegExp;
657
634
  */
658
635
  declare function normalizeDeclaredPersona(raw: string | null | undefined): string | null;
659
636
  /**
660
- * Keys no vocabulary member may claim. 'unknown' and '__all__' are structural
661
- * in weightCellsFor / CONTRACTS §4; the plural forms are pre-069 legacy labels
662
- * that canonicalPersona still remaps, so a member claiming one would be
663
- * silently rewritten at resolve time. MUST stay in sync with migration 113.
637
+ * Keys no vocabulary member may claim: 'unknown' and '__all__' are structural
638
+ * in weightCellsFor / CONTRACTS §4. MUST stay in sync with the CHECK constraint
639
+ * on persona_set_members.key (migration 113, relaxed by 153).
640
+ *
641
+ * This also reserved four plural labels until 2026-09-13, because the
642
+ * name-specific alias map that remapped them at resolve time would have
643
+ * silently rewritten a member claiming one. That map went with the seeded
644
+ * personas, so those strings are ordinary keys now.
664
645
  */
665
646
  declare const RESERVED_PERSONA_KEYS: readonly string[];
647
+ /**
648
+ * Canonicalizes any persona/cluster label to a persona KEY: trimmed,
649
+ * lowercased, and shaped like one (`PERSONA_KEY_RE`). Null, empty, and
650
+ * anything that could never be a key become 'unknown' — "we don't know" is
651
+ * always a safe answer.
652
+ *
653
+ * Generic on purpose. This used to be a lookup in a table of four seeded
654
+ * persona names, so every OTHER label — including every key a customer
655
+ * declared — folded to 'unknown': a registry pin scoped to `admin` was stored
656
+ * under 'unknown' and then applied to every unidentified visitor. It says
657
+ * nothing about membership; callers that serve must still check the project's
658
+ * vocabulary (resolvePersona does).
659
+ */
660
+ declare function canonicalPersona(label: string | null | undefined): string;
666
661
  type PersonaVocabularyMember = {
667
662
  key: string;
668
663
  displayName: string;
@@ -671,16 +666,11 @@ type PersonaVocabularyMember = {
671
666
  /** Retired members stop resolving but their weight rows keep pooling. */
672
667
  status?: 'active' | 'retired';
673
668
  };
674
- /**
675
- * The pinned four as a vocabulary — what every project's version-1 default set
676
- * contains, and the fallback when a project has no active set (a missed
677
- * app-code insert degrades to today's behaviour, never an error).
678
- */
679
669
  /**
680
670
  * The vocabulary a project has when it has declared nothing: EMPTY.
681
671
  *
682
- * This shipped as a hardcoded four buyer / researcher / deal_seeker / browser
683
- * — which the product then presented as if it knew the customer's audience.
672
+ * This shipped as a hardcoded four seeded personas, which the product then
673
+ * presented as if it knew the customer's audience.
684
674
  * Earned rows (2026-09-12) demoted them to a `starter` state; this removes them.
685
675
  *
686
676
  * The measurement that settled it, across all of production history:
@@ -724,8 +714,7 @@ type PersonaResolution = {
724
714
  * Resolves the persona a decision is keyed on.
725
715
  *
726
716
  * Precedence, in order:
727
- * 1. Declared value matching an active member (directly, via alias, or via a
728
- * legacy plural label whose canonical form is a member) → that key,
717
+ * 1. Declared value matching an active member (directly or via alias) that key,
729
718
  * confidence 1. Declared skips reliability gating: it is ground truth from
730
719
  * the customer's app, the same trust level as everything else the pk_ key
731
720
  * sends.
@@ -745,11 +734,14 @@ declare function resolvePersona(input: {
745
734
  * Normalizes a DECISION-TIME persona (slot_decisions / layout_decisions rows)
746
735
  * for training. Unlike `canonicalPersona`, this trusts the stored value
747
736
  * verbatim: it was validated against the project vocabulary when the decision
748
- * was written, and re-squashing it through the closed global union at close-out
737
+ * was written, and re-squashing it through a closed global union at close-out
749
738
  * silently rerouted every declared-persona trial onto the 'unknown' marginals
750
- * (the double-squash bug, spec §4.3). Only the legacy plural labels are still
751
- * remapped — pre-069 rows carry them.
739
+ * (the double-squash bug, spec §4.3).
740
+ *
741
+ * It also remapped four pre-069 plural labels until 2026-09-13; migration 069
742
+ * had already rewritten those rows, and the remap was keyed on the retired
743
+ * seeded names, so it went with them.
752
744
  */
753
745
  declare function decisionPersona(label: string | null | undefined): string;
754
746
 
755
- export { type ArmPosterior, CLUSTER_PRIORITY, DEFAULT_PERSONA_VOCABULARY, EV_SHRINK_K, type EvArm, type FactoredSlotChoice, GLOBAL_FACTOR_LEVEL, GLOBAL_FACTOR_PERSONA, LAYOUT_ARCHETYPES, LAYOUT_ARCHETYPE_NAMES, LAYOUT_FACTOR_BUCKETS, LEGACY_PERSONA_MAP, type LayoutArchetype, type LayoutFactorCell, 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, SLOT_FACTORS, type SlotDecl, type SlotFactor, type SlotFactorCell, type SlotFactorContext, type SlotResult, UNKNOWN_PERSONA, type ValueCell, type ValueCellRow, WEIGHTS_FALLBACK_PRIOR_PULLS, type WeightsFallbackArm, applyClusterHeuristic, broadestValueCell, candidateLayouts, canonicalArm, canonicalPersona, chooseLayout, chooseLayoutFactored, chooseSlotArmFactored, confidenceBand, decisionPersona, factorCellsForOrder, factorCellsForTrial, factorLevelsFor, fnv1a, hashLayout, layoutBucketOf, marginalArmKey, normalizeDeclaredPersona, orderByArchetype, parseArm, pickDeterministicArm, pickFromWeights, pooledPosterior, posteriorOfCounts, previewOrderForPersona, resolvePersona, sampleArm, sampleArmEv, sampleBeta, shrunkAvgValue, shrunkPosterior, slotBaselineArm, slotResultFor, validateSlotDecl, visitLevel, weightCellsFor };
747
+ export { type ArmPosterior, DEFAULT_PERSONA_VOCABULARY, EV_SHRINK_K, type EvArm, type FactoredSlotChoice, GLOBAL_FACTOR_LEVEL, GLOBAL_FACTOR_PERSONA, LAYOUT_ARCHETYPES, LAYOUT_ARCHETYPE_NAMES, LAYOUT_FACTOR_BUCKETS, type LayoutArchetype, type LayoutFactorCell, type LearnedLayout, PERSONA_KEY_RE, POOL_ALL, type PersonaResolution, type PersonaVocabularyMember, type PoolCells, type PoolCounts, RESERVED_PERSONA_KEYS, SHRINKAGE_M, SLOT_FACTORS, type SlotDecl, type SlotFactor, type SlotFactorCell, type SlotFactorContext, type SlotResult, UNKNOWN_PERSONA, UNKNOWN_PERSONA_DISPLAY, type ValueCell, type ValueCellRow, WEIGHTS_FALLBACK_PRIOR_PULLS, type WeightsFallbackArm, applyClusterHeuristic, broadestValueCell, candidateLayouts, canonicalArm, canonicalPersona, chooseLayout, chooseLayoutFactored, chooseSlotArmFactored, confidenceBand, decisionPersona, factorCellsForOrder, factorCellsForTrial, factorLevelsFor, fnv1a, hashLayout, layoutBucketOf, marginalArmKey, normalizeDeclaredPersona, orderByArchetype, parseArm, pickDeterministicArm, pickFromWeights, pooledPosterior, posteriorOfCounts, previewOrderForPersona, resolvePersona, sampleArm, sampleArmEv, sampleBeta, shrunkAvgValue, shrunkPosterior, slotBaselineArm, slotResultFor, validateSlotDecl, visitLevel, weightCellsFor };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var I=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames,re=Object.getOwnPropertySymbols;var ne=Object.prototype.hasOwnProperty,Ae=Object.prototype.propertyIsEnumerable;var te=(e,r,t)=>r in e?I(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,Y=(e,r)=>{for(var t in r||(r={}))ne.call(r,t)&&te(e,t,r[t]);if(re)for(var t of re(r))Ae.call(r,t)&&te(e,t,r[t]);return e};var _e=(e,r)=>{for(var t in r)I(e,t,{get:r[t],enumerable:!0})},Se=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of ve(r))!ne.call(e,o)&&o!==t&&I(e,o,{get:()=>r[o],enumerable:!(n=ye(r,o))||n.enumerable});return e};var Pe=e=>Se(I({},"__esModule",{value:!0}),e);var er={};_e(er,{CLUSTER_PRIORITY:()=>we,DEFAULT_PERSONA_VOCABULARY:()=>de,EV_SHRINK_K:()=>fe,GLOBAL_FACTOR_LEVEL:()=>U,GLOBAL_FACTOR_PERSONA:()=>le,LAYOUT_ARCHETYPES:()=>N,LAYOUT_ARCHETYPE_NAMES:()=>$,LAYOUT_FACTOR_BUCKETS:()=>z,LEGACY_PERSONA_MAP:()=>T,PERSONAS:()=>ke,PERSONA_DISPLAY:()=>Ce,PERSONA_KEY_RE:()=>me,POOL_ALL:()=>P,RESERVED_PERSONA_KEYS:()=>ge,SHRINKAGE_M:()=>ae,SLOT_FACTORS:()=>De,UNKNOWN_PERSONA:()=>R,WEIGHTS_FALLBACK_PRIOR_PULLS:()=>ie,applyClusterHeuristic:()=>Ee,broadestValueCell:()=>Ke,candidateLayouts:()=>K,canonicalArm:()=>J,canonicalPersona:()=>D,chooseLayout:()=>Oe,chooseLayoutFactored:()=>Te,chooseSlotArmFactored:()=>Ve,confidenceBand:()=>Ge,decisionPersona:()=>Qe,factorCellsForOrder:()=>Ie,factorCellsForTrial:()=>$e,factorLevelsFor:()=>X,fnv1a:()=>ce,hashLayout:()=>V,layoutBucketOf:()=>W,marginalArmKey:()=>Ye,normalizeDeclaredPersona:()=>We,orderByArchetype:()=>H,parseArm:()=>Q,pickDeterministicArm:()=>je,pickFromWeights:()=>Fe,pooledPosterior:()=>Ne,posteriorOfCounts:()=>_,previewOrderForPersona:()=>se,resolvePersona:()=>Je,sampleArm:()=>j,sampleArmEv:()=>ze,sampleBeta:()=>w,shrunkAvgValue:()=>pe,shrunkPosterior:()=>S,slotBaselineArm:()=>ue,slotResultFor:()=>qe,validateSlotDecl:()=>He,visitLevel:()=>Be,weightCellsFor:()=>Ue});module.exports=Pe(er);var ke=["buyer","researcher","deal_seeker","browser"],R="unknown",Ce={buyer:"Buyer",researcher:"Researcher",deal_seeker:"Deal seeker",browser:"Browser",unknown:"Unknown"},T={buyers:"buyer",researchers:"researcher","deal-seekers":"deal_seeker",browsers:"browser",buyer:"buyer",researcher:"researcher",deal_seeker:"deal_seeker",browser:"browser"};function D(e){var t;if(e==null)return R;let r=e.trim().toLowerCase();return(t=T[r])!=null?t:R}var Re=[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 L(e,r){return e>>>r|e<<32-r}function oe(e){return(e>>>0).toString(16).padStart(8,"0")}function Le(e){let r=new TextEncoder().encode(e),t=r.length,n=t*8,o=(t+8>>6)+1<<6,s=new Uint8Array(o);s.set(r),s[t]=128;let a=new DataView(s.buffer);a.setUint32(o-8,Math.floor(n/4294967296),!1),a.setUint32(o-4,n>>>0,!1);let l=1779033703,u=3144134277,f=1013904242,m=2773480762,y=1359893119,d=2600822924,b=528734635,c=1541459225,p=new Uint32Array(64);for(let A=0;A<o;A+=64){for(let g=0;g<16;g++)p[g]=a.getUint32(A+g*4,!1);for(let g=16;g<64;g++){let O=L(p[g-15],7)^L(p[g-15],18)^p[g-15]>>>3,F=L(p[g-2],17)^L(p[g-2],19)^p[g-2]>>>10;p[g]=p[g-16]+O+p[g-7]+F>>>0}let i=l,v=u,x=f,k=m,h=y,C=d,M=b,E=c;for(let g=0;g<64;g++){let O=L(h,6)^L(h,11)^L(h,25),F=h&C^~h&M,ee=E+O+F+Re[g]+p[g]>>>0,be=L(i,2)^L(i,13)^L(i,22),xe=i&v^i&x^v&x,he=be+xe>>>0;E=M,M=C,C=h,h=k+ee>>>0,k=x,x=v,v=i,i=ee+he>>>0}l=l+i>>>0,u=u+v>>>0,f=f+x>>>0,m=m+k>>>0,y=y+h>>>0,d=d+C>>>0,b=b+M>>>0,c=c+E>>>0}return oe(l)+oe(u)}function V(e){return Le(e.join("|"))}var N={conversion_led:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],evidence_led:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],price_led:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],discovery_led:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]},$=["conversion_led","evidence_led","price_led","discovery_led"],we={buyer:[...N.conversion_led],researcher:[...N.evidence_led],deal_seeker:[...N.price_led],browser:[...N.discovery_led]};function H(e,r,t,n){let o=N[t];if(!o)return e;let s=o.indexOf("generic"),a=f=>{let m=o.indexOf(f);return m===-1?s:m},l=n?e.filter(f=>n.get(f)!=="structural"):[...e];if(l.sort((f,m)=>{var b,c;let y=(b=r.get(f))!=null?b:"generic",d=(c=r.get(m))!=null?c:"generic";return a(y)-a(d)}),!n)return l;let u=0;return e.map(f=>n.get(f)==="structural"?f:l[u++])}function Me(e){let r=2166136261;for(let t=0;t<e.length;t++)r^=e.charCodeAt(t),r=Math.imul(r,16777619)>>>0;return r>>>0}function se(e,r,t,n){if(!t||t==="unknown")return e;let o=$[Me(t)%$.length];return H(e,r,o,n)}var Ee=se;function K(e,r,t){let n=new Map;n.set(V(e),[...e]);for(let o of $){let s=H(e,r,o,t),a=V(s);n.has(a)||n.set(a,s)}return n}function q(e,r){if(e<1)return q(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 o,s;do{let l=Math.max(1e-15,r()),u=r();o=Math.sqrt(-2*Math.log(l))*Math.cos(2*Math.PI*u),s=1+n*o}while(s<=0);s=s*s*s;let a=r();if(a<1-.0331*o*o*o*o||Math.log(a)<.5*o*o+t*(1-s+Math.log(s)))return t*s}}function w(e,r,t=Math.random){let n=q(e,t),o=q(r,t),s=n+o;return s<=0?e/(e+r):n/s}function j(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=e[0],n=w(t.alpha,t.beta,r);for(let o=1;o<e.length;o++){let s=e[o],a=w(s.alpha,s.beta,r);a>n&&(t=s,n=a)}return t.arm}function Oe(e,r,t,n,o=Math.random,s){var m,y;let a=K(e,r,s),l=[];for(let d of a.keys()){let b=n.get(d);l.push({arm:d,alpha:(m=b==null?void 0:b.alpha)!=null?m:1,beta:(y=b==null?void 0:b.beta)!=null?y:1})}let u=j(l,o),f=u?a.get(u):void 0;return f!=null?f:e}var ae=20;function S(e,r,t=20){let n=r.alpha+r.beta;if(n<=0||t<=0)return{alpha:e.alpha,beta:e.beta};let o=r.alpha/n,s=t*n/(n+t);return{alpha:e.alpha+s*o,beta:e.beta+s*(1-o)}}var ie=5;function Fe(e,r){var n,o;let t=null;for(let s of e){if(!r.includes(s.variantId))continue;let a=(n=s.pulls)!=null?n:0,l=a>0?a*s.avgReward/(a+ie):0;(!t||l>t.score)&&(t={variantId:s.variantId,score:l})}return(o=t==null?void 0:t.variantId)!=null?o:null}var P="__all__",B={exposures:0,conversions:0};function _(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function Ne(e,r,t=20){var d,b,c,p;let n=(d=e.segment)!=null?d:B,o=(b=e.global)!=null?b:B,s=_(o),a=S(_(n),s,t);if(!r)return a;let l=(c=e.persona)!=null?c:B,u=(p=e.child)!=null?p:B,f=S(_(l),s,t),m=(n.exposures+1)/(n.exposures+l.exposures+2),y={alpha:m*a.alpha+(1-m)*f.alpha,beta:m*a.beta+(1-m)*f.beta};return S(_(u),y,t)}function Ke(e){var n,o;let r=null,t=-1;for(let s of e){let a=s.segment===P,l=s.persona===P,u=a&&l?3:a||l?2:1;u>t&&(t=u,r=s)}return{valueSum:(n=r==null?void 0:r.valueSum)!=null?n:0,valueCount:(o=r==null?void 0:r.valueCount)!=null?o:0}}function Ue(e,r){return r==="unknown"||r===P||r===""?[{segment:e,persona:P},{segment:P,persona:P}]:[{segment:e,persona:r},{segment:e,persona:P},{segment:P,persona:r},{segment:P,persona:P}]}var z=4,le="__global__";function W(e,r){return r<=0?0:Math.min(z-1,Math.floor(e*z/r))}function Ie(e,r){return e.map((t,n)=>{var o;return{parent:(o=r.get(t))!=null?o:"generic",bucket:W(n,e.length)}})}var G=(e,r)=>`${e}#${r}`;function Te(e,r,t,n,o=Math.random,s){var A;let a=K(e,r,s),l=new Map,u=new Map,f=0,m=0;for(let i of n)i.persona===le?(l.set(G(i.parent,i.bucket),i),f+=i.exposures,m+=i.conversions):i.persona===t&&u.set(G(i.parent,i.bucket),i);let y=_({exposures:f,conversions:m}),d=new Map,b=(i,v)=>{var O,F;let x=G(i,v),k=d.get(x);if(k!==void 0)return k;let h=l.get(x),C=S(_({exposures:(O=h==null?void 0:h.exposures)!=null?O:0,conversions:(F=h==null?void 0:h.conversions)!=null?F:0}),y),M=u.get(x),E=M?S(_({exposures:M.exposures,conversions:M.conversions}),C):C,g=w(E.alpha,E.beta,o);return d.set(x,g),g},c=null,p=-1/0;for(let i of a.values()){let v=0;for(let x=0;x<i.length;x++)v+=b((A=r.get(i[x]))!=null?A:"generic",W(x,i.length));v>p&&(p=v,c=i)}return c!=null?c:e}var U="__global__",De=["device","source","persona","visit"];function X(e){let r=[];return e.device&&r.push({factor:"device",level:e.device}),e.source&&r.push({factor:"source",level:e.source}),e.persona&&e.persona!==R&&r.push({factor:"persona",level:e.persona}),e.visit&&r.push({factor:"visit",level:e.visit}),r}var Z=(e,r,t)=>`${e}\0${r}\0${t}`;function Ve(e,r,t,n=Math.random){if(e.length===0)return null;if(e.length===1)return{arm:e[0],factorsUsed:0};let o=new Map,s=0,a=0;for(let c of t)o.set(Z(c.arm,c.factor,c.level),c),c.level===U&&(s+=c.exposures,a+=c.conversions);let l=_({exposures:s,conversions:a}),u=X(r),f=new Map,m=c=>{var A,i;let p=o.get(Z(c,"global",U));return S(_({exposures:(A=p==null?void 0:p.exposures)!=null?A:0,conversions:(i=p==null?void 0:p.conversions)!=null?i:0}),l)},y=(c,p,A)=>{let i=Z(c,p,A),v=f.get(i);if(v!==void 0)return v;let x=m(c),k=o.get(i),h=k?S(_({exposures:k.exposures,conversions:k.conversions}),x):x,C=w(h.alpha,h.beta,n);return f.set(i,C),C},d=null,b=-1/0;for(let c of e){let p=u.length===0?y(c,"global",U):0;for(let{factor:A,level:i}of u)p+=y(c,A,i);p>b&&(b=p,d=c)}return d===null?null:{arm:d,factorsUsed:u.length}}function $e(e,r,t){let n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,o=[{arm:e,factor:"global",level:U,weight:1}];for(let{factor:s,level:a}of X(r))o.push({arm:e,factor:s,level:a,weight:s==="persona"?n:1});return o}function Be(e){return e==null||!Number.isFinite(e)||e<1?null:e>1?"returning":"new"}function J(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function Q(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 o=t.slice(0,n);if(o in r)return null;r[o]=t.slice(n+1)}return r}function Ye(e,r){return`${e}=${r}`}function ue(e){var t,n,o;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 J(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[s,a]of Object.entries((n=e.dims)!=null?n:{}))r[s]=(o=a[0])!=null?o:"";return J(r)}function He(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 s=e.arms;if(s.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(s.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(s).size!==s.length)return{ok:!1,reason:"arms must be unique"};if(s.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(!s.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 o=1;for(let[s,a]of n){if(a.length<2)return{ok:!1,reason:`dim "${s}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${s}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${s}" has duplicate values`};o*=a.length}if(o>64)return{ok:!1,reason:`declared space of ${o} 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 s=e.baseline,a=n.map(([u])=>u).sort(),l=Object.keys(s).sort();if(a.join(" ")!==l.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[u,f]of n)if(!f.includes(s[u]))return{ok:!1,reason:`baseline value for dim "${u}" is not declared`}}return{ok:!0}}function qe(e,r){var t,n;return e.dims!=null?(n=(t=Q(r))!=null?t:Q(ue(e)))!=null?n:{}:r}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 je(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 Ge(e){return e>=.3?e<.7?"medium":"high":"low"}var fe=20;function pe(e,r,t=fe){let n=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return n;if(e.valueCount<=0)return r;let o=e.valueCount/(e.valueCount+t);return o*n+(1-o)*r}function ze(e,r,t=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=null,o=-1/0;for(let s of e){let a=w(s.alpha,s.beta,t)*pe(s,r);a>o&&(n=s,o=a)}return n.arm}var me=/^[a-z0-9][a-z0-9_-]{0,31}$/;function We(e){if(typeof e!="string")return null;let r=e.trim().toLowerCase();return r&&me.test(r)?r:null}var ge=["unknown","__all__","buyers","researchers","deal-seekers","browsers"],de=[],Ze=64;function Xe(e){var t;let r=new Map;for(let n of e)if(n.status!=="retired"){r.set(n.key,n.key);for(let o of(t=n.aliases)!=null?t:[])ge.includes(o)||r.set(o,n.key)}return r}function Je(e,r=de){var l,u,f;let t=Xe(r),n=(l=e.inferredConfidence)!=null?l:0,o,s=(f=(u=e.declared)==null?void 0:u.trim().toLowerCase())!=null?f:"";if(s!==""){let m=t.get(s),y=m===void 0?t.get(D(s)):void 0,d=m!=null?m:y;if(d!==void 0)return{persona:d,source:"declared",confidence:1};o=s.slice(0,Ze)}let a=D(e.clusterLabel);return a!==R&&t.has(a)?Y({persona:t.get(a),source:"inferred",confidence:n},o!==void 0&&{unrecognizedDeclared:o}):Y({persona:R,source:"none",confidence:n},o!==void 0&&{unrecognizedDeclared:o})}function Qe(e){var t;if(e==null)return R;let r=e.trim().toLowerCase();return r===""?R:(t=T[r])!=null?t:r}0&&(module.exports={CLUSTER_PRIORITY,DEFAULT_PERSONA_VOCABULARY,EV_SHRINK_K,GLOBAL_FACTOR_LEVEL,GLOBAL_FACTOR_PERSONA,LAYOUT_ARCHETYPES,LAYOUT_ARCHETYPE_NAMES,LAYOUT_FACTOR_BUCKETS,LEGACY_PERSONA_MAP,PERSONAS,PERSONA_DISPLAY,PERSONA_KEY_RE,POOL_ALL,RESERVED_PERSONA_KEYS,SHRINKAGE_M,SLOT_FACTORS,UNKNOWN_PERSONA,WEIGHTS_FALLBACK_PRIOR_PULLS,applyClusterHeuristic,broadestValueCell,candidateLayouts,canonicalArm,canonicalPersona,chooseLayout,chooseLayoutFactored,chooseSlotArmFactored,confidenceBand,decisionPersona,factorCellsForOrder,factorCellsForTrial,factorLevelsFor,fnv1a,hashLayout,layoutBucketOf,marginalArmKey,normalizeDeclaredPersona,orderByArchetype,parseArm,pickDeterministicArm,pickFromWeights,pooledPosterior,posteriorOfCounts,previewOrderForPersona,resolvePersona,sampleArm,sampleArmEv,sampleBeta,shrunkAvgValue,shrunkPosterior,slotBaselineArm,slotResultFor,validateSlotDecl,visitLevel,weightCellsFor});
1
+ "use strict";var K=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames,J=Object.getOwnPropertySymbols;var ee=Object.prototype.hasOwnProperty,Ae=Object.prototype.propertyIsEnumerable;var Q=(e,r,t)=>r in e?K(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t,$=(e,r)=>{for(var t in r||(r={}))ee.call(r,t)&&Q(e,t,r[t]);if(J)for(var t of J(r))Ae.call(r,t)&&Q(e,t,r[t]);return e};var Se=(e,r)=>{for(var t in r)K(e,t,{get:r[t],enumerable:!0})},Ce=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of ve(r))!ee.call(e,o)&&o!==t&&K(e,o,{get:()=>r[o],enumerable:!(n=ye(r,o))||n.enumerable});return e};var _e=e=>Ce(K({},"__esModule",{value:!0}),e);var Xe={};Se(Xe,{DEFAULT_PERSONA_VOCABULARY:()=>be,EV_SHRINK_K:()=>ue,GLOBAL_FACTOR_LEVEL:()=>U,GLOBAL_FACTOR_PERSONA:()=>ae,LAYOUT_ARCHETYPES:()=>te,LAYOUT_ARCHETYPE_NAMES:()=>T,LAYOUT_FACTOR_BUCKETS:()=>Y,PERSONA_KEY_RE:()=>fe,POOL_ALL:()=>_,RESERVED_PERSONA_KEYS:()=>me,SHRINKAGE_M:()=>oe,SLOT_FACTORS:()=>Ie,UNKNOWN_PERSONA:()=>M,UNKNOWN_PERSONA_DISPLAY:()=>ke,WEIGHTS_FALLBACK_PRIOR_PULLS:()=>se,applyClusterHeuristic:()=>Re,broadestValueCell:()=>Fe,candidateLayouts:()=>N,canonicalArm:()=>W,canonicalPersona:()=>ge,chooseLayout:()=>we,chooseLayoutFactored:()=>Ke,chooseSlotArmFactored:()=>Te,confidenceBand:()=>Ye,decisionPersona:()=>Ze,factorCellsForOrder:()=>Ue,factorCellsForTrial:()=>Ve,factorLevelsFor:()=>G,fnv1a:()=>le,hashLayout:()=>I,layoutBucketOf:()=>j,marginalArmKey:()=>De,normalizeDeclaredPersona:()=>pe,orderByArchetype:()=>D,parseArm:()=>Z,pickDeterministicArm:()=>qe,pickFromWeights:()=>Oe,pooledPosterior:()=>Ee,posteriorOfCounts:()=>S,previewOrderForPersona:()=>ne,resolvePersona:()=>We,sampleArm:()=>H,sampleArmEv:()=>je,sampleBeta:()=>R,shrunkAvgValue:()=>ce,shrunkPosterior:()=>C,slotBaselineArm:()=>ie,slotResultFor:()=>He,validateSlotDecl:()=>Be,visitLevel:()=>$e,weightCellsFor:()=>Ne});module.exports=_e(Xe);var M="unknown",ke="Unknown";var Le=[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 P(e,r){return e>>>r|e<<32-r}function re(e){return(e>>>0).toString(16).padStart(8,"0")}function Pe(e){let r=new TextEncoder().encode(e),t=r.length,n=t*8,o=(t+8>>6)+1<<6,s=new Uint8Array(o);s.set(r),s[t]=128;let a=new DataView(s.buffer);a.setUint32(o-8,Math.floor(n/4294967296),!1),a.setUint32(o-4,n>>>0,!1);let l=1779033703,u=3144134277,f=1013904242,m=2773480762,y=1359893119,d=2600822924,b=528734635,c=1541459225,p=new Uint32Array(64);for(let A=0;A<o;A+=64){for(let g=0;g<16;g++)p[g]=a.getUint32(A+g*4,!1);for(let g=16;g<64;g++){let E=P(p[g-15],7)^P(p[g-15],18)^p[g-15]>>>3,F=P(p[g-2],17)^P(p[g-2],19)^p[g-2]>>>10;p[g]=p[g-16]+E+p[g-7]+F>>>0}let i=l,v=u,x=f,k=m,h=y,L=d,w=b,O=c;for(let g=0;g<64;g++){let E=P(h,6)^P(h,11)^P(h,25),F=h&L^~h&w,X=O+E+F+Le[g]+p[g]>>>0,de=P(i,2)^P(i,13)^P(i,22),xe=i&v^i&x^v&x,he=de+xe>>>0;O=w,w=L,L=h,h=k+X>>>0,k=x,x=v,v=i,i=X+he>>>0}l=l+i>>>0,u=u+v>>>0,f=f+x>>>0,m=m+k>>>0,y=y+h>>>0,d=d+L>>>0,b=b+w>>>0,c=c+O>>>0}return re(l)+re(u)}function I(e){return Pe(e.join("|"))}var te={conversion_led:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],evidence_led:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],price_led:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],discovery_led:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]},T=["conversion_led","evidence_led","price_led","discovery_led"];function D(e,r,t,n){let o=te[t];if(!o)return e;let s=o.indexOf("generic"),a=f=>{let m=o.indexOf(f);return m===-1?s:m},l=n?e.filter(f=>n.get(f)!=="structural"):[...e];if(l.sort((f,m)=>{var b,c;let y=(b=r.get(f))!=null?b:"generic",d=(c=r.get(m))!=null?c:"generic";return a(y)-a(d)}),!n)return l;let u=0;return e.map(f=>n.get(f)==="structural"?f:l[u++])}function Me(e){let r=2166136261;for(let t=0;t<e.length;t++)r^=e.charCodeAt(t),r=Math.imul(r,16777619)>>>0;return r>>>0}function ne(e,r,t,n){if(!t||t==="unknown")return e;let o=T[Me(t)%T.length];return D(e,r,o,n)}var Re=ne;function N(e,r,t){let n=new Map;n.set(I(e),[...e]);for(let o of T){let s=D(e,r,o,t),a=I(s);n.has(a)||n.set(a,s)}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 o,s;do{let l=Math.max(1e-15,r()),u=r();o=Math.sqrt(-2*Math.log(l))*Math.cos(2*Math.PI*u),s=1+n*o}while(s<=0);s=s*s*s;let a=r();if(a<1-.0331*o*o*o*o||Math.log(a)<.5*o*o+t*(1-s+Math.log(s)))return t*s}}function R(e,r,t=Math.random){let n=B(e,t),o=B(r,t),s=n+o;return s<=0?e/(e+r):n/s}function H(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=e[0],n=R(t.alpha,t.beta,r);for(let o=1;o<e.length;o++){let s=e[o],a=R(s.alpha,s.beta,r);a>n&&(t=s,n=a)}return t.arm}function we(e,r,t,n,o=Math.random,s){var m,y;let a=N(e,r,s),l=[];for(let d of a.keys()){let b=n.get(d);l.push({arm:d,alpha:(m=b==null?void 0:b.alpha)!=null?m:1,beta:(y=b==null?void 0:b.beta)!=null?y:1})}let u=H(l,o),f=u?a.get(u):void 0;return f!=null?f:e}var oe=20;function C(e,r,t=20){let n=r.alpha+r.beta;if(n<=0||t<=0)return{alpha:e.alpha,beta:e.beta};let o=r.alpha/n,s=t*n/(n+t);return{alpha:e.alpha+s*o,beta:e.beta+s*(1-o)}}var se=5;function Oe(e,r){var n,o;let t=null;for(let s of e){if(!r.includes(s.variantId))continue;let a=(n=s.pulls)!=null?n:0,l=a>0?a*s.avgReward/(a+se):0;(!t||l>t.score)&&(t={variantId:s.variantId,score:l})}return(o=t==null?void 0:t.variantId)!=null?o:null}var _="__all__",V={exposures:0,conversions:0};function S(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function Ee(e,r,t=20){var d,b,c,p;let n=(d=e.segment)!=null?d:V,o=(b=e.global)!=null?b:V,s=S(o),a=C(S(n),s,t);if(!r)return a;let l=(c=e.persona)!=null?c:V,u=(p=e.child)!=null?p:V,f=C(S(l),s,t),m=(n.exposures+1)/(n.exposures+l.exposures+2),y={alpha:m*a.alpha+(1-m)*f.alpha,beta:m*a.beta+(1-m)*f.beta};return C(S(u),y,t)}function Fe(e){var n,o;let r=null,t=-1;for(let s of e){let a=s.segment===_,l=s.persona===_,u=a&&l?3:a||l?2:1;u>t&&(t=u,r=s)}return{valueSum:(n=r==null?void 0:r.valueSum)!=null?n:0,valueCount:(o=r==null?void 0:r.valueCount)!=null?o:0}}function Ne(e,r){return r==="unknown"||r===_||r===""?[{segment:e,persona:_},{segment:_,persona:_}]:[{segment:e,persona:r},{segment:e,persona:_},{segment:_,persona:r},{segment:_,persona:_}]}var Y=4,ae="__global__";function j(e,r){return r<=0?0:Math.min(Y-1,Math.floor(e*Y/r))}function Ue(e,r){return e.map((t,n)=>{var o;return{parent:(o=r.get(t))!=null?o:"generic",bucket:j(n,e.length)}})}var q=(e,r)=>`${e}#${r}`;function Ke(e,r,t,n,o=Math.random,s){var A;let a=N(e,r,s),l=new Map,u=new Map,f=0,m=0;for(let i of n)i.persona===ae?(l.set(q(i.parent,i.bucket),i),f+=i.exposures,m+=i.conversions):i.persona===t&&u.set(q(i.parent,i.bucket),i);let y=S({exposures:f,conversions:m}),d=new Map,b=(i,v)=>{var E,F;let x=q(i,v),k=d.get(x);if(k!==void 0)return k;let h=l.get(x),L=C(S({exposures:(E=h==null?void 0:h.exposures)!=null?E:0,conversions:(F=h==null?void 0:h.conversions)!=null?F:0}),y),w=u.get(x),O=w?C(S({exposures:w.exposures,conversions:w.conversions}),L):L,g=R(O.alpha,O.beta,o);return d.set(x,g),g},c=null,p=-1/0;for(let i of a.values()){let v=0;for(let x=0;x<i.length;x++)v+=b((A=r.get(i[x]))!=null?A:"generic",j(x,i.length));v>p&&(p=v,c=i)}return c!=null?c:e}var U="__global__",Ie=["device","source","persona","visit"];function G(e){let r=[];return e.device&&r.push({factor:"device",level:e.device}),e.source&&r.push({factor:"source",level:e.source}),e.persona&&e.persona!==M&&r.push({factor:"persona",level:e.persona}),e.visit&&r.push({factor:"visit",level:e.visit}),r}var z=(e,r,t)=>`${e}\0${r}\0${t}`;function Te(e,r,t,n=Math.random){if(e.length===0)return null;if(e.length===1)return{arm:e[0],factorsUsed:0};let o=new Map,s=0,a=0;for(let c of t)o.set(z(c.arm,c.factor,c.level),c),c.level===U&&(s+=c.exposures,a+=c.conversions);let l=S({exposures:s,conversions:a}),u=G(r),f=new Map,m=c=>{var A,i;let p=o.get(z(c,"global",U));return C(S({exposures:(A=p==null?void 0:p.exposures)!=null?A:0,conversions:(i=p==null?void 0:p.conversions)!=null?i:0}),l)},y=(c,p,A)=>{let i=z(c,p,A),v=f.get(i);if(v!==void 0)return v;let x=m(c),k=o.get(i),h=k?C(S({exposures:k.exposures,conversions:k.conversions}),x):x,L=R(h.alpha,h.beta,n);return f.set(i,L),L},d=null,b=-1/0;for(let c of e){let p=u.length===0?y(c,"global",U):0;for(let{factor:A,level:i}of u)p+=y(c,A,i);p>b&&(b=p,d=c)}return d===null?null:{arm:d,factorsUsed:u.length}}function Ve(e,r,t){let n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,o=[{arm:e,factor:"global",level:U,weight:1}];for(let{factor:s,level:a}of G(r))o.push({arm:e,factor:s,level:a,weight:s==="persona"?n:1});return o}function $e(e){return e==null||!Number.isFinite(e)||e<1?null:e>1?"returning":"new"}function W(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 o=t.slice(0,n);if(o in r)return null;r[o]=t.slice(n+1)}return r}function De(e,r){return`${e}=${r}`}function ie(e){var t,n,o;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 W(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[s,a]of Object.entries((n=e.dims)!=null?n:{}))r[s]=(o=a[0])!=null?o:"";return W(r)}function Be(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 s=e.arms;if(s.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(s.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(s).size!==s.length)return{ok:!1,reason:"arms must be unique"};if(s.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(!s.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 o=1;for(let[s,a]of n){if(a.length<2)return{ok:!1,reason:`dim "${s}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${s}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${s}" has duplicate values`};o*=a.length}if(o>64)return{ok:!1,reason:`declared space of ${o} 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 s=e.baseline,a=n.map(([u])=>u).sort(),l=Object.keys(s).sort();if(a.join(" ")!==l.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[u,f]of n)if(!f.includes(s[u]))return{ok:!1,reason:`baseline value for dim "${u}" is not declared`}}return{ok:!0}}function He(e,r){var t,n;return e.dims!=null?(n=(t=Z(r))!=null?t:Z(ie(e)))!=null?n:{}:r}function le(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[le(`${e}:${r}`)%n.length]}function Ye(e){return e>=.3?e<.7?"medium":"high":"low"}var ue=20;function ce(e,r,t=ue){let n=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return n;if(e.valueCount<=0)return r;let o=e.valueCount/(e.valueCount+t);return o*n+(1-o)*r}function je(e,r,t=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=null,o=-1/0;for(let s of e){let a=R(s.alpha,s.beta,t)*ce(s,r);a>o&&(n=s,o=a)}return n.arm}var fe=/^[a-z0-9][a-z0-9_-]{0,31}$/;function pe(e){if(typeof e!="string")return null;let r=e.trim().toLowerCase();return r&&fe.test(r)?r:null}var me=["unknown","__all__"];function ge(e){var r;return(r=pe(e))!=null?r:M}var be=[],ze=64;function Ge(e){var t;let r=new Map;for(let n of e)if(n.status!=="retired"){r.set(n.key,n.key);for(let o of(t=n.aliases)!=null?t:[])me.includes(o)||r.set(o,n.key)}return r}function We(e,r=be){var l,u,f;let t=Ge(r),n=(l=e.inferredConfidence)!=null?l:0,o,s=(f=(u=e.declared)==null?void 0:u.trim().toLowerCase())!=null?f:"";if(s!==""){let m=t.get(s);if(m!==void 0)return{persona:m,source:"declared",confidence:1};o=s.slice(0,ze)}let a=ge(e.clusterLabel);return a!==M&&t.has(a)?$({persona:t.get(a),source:"inferred",confidence:n},o!==void 0&&{unrecognizedDeclared:o}):$({persona:M,source:"none",confidence:n},o!==void 0&&{unrecognizedDeclared:o})}function Ze(e){if(e==null)return M;let r=e.trim().toLowerCase();return r===""?M:r}0&&(module.exports={DEFAULT_PERSONA_VOCABULARY,EV_SHRINK_K,GLOBAL_FACTOR_LEVEL,GLOBAL_FACTOR_PERSONA,LAYOUT_ARCHETYPES,LAYOUT_ARCHETYPE_NAMES,LAYOUT_FACTOR_BUCKETS,PERSONA_KEY_RE,POOL_ALL,RESERVED_PERSONA_KEYS,SHRINKAGE_M,SLOT_FACTORS,UNKNOWN_PERSONA,UNKNOWN_PERSONA_DISPLAY,WEIGHTS_FALLBACK_PRIOR_PULLS,applyClusterHeuristic,broadestValueCell,candidateLayouts,canonicalArm,canonicalPersona,chooseLayout,chooseLayoutFactored,chooseSlotArmFactored,confidenceBand,decisionPersona,factorCellsForOrder,factorCellsForTrial,factorLevelsFor,fnv1a,hashLayout,layoutBucketOf,marginalArmKey,normalizeDeclaredPersona,orderByArchetype,parseArm,pickDeterministicArm,pickFromWeights,pooledPosterior,posteriorOfCounts,previewOrderForPersona,resolvePersona,sampleArm,sampleArmEv,sampleBeta,shrunkAvgValue,shrunkPosterior,slotBaselineArm,slotResultFor,validateSlotDecl,visitLevel,weightCellsFor});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{a as T}from"./chunk-HBG7RQ56.mjs";var ve=["buyer","researcher","deal_seeker","browser"],L="unknown",Ae={buyer:"Buyer",researcher:"Researcher",deal_seeker:"Deal seeker",browser:"Browser",unknown:"Unknown"},D={buyers:"buyer",researchers:"researcher","deal-seekers":"deal_seeker",browsers:"browser",buyer:"buyer",researcher:"researcher",deal_seeker:"deal_seeker",browser:"browser"};function V(e){var t;if(e==null)return L;let r=e.trim().toLowerCase();return(t=D[r])!=null?t:L}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 k(e,r){return e>>>r|e<<32-r}function G(e){return(e>>>0).toString(16).padStart(8,"0")}function ae(e){let r=new TextEncoder().encode(e),t=r.length,n=t*8,o=(t+8>>6)+1<<6,s=new Uint8Array(o);s.set(r),s[t]=128;let a=new DataView(s.buffer);a.setUint32(o-8,Math.floor(n/4294967296),!1),a.setUint32(o-4,n>>>0,!1);let l=1779033703,u=3144134277,f=1013904242,m=2773480762,y=1359893119,d=2600822924,b=528734635,c=1541459225,p=new Uint32Array(64);for(let A=0;A<o;A+=64){for(let g=0;g<16;g++)p[g]=a.getUint32(A+g*4,!1);for(let g=16;g<64;g++){let O=k(p[g-15],7)^k(p[g-15],18)^p[g-15]>>>3,F=k(p[g-2],17)^k(p[g-2],19)^p[g-2]>>>10;p[g]=p[g-16]+O+p[g-7]+F>>>0}let i=l,v=u,x=f,S=m,h=y,P=d,w=b,E=c;for(let g=0;g<64;g++){let O=k(h,6)^k(h,11)^k(h,25),F=h&P^~h&w,j=E+O+F+se[g]+p[g]>>>0,te=k(i,2)^k(i,13)^k(i,22),ne=i&v^i&x^v&x,oe=te+ne>>>0;E=w,w=P,P=h,h=S+j>>>0,S=x,x=v,v=i,i=j+oe>>>0}l=l+i>>>0,u=u+v>>>0,f=f+x>>>0,m=m+S>>>0,y=y+h>>>0,d=d+P>>>0,b=b+w>>>0,c=c+E>>>0}return G(l)+G(u)}function $(e){return ae(e.join("|"))}var N={conversion_led:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],evidence_led:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],price_led:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],discovery_led:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]},B=["conversion_led","evidence_led","price_led","discovery_led"],ke={buyer:[...N.conversion_led],researcher:[...N.evidence_led],deal_seeker:[...N.price_led],browser:[...N.discovery_led]};function z(e,r,t,n){let o=N[t];if(!o)return e;let s=o.indexOf("generic"),a=f=>{let m=o.indexOf(f);return m===-1?s:m},l=n?e.filter(f=>n.get(f)!=="structural"):[...e];if(l.sort((f,m)=>{var b,c;let y=(b=r.get(f))!=null?b:"generic",d=(c=r.get(m))!=null?c:"generic";return a(y)-a(d)}),!n)return l;let u=0;return e.map(f=>n.get(f)==="structural"?f:l[u++])}function ie(e){let r=2166136261;for(let t=0;t<e.length;t++)r^=e.charCodeAt(t),r=Math.imul(r,16777619)>>>0;return r>>>0}function le(e,r,t,n){if(!t||t==="unknown")return e;let o=B[ie(t)%B.length];return z(e,r,o,n)}var Ce=le;function K(e,r,t){let n=new Map;n.set($(e),[...e]);for(let o of B){let s=z(e,r,o,t),a=$(s);n.has(a)||n.set(a,s)}return n}function Y(e,r){if(e<1)return Y(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 o,s;do{let l=Math.max(1e-15,r()),u=r();o=Math.sqrt(-2*Math.log(l))*Math.cos(2*Math.PI*u),s=1+n*o}while(s<=0);s=s*s*s;let a=r();if(a<1-.0331*o*o*o*o||Math.log(a)<.5*o*o+t*(1-s+Math.log(s)))return t*s}}function M(e,r,t=Math.random){let n=Y(e,t),o=Y(r,t),s=n+o;return s<=0?e/(e+r):n/s}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=M(t.alpha,t.beta,r);for(let o=1;o<e.length;o++){let s=e[o],a=M(s.alpha,s.beta,r);a>n&&(t=s,n=a)}return t.arm}function Ee(e,r,t,n,o=Math.random,s){var m,y;let a=K(e,r,s),l=[];for(let d of a.keys()){let b=n.get(d);l.push({arm:d,alpha:(m=b==null?void 0:b.alpha)!=null?m:1,beta:(y=b==null?void 0:b.beta)!=null?y:1})}let u=W(l,o),f=u?a.get(u):void 0;return f!=null?f:e}var Z=20;function C(e,r,t=20){let n=r.alpha+r.beta;if(n<=0||t<=0)return{alpha:e.alpha,beta:e.beta};let o=r.alpha/n,s=t*n/(n+t);return{alpha:e.alpha+s*o,beta:e.beta+s*(1-o)}}var ue=5;function Fe(e,r){var n,o;let t=null;for(let s of e){if(!r.includes(s.variantId))continue;let a=(n=s.pulls)!=null?n:0,l=a>0?a*s.avgReward/(a+ue):0;(!t||l>t.score)&&(t={variantId:s.variantId,score:l})}return(o=t==null?void 0:t.variantId)!=null?o:null}var R="__all__",U={exposures:0,conversions:0};function _(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function Ue(e,r,t=20){var d,b,c,p;let n=(d=e.segment)!=null?d:U,o=(b=e.global)!=null?b:U,s=_(o),a=C(_(n),s,t);if(!r)return a;let l=(c=e.persona)!=null?c:U,u=(p=e.child)!=null?p:U,f=C(_(l),s,t),m=(n.exposures+1)/(n.exposures+l.exposures+2),y={alpha:m*a.alpha+(1-m)*f.alpha,beta:m*a.beta+(1-m)*f.beta};return C(_(u),y,t)}function Ie(e){var n,o;let r=null,t=-1;for(let s of e){let a=s.segment===R,l=s.persona===R,u=a&&l?3:a||l?2:1;u>t&&(t=u,r=s)}return{valueSum:(n=r==null?void 0:r.valueSum)!=null?n:0,valueCount:(o=r==null?void 0:r.valueCount)!=null?o:0}}function Te(e,r){return r==="unknown"||r===R||r===""?[{segment:e,persona:R},{segment:R,persona:R}]:[{segment:e,persona:r},{segment:e,persona:R},{segment:R,persona:r},{segment:R,persona:R}]}var X=4,ce="__global__";function J(e,r){return r<=0?0:Math.min(X-1,Math.floor(e*X/r))}function He(e,r){return e.map((t,n)=>{var o;return{parent:(o=r.get(t))!=null?o:"generic",bucket:J(n,e.length)}})}var H=(e,r)=>`${e}#${r}`;function qe(e,r,t,n,o=Math.random,s){var A;let a=K(e,r,s),l=new Map,u=new Map,f=0,m=0;for(let i of n)i.persona===ce?(l.set(H(i.parent,i.bucket),i),f+=i.exposures,m+=i.conversions):i.persona===t&&u.set(H(i.parent,i.bucket),i);let y=_({exposures:f,conversions:m}),d=new Map,b=(i,v)=>{var O,F;let x=H(i,v),S=d.get(x);if(S!==void 0)return S;let h=l.get(x),P=C(_({exposures:(O=h==null?void 0:h.exposures)!=null?O:0,conversions:(F=h==null?void 0:h.conversions)!=null?F:0}),y),w=u.get(x),E=w?C(_({exposures:w.exposures,conversions:w.conversions}),P):P,g=M(E.alpha,E.beta,o);return d.set(x,g),g},c=null,p=-1/0;for(let i of a.values()){let v=0;for(let x=0;x<i.length;x++)v+=b((A=r.get(i[x]))!=null?A:"generic",J(x,i.length));v>p&&(p=v,c=i)}return c!=null?c:e}var I="__global__",Xe=["device","source","persona","visit"];function Q(e){let r=[];return e.device&&r.push({factor:"device",level:e.device}),e.source&&r.push({factor:"source",level:e.source}),e.persona&&e.persona!==L&&r.push({factor:"persona",level:e.persona}),e.visit&&r.push({factor:"visit",level:e.visit}),r}var q=(e,r,t)=>`${e}\0${r}\0${t}`;function Je(e,r,t,n=Math.random){if(e.length===0)return null;if(e.length===1)return{arm:e[0],factorsUsed:0};let o=new Map,s=0,a=0;for(let c of t)o.set(q(c.arm,c.factor,c.level),c),c.level===I&&(s+=c.exposures,a+=c.conversions);let l=_({exposures:s,conversions:a}),u=Q(r),f=new Map,m=c=>{var A,i;let p=o.get(q(c,"global",I));return C(_({exposures:(A=p==null?void 0:p.exposures)!=null?A:0,conversions:(i=p==null?void 0:p.conversions)!=null?i:0}),l)},y=(c,p,A)=>{let i=q(c,p,A),v=f.get(i);if(v!==void 0)return v;let x=m(c),S=o.get(i),h=S?C(_({exposures:S.exposures,conversions:S.conversions}),x):x,P=M(h.alpha,h.beta,n);return f.set(i,P),P},d=null,b=-1/0;for(let c of e){let p=u.length===0?y(c,"global",I):0;for(let{factor:A,level:i}of u)p+=y(c,A,i);p>b&&(b=p,d=c)}return d===null?null:{arm:d,factorsUsed:u.length}}function Qe(e,r,t){let n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,o=[{arm:e,factor:"global",level:I,weight:1}];for(let{factor:s,level:a}of Q(r))o.push({arm:e,factor:s,level:a,weight:s==="persona"?n:1});return o}function er(e){return e==null||!Number.isFinite(e)||e<1?null:e>1?"returning":"new"}function ee(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function re(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 o=t.slice(0,n);if(o in r)return null;r[o]=t.slice(n+1)}return r}function tr(e,r){return`${e}=${r}`}function fe(e){var t,n,o;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 ee(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[s,a]of Object.entries((n=e.dims)!=null?n:{}))r[s]=(o=a[0])!=null?o:"";return ee(r)}function nr(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 s=e.arms;if(s.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(s.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(s).size!==s.length)return{ok:!1,reason:"arms must be unique"};if(s.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(!s.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 o=1;for(let[s,a]of n){if(a.length<2)return{ok:!1,reason:`dim "${s}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${s}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${s}" has duplicate values`};o*=a.length}if(o>64)return{ok:!1,reason:`declared space of ${o} 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 s=e.baseline,a=n.map(([u])=>u).sort(),l=Object.keys(s).sort();if(a.join(" ")!==l.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[u,f]of n)if(!f.includes(s[u]))return{ok:!1,reason:`baseline value for dim "${u}" is not declared`}}return{ok:!0}}function or(e,r){var t,n;return e.dims!=null?(n=(t=re(r))!=null?t:re(fe(e)))!=null?n:{}:r}function pe(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 ar(e,r,t){if(t.length===0)throw new Error("pickDeterministicArm requires at least one arm");let n=[...t].sort();return n[pe(`${e}:${r}`)%n.length]}function ir(e){return e>=.3?e<.7?"medium":"high":"low"}var me=20;function ge(e,r,t=me){let n=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return n;if(e.valueCount<=0)return r;let o=e.valueCount/(e.valueCount+t);return o*n+(1-o)*r}function cr(e,r,t=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=null,o=-1/0;for(let s of e){let a=M(s.alpha,s.beta,t)*ge(s,r);a>o&&(n=s,o=a)}return n.arm}var de=/^[a-z0-9][a-z0-9_-]{0,31}$/;function mr(e){if(typeof e!="string")return null;let r=e.trim().toLowerCase();return r&&de.test(r)?r:null}var be=["unknown","__all__","buyers","researchers","deal-seekers","browsers"],xe=[],he=64;function ye(e){var t;let r=new Map;for(let n of e)if(n.status!=="retired"){r.set(n.key,n.key);for(let o of(t=n.aliases)!=null?t:[])be.includes(o)||r.set(o,n.key)}return r}function gr(e,r=xe){var l,u,f;let t=ye(r),n=(l=e.inferredConfidence)!=null?l:0,o,s=(f=(u=e.declared)==null?void 0:u.trim().toLowerCase())!=null?f:"";if(s!==""){let m=t.get(s),y=m===void 0?t.get(V(s)):void 0,d=m!=null?m:y;if(d!==void 0)return{persona:d,source:"declared",confidence:1};o=s.slice(0,he)}let a=V(e.clusterLabel);return a!==L&&t.has(a)?T({persona:t.get(a),source:"inferred",confidence:n},o!==void 0&&{unrecognizedDeclared:o}):T({persona:L,source:"none",confidence:n},o!==void 0&&{unrecognizedDeclared:o})}function dr(e){var t;if(e==null)return L;let r=e.trim().toLowerCase();return r===""?L:(t=D[r])!=null?t:r}export{ke as CLUSTER_PRIORITY,xe as DEFAULT_PERSONA_VOCABULARY,me as EV_SHRINK_K,I as GLOBAL_FACTOR_LEVEL,ce as GLOBAL_FACTOR_PERSONA,N as LAYOUT_ARCHETYPES,B as LAYOUT_ARCHETYPE_NAMES,X as LAYOUT_FACTOR_BUCKETS,D as LEGACY_PERSONA_MAP,ve as PERSONAS,Ae as PERSONA_DISPLAY,de as PERSONA_KEY_RE,R as POOL_ALL,be as RESERVED_PERSONA_KEYS,Z as SHRINKAGE_M,Xe as SLOT_FACTORS,L as UNKNOWN_PERSONA,ue as WEIGHTS_FALLBACK_PRIOR_PULLS,Ce as applyClusterHeuristic,Ie as broadestValueCell,K as candidateLayouts,ee as canonicalArm,V as canonicalPersona,Ee as chooseLayout,qe as chooseLayoutFactored,Je as chooseSlotArmFactored,ir as confidenceBand,dr as decisionPersona,He as factorCellsForOrder,Qe as factorCellsForTrial,Q as factorLevelsFor,pe as fnv1a,$ as hashLayout,J as layoutBucketOf,tr as marginalArmKey,mr as normalizeDeclaredPersona,z as orderByArchetype,re as parseArm,ar as pickDeterministicArm,Fe as pickFromWeights,Ue as pooledPosterior,_ as posteriorOfCounts,le as previewOrderForPersona,gr as resolvePersona,W as sampleArm,cr as sampleArmEv,M as sampleBeta,ge as shrunkAvgValue,C as shrunkPosterior,fe as slotBaselineArm,or as slotResultFor,nr as validateSlotDecl,er as visitLevel,Te as weightCellsFor};
1
+ import{a as I}from"./chunk-HBG7RQ56.mjs";var R="unknown",ve="Unknown";var te=[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 k(e,r){return e>>>r|e<<32-r}function q(e){return(e>>>0).toString(16).padStart(8,"0")}function ne(e){let r=new TextEncoder().encode(e),t=r.length,n=t*8,o=(t+8>>6)+1<<6,s=new Uint8Array(o);s.set(r),s[t]=128;let a=new DataView(s.buffer);a.setUint32(o-8,Math.floor(n/4294967296),!1),a.setUint32(o-4,n>>>0,!1);let l=1779033703,u=3144134277,f=1013904242,m=2773480762,y=1359893119,d=2600822924,b=528734635,c=1541459225,p=new Uint32Array(64);for(let A=0;A<o;A+=64){for(let g=0;g<16;g++)p[g]=a.getUint32(A+g*4,!1);for(let g=16;g<64;g++){let E=k(p[g-15],7)^k(p[g-15],18)^p[g-15]>>>3,F=k(p[g-2],17)^k(p[g-2],19)^p[g-2]>>>10;p[g]=p[g-16]+E+p[g-7]+F>>>0}let i=l,v=u,x=f,C=m,h=y,_=d,M=b,O=c;for(let g=0;g<64;g++){let E=k(h,6)^k(h,11)^k(h,25),F=h&_^~h&M,H=O+E+F+te[g]+p[g]>>>0,Q=k(i,2)^k(i,13)^k(i,22),ee=i&v^i&x^v&x,re=Q+ee>>>0;O=M,M=_,_=h,h=C+H>>>0,C=x,x=v,v=i,i=H+re>>>0}l=l+i>>>0,u=u+v>>>0,f=f+x>>>0,m=m+C>>>0,y=y+h>>>0,d=d+_>>>0,b=b+M>>>0,c=c+O>>>0}return q(l)+q(u)}function T(e){return ne(e.join("|"))}var oe={conversion_led:["pricing","cta","hero","comparison","social_proof","trust","features","faq","navigation","generic"],evidence_led:["features","comparison","faq","hero","trust","social_proof","pricing","cta","navigation","generic"],price_led:["pricing","comparison","social_proof","trust","cta","hero","features","faq","navigation","generic"],discovery_led:["hero","features","social_proof","pricing","cta","trust","faq","comparison","navigation","generic"]},V=["conversion_led","evidence_led","price_led","discovery_led"];function Y(e,r,t,n){let o=oe[t];if(!o)return e;let s=o.indexOf("generic"),a=f=>{let m=o.indexOf(f);return m===-1?s:m},l=n?e.filter(f=>n.get(f)!=="structural"):[...e];if(l.sort((f,m)=>{var b,c;let y=(b=r.get(f))!=null?b:"generic",d=(c=r.get(m))!=null?c:"generic";return a(y)-a(d)}),!n)return l;let u=0;return e.map(f=>n.get(f)==="structural"?f:l[u++])}function se(e){let r=2166136261;for(let t=0;t<e.length;t++)r^=e.charCodeAt(t),r=Math.imul(r,16777619)>>>0;return r>>>0}function ae(e,r,t,n){if(!t||t==="unknown")return e;let o=V[se(t)%V.length];return Y(e,r,o,n)}var _e=ae;function N(e,r,t){let n=new Map;n.set(T(e),[...e]);for(let o of V){let s=Y(e,r,o,t),a=T(s);n.has(a)||n.set(a,s)}return n}function $(e,r){if(e<1)return $(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 o,s;do{let l=Math.max(1e-15,r()),u=r();o=Math.sqrt(-2*Math.log(l))*Math.cos(2*Math.PI*u),s=1+n*o}while(s<=0);s=s*s*s;let a=r();if(a<1-.0331*o*o*o*o||Math.log(a)<.5*o*o+t*(1-s+Math.log(s)))return t*s}}function w(e,r,t=Math.random){let n=$(e,t),o=$(r,t),s=n+o;return s<=0?e/(e+r):n/s}function j(e,r=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let t=e[0],n=w(t.alpha,t.beta,r);for(let o=1;o<e.length;o++){let s=e[o],a=w(s.alpha,s.beta,r);a>n&&(t=s,n=a)}return t.arm}function Re(e,r,t,n,o=Math.random,s){var m,y;let a=N(e,r,s),l=[];for(let d of a.keys()){let b=n.get(d);l.push({arm:d,alpha:(m=b==null?void 0:b.alpha)!=null?m:1,beta:(y=b==null?void 0:b.beta)!=null?y:1})}let u=j(l,o),f=u?a.get(u):void 0;return f!=null?f:e}var z=20;function L(e,r,t=20){let n=r.alpha+r.beta;if(n<=0||t<=0)return{alpha:e.alpha,beta:e.beta};let o=r.alpha/n,s=t*n/(n+t);return{alpha:e.alpha+s*o,beta:e.beta+s*(1-o)}}var ie=5;function Oe(e,r){var n,o;let t=null;for(let s of e){if(!r.includes(s.variantId))continue;let a=(n=s.pulls)!=null?n:0,l=a>0?a*s.avgReward/(a+ie):0;(!t||l>t.score)&&(t={variantId:s.variantId,score:l})}return(o=t==null?void 0:t.variantId)!=null?o:null}var P="__all__",U={exposures:0,conversions:0};function S(e){return{alpha:e.conversions+1,beta:Math.max(0,e.exposures-e.conversions)+1}}function Ne(e,r,t=20){var d,b,c,p;let n=(d=e.segment)!=null?d:U,o=(b=e.global)!=null?b:U,s=S(o),a=L(S(n),s,t);if(!r)return a;let l=(c=e.persona)!=null?c:U,u=(p=e.child)!=null?p:U,f=L(S(l),s,t),m=(n.exposures+1)/(n.exposures+l.exposures+2),y={alpha:m*a.alpha+(1-m)*f.alpha,beta:m*a.beta+(1-m)*f.beta};return L(S(u),y,t)}function Ue(e){var n,o;let r=null,t=-1;for(let s of e){let a=s.segment===P,l=s.persona===P,u=a&&l?3:a||l?2:1;u>t&&(t=u,r=s)}return{valueSum:(n=r==null?void 0:r.valueSum)!=null?n:0,valueCount:(o=r==null?void 0:r.valueCount)!=null?o:0}}function Ke(e,r){return r==="unknown"||r===P||r===""?[{segment:e,persona:P},{segment:P,persona:P}]:[{segment:e,persona:r},{segment:e,persona:P},{segment:P,persona:r},{segment:P,persona:P}]}var G=4,le="__global__";function W(e,r){return r<=0?0:Math.min(G-1,Math.floor(e*G/r))}function Be(e,r){return e.map((t,n)=>{var o;return{parent:(o=r.get(t))!=null?o:"generic",bucket:W(n,e.length)}})}var D=(e,r)=>`${e}#${r}`;function He(e,r,t,n,o=Math.random,s){var A;let a=N(e,r,s),l=new Map,u=new Map,f=0,m=0;for(let i of n)i.persona===le?(l.set(D(i.parent,i.bucket),i),f+=i.exposures,m+=i.conversions):i.persona===t&&u.set(D(i.parent,i.bucket),i);let y=S({exposures:f,conversions:m}),d=new Map,b=(i,v)=>{var E,F;let x=D(i,v),C=d.get(x);if(C!==void 0)return C;let h=l.get(x),_=L(S({exposures:(E=h==null?void 0:h.exposures)!=null?E:0,conversions:(F=h==null?void 0:h.conversions)!=null?F:0}),y),M=u.get(x),O=M?L(S({exposures:M.exposures,conversions:M.conversions}),_):_,g=w(O.alpha,O.beta,o);return d.set(x,g),g},c=null,p=-1/0;for(let i of a.values()){let v=0;for(let x=0;x<i.length;x++)v+=b((A=r.get(i[x]))!=null?A:"generic",W(x,i.length));v>p&&(p=v,c=i)}return c!=null?c:e}var K="__global__",We=["device","source","persona","visit"];function Z(e){let r=[];return e.device&&r.push({factor:"device",level:e.device}),e.source&&r.push({factor:"source",level:e.source}),e.persona&&e.persona!==R&&r.push({factor:"persona",level:e.persona}),e.visit&&r.push({factor:"visit",level:e.visit}),r}var B=(e,r,t)=>`${e}\0${r}\0${t}`;function Ze(e,r,t,n=Math.random){if(e.length===0)return null;if(e.length===1)return{arm:e[0],factorsUsed:0};let o=new Map,s=0,a=0;for(let c of t)o.set(B(c.arm,c.factor,c.level),c),c.level===K&&(s+=c.exposures,a+=c.conversions);let l=S({exposures:s,conversions:a}),u=Z(r),f=new Map,m=c=>{var A,i;let p=o.get(B(c,"global",K));return L(S({exposures:(A=p==null?void 0:p.exposures)!=null?A:0,conversions:(i=p==null?void 0:p.conversions)!=null?i:0}),l)},y=(c,p,A)=>{let i=B(c,p,A),v=f.get(i);if(v!==void 0)return v;let x=m(c),C=o.get(i),h=C?L(S({exposures:C.exposures,conversions:C.conversions}),x):x,_=w(h.alpha,h.beta,n);return f.set(i,_),_},d=null,b=-1/0;for(let c of e){let p=u.length===0?y(c,"global",K):0;for(let{factor:A,level:i}of u)p+=y(c,A,i);p>b&&(b=p,d=c)}return d===null?null:{arm:d,factorsUsed:u.length}}function Xe(e,r,t){let n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0,o=[{arm:e,factor:"global",level:K,weight:1}];for(let{factor:s,level:a}of Z(r))o.push({arm:e,factor:s,level:a,weight:s==="persona"?n:1});return o}function Je(e){return e==null||!Number.isFinite(e)||e<1?null:e>1?"returning":"new"}function X(e){return Object.keys(e).sort().map(r=>`${r}=${e[r]}`).join("|")}function J(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 o=t.slice(0,n);if(o in r)return null;r[o]=t.slice(n+1)}return r}function er(e,r){return`${e}=${r}`}function ue(e){var t,n,o;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 X(e.baseline);if(typeof e.baseline=="string")return e.baseline;let r={};for(let[s,a]of Object.entries((n=e.dims)!=null?n:{}))r[s]=(o=a[0])!=null?o:"";return X(r)}function rr(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 s=e.arms;if(s.length<2)return{ok:!1,reason:"arms requires at least 2 entries"};if(s.length>12)return{ok:!1,reason:"arms allows at most 12 entries"};if(new Set(s).size!==s.length)return{ok:!1,reason:"arms must be unique"};if(s.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(!s.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 o=1;for(let[s,a]of n){if(a.length<2)return{ok:!1,reason:`dim "${s}" requires at least 2 values`};if(a.length>6)return{ok:!1,reason:`dim "${s}" allows at most 6 values`};if(new Set(a).size!==a.length)return{ok:!1,reason:`dim "${s}" has duplicate values`};o*=a.length}if(o>64)return{ok:!1,reason:`declared space of ${o} 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 s=e.baseline,a=n.map(([u])=>u).sort(),l=Object.keys(s).sort();if(a.join(" ")!==l.join(" "))return{ok:!1,reason:"baseline must set every declared dim exactly once"};for(let[u,f]of n)if(!f.includes(s[u]))return{ok:!1,reason:`baseline value for dim "${u}" is not declared`}}return{ok:!0}}function tr(e,r){var t,n;return e.dims!=null?(n=(t=J(r))!=null?t:J(ue(e)))!=null?n:{}:r}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 or(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 sr(e){return e>=.3?e<.7?"medium":"high":"low"}var fe=20;function pe(e,r,t=fe){let n=e.valueCount>0?e.valueSum/e.valueCount:0;if(r<=0)return n;if(e.valueCount<=0)return r;let o=e.valueCount/(e.valueCount+t);return o*n+(1-o)*r}function lr(e,r,t=Math.random){if(e.length===0)return null;if(e.length===1)return e[0].arm;let n=null,o=-1/0;for(let s of e){let a=w(s.alpha,s.beta,t)*pe(s,r);a>o&&(n=s,o=a)}return n.arm}var me=/^[a-z0-9][a-z0-9_-]{0,31}$/;function ge(e){if(typeof e!="string")return null;let r=e.trim().toLowerCase();return r&&me.test(r)?r:null}var be=["unknown","__all__"];function de(e){var r;return(r=ge(e))!=null?r:R}var xe=[],he=64;function ye(e){var t;let r=new Map;for(let n of e)if(n.status!=="retired"){r.set(n.key,n.key);for(let o of(t=n.aliases)!=null?t:[])be.includes(o)||r.set(o,n.key)}return r}function fr(e,r=xe){var l,u,f;let t=ye(r),n=(l=e.inferredConfidence)!=null?l:0,o,s=(f=(u=e.declared)==null?void 0:u.trim().toLowerCase())!=null?f:"";if(s!==""){let m=t.get(s);if(m!==void 0)return{persona:m,source:"declared",confidence:1};o=s.slice(0,he)}let a=de(e.clusterLabel);return a!==R&&t.has(a)?I({persona:t.get(a),source:"inferred",confidence:n},o!==void 0&&{unrecognizedDeclared:o}):I({persona:R,source:"none",confidence:n},o!==void 0&&{unrecognizedDeclared:o})}function pr(e){if(e==null)return R;let r=e.trim().toLowerCase();return r===""?R:r}export{xe as DEFAULT_PERSONA_VOCABULARY,fe as EV_SHRINK_K,K as GLOBAL_FACTOR_LEVEL,le as GLOBAL_FACTOR_PERSONA,oe as LAYOUT_ARCHETYPES,V as LAYOUT_ARCHETYPE_NAMES,G as LAYOUT_FACTOR_BUCKETS,me as PERSONA_KEY_RE,P as POOL_ALL,be as RESERVED_PERSONA_KEYS,z as SHRINKAGE_M,We as SLOT_FACTORS,R as UNKNOWN_PERSONA,ve as UNKNOWN_PERSONA_DISPLAY,ie as WEIGHTS_FALLBACK_PRIOR_PULLS,_e as applyClusterHeuristic,Ue as broadestValueCell,N as candidateLayouts,X as canonicalArm,de as canonicalPersona,Re as chooseLayout,He as chooseLayoutFactored,Ze as chooseSlotArmFactored,sr as confidenceBand,pr as decisionPersona,Be as factorCellsForOrder,Xe as factorCellsForTrial,Z as factorLevelsFor,ce as fnv1a,T as hashLayout,W as layoutBucketOf,er as marginalArmKey,ge as normalizeDeclaredPersona,Y as orderByArchetype,J as parseArm,or as pickDeterministicArm,Oe as pickFromWeights,Ne as pooledPosterior,S as posteriorOfCounts,ae as previewOrderForPersona,fr as resolvePersona,j as sampleArm,lr as sampleArmEv,w as sampleBeta,pe as shrunkAvgValue,L as shrunkPosterior,ue as slotBaselineArm,tr as slotResultFor,rr as validateSlotDecl,Je as visitLevel,Ke as weightCellsFor};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentientui/policy",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "private": false,
5
5
  "description": "Pure decision-policy functions shared by the SentientUI API and the keyless local engine",
6
6
  "license": "MIT",