@higher.archi/boe 1.0.14 → 1.0.15

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.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * FNV-1a 32-bit hash. Pure JS, zero dependencies, browser-safe.
3
+ * Returns a float in [0.0, 1.0) for deterministic bucket resolution.
4
+ */
5
+ export declare function fnv1a(input: string): number;
6
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/abtesting/hash.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO3C"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fnv1a = fnv1a;
4
+ /**
5
+ * FNV-1a 32-bit hash. Pure JS, zero dependencies, browser-safe.
6
+ * Returns a float in [0.0, 1.0) for deterministic bucket resolution.
7
+ */
8
+ function fnv1a(input) {
9
+ let hash = 0x811c9dc5; // FNV offset basis
10
+ for (let i = 0; i < input.length; i++) {
11
+ hash ^= input.charCodeAt(i);
12
+ hash = Math.imul(hash, 0x01000193); // FNV prime
13
+ }
14
+ return (hash >>> 0) / 0x100000000;
15
+ }
16
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/abtesting/hash.ts"],"names":[],"mappings":";;AAIA,sBAOC;AAXD;;;GAGG;AACH,SAAgB,KAAK,CAAC,KAAa;IACjC,IAAI,IAAI,GAAG,UAAU,CAAC,CAAC,mBAAmB;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,YAAY;IAClD,CAAC;IACD,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,WAAW,CAAC;AACpC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export type { ABVariant, ABTestConfig, ResolvedVariant } from './types';
2
+ export { resolveVariant } from './resolver';
3
+ export { fnv1a } from './hash';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/abtesting/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGxE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fnv1a = exports.resolveVariant = void 0;
4
+ // Core resolver
5
+ var resolver_1 = require("./resolver");
6
+ Object.defineProperty(exports, "resolveVariant", { enumerable: true, get: function () { return resolver_1.resolveVariant; } });
7
+ // Hash (exported for advanced use / testing)
8
+ var hash_1 = require("./hash");
9
+ Object.defineProperty(exports, "fnv1a", { enumerable: true, get: function () { return hash_1.fnv1a; } });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/abtesting/index.ts"],"names":[],"mappings":";;;AAGA,gBAAgB;AAChB,uCAA4C;AAAnC,0GAAA,cAAc,OAAA;AAEvB,6CAA6C;AAC7C,+BAA+B;AAAtB,6FAAA,KAAK,OAAA"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A/B Test Variant Resolver
3
+ *
4
+ * Deterministic: the same entityId + testId always resolves to the same variant.
5
+ * Engine-agnostic: works with any compiled ruleset type.
6
+ */
7
+ import type { ABTestConfig, ResolvedVariant } from './types';
8
+ /**
9
+ * Resolves an entity to a variant. Deterministic: same entityId + testId
10
+ * always returns the same variant.
11
+ *
12
+ * The hash key includes testId so the same entity can be independently
13
+ * bucketed across concurrent tests.
14
+ *
15
+ * @typeParam T - The compiled ruleset type
16
+ * @param config - The A/B test configuration with variants and weights
17
+ * @param entityId - The entity identifier to bucket (user ID, account ID, etc.)
18
+ * @returns The resolved variant with its compiled ruleset
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const { variantId, ruleset } = resolveVariant(test, applicationId);
23
+ * const engine = new ScoringEngine(ruleset);
24
+ * const result = engine.execute(facts);
25
+ * ```
26
+ */
27
+ export declare function resolveVariant<T>(config: ABTestConfig<T>, entityId: string): ResolvedVariant<T>;
28
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/abtesting/resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA4B7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,QAAQ,EAAE,MAAM,GACf,eAAe,CAAC,CAAC,CAAC,CA4BpB"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * A/B Test Variant Resolver
4
+ *
5
+ * Deterministic: the same entityId + testId always resolves to the same variant.
6
+ * Engine-agnostic: works with any compiled ruleset type.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.resolveVariant = resolveVariant;
10
+ const hash_1 = require("./hash");
11
+ /**
12
+ * Validates that an ABTestConfig is well-formed.
13
+ * @throws if variants are empty, weights don't sum to ~1.0, or IDs are duplicated
14
+ */
15
+ function validateConfig(config) {
16
+ if (!config.variants.length) {
17
+ throw new Error(`ABTest "${config.testId}": must have at least one variant`);
18
+ }
19
+ const total = config.variants.reduce((sum, v) => sum + v.weight, 0);
20
+ if (Math.abs(total - 1.0) > 0.001) {
21
+ throw new Error(`ABTest "${config.testId}": variant weights must sum to 1.0 (got ${total})`);
22
+ }
23
+ const ids = new Set();
24
+ for (const v of config.variants) {
25
+ if (ids.has(v.id)) {
26
+ throw new Error(`ABTest "${config.testId}": duplicate variant id "${v.id}"`);
27
+ }
28
+ ids.add(v.id);
29
+ }
30
+ }
31
+ /**
32
+ * Resolves an entity to a variant. Deterministic: same entityId + testId
33
+ * always returns the same variant.
34
+ *
35
+ * The hash key includes testId so the same entity can be independently
36
+ * bucketed across concurrent tests.
37
+ *
38
+ * @typeParam T - The compiled ruleset type
39
+ * @param config - The A/B test configuration with variants and weights
40
+ * @param entityId - The entity identifier to bucket (user ID, account ID, etc.)
41
+ * @returns The resolved variant with its compiled ruleset
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const { variantId, ruleset } = resolveVariant(test, applicationId);
46
+ * const engine = new ScoringEngine(ruleset);
47
+ * const result = engine.execute(facts);
48
+ * ```
49
+ */
50
+ function resolveVariant(config, entityId) {
51
+ validateConfig(config);
52
+ const hashValue = (0, hash_1.fnv1a)(`${config.testId}:${entityId}`);
53
+ let cumulative = 0;
54
+ for (const variant of config.variants) {
55
+ cumulative += variant.weight;
56
+ if (hashValue < cumulative) {
57
+ return {
58
+ variantId: variant.id,
59
+ ruleset: variant.ruleset,
60
+ entityId,
61
+ testId: config.testId,
62
+ hashValue,
63
+ };
64
+ }
65
+ }
66
+ // Fallback to last variant (floating-point edge case)
67
+ const last = config.variants[config.variants.length - 1];
68
+ return {
69
+ variantId: last.id,
70
+ ruleset: last.ruleset,
71
+ entityId,
72
+ testId: config.testId,
73
+ hashValue,
74
+ };
75
+ }
76
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/abtesting/resolver.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAiDH,wCA+BC;AA7ED,iCAA+B;AAE/B;;;GAGG;AACH,SAAS,cAAc,CAAI,MAAuB;IAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,MAAM,mCAAmC,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpE,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CACb,WAAW,MAAM,CAAC,MAAM,2CAA2C,KAAK,GAAG,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,MAAM,4BAA4B,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC/E,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,cAAc,CAC5B,MAAuB,EACvB,QAAgB;IAEhB,cAAc,CAAC,MAAM,CAAC,CAAC;IAEvB,MAAM,SAAS,GAAG,IAAA,YAAK,EAAC,GAAG,MAAM,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC,CAAC;IAExD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,SAAS,GAAG,UAAU,EAAE,CAAC;YAC3B,OAAO;gBACL,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,QAAQ;gBACR,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS;aACV,CAAC;QACJ,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzD,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,EAAE;QAClB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ;QACR,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * A/B Testing Types
3
+ *
4
+ * Deterministic variant resolution for ruleset A/B testing.
5
+ * Works with any BOE engine type — the generic parameter T
6
+ * carries the compiled ruleset type through resolution.
7
+ */
8
+ /**
9
+ * A single variant in an A/B test configuration.
10
+ * @typeParam T - The compiled ruleset type (e.g., CompiledScoringRuleSet)
11
+ */
12
+ export type ABVariant<T> = {
13
+ /** Unique identifier for this variant (e.g., "control", "challenger-v2") */
14
+ id: string;
15
+ /** Traffic weight as a decimal (0.0 to 1.0). All weights in a test must sum to 1.0. */
16
+ weight: number;
17
+ /** The compiled ruleset to use for entities bucketed into this variant */
18
+ ruleset: T;
19
+ };
20
+ /**
21
+ * Configuration for an A/B test over compiled rulesets.
22
+ * @typeParam T - The compiled ruleset type
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const test: ABTestConfig<CompiledScoringRuleSet> = {
27
+ * testId: 'scoring-v2-rollout',
28
+ * variants: [
29
+ * { id: 'control', weight: 0.8, ruleset: controlRuleset },
30
+ * { id: 'challenger', weight: 0.2, ruleset: challengerRuleset },
31
+ * ],
32
+ * };
33
+ * ```
34
+ */
35
+ export type ABTestConfig<T> = {
36
+ /** Unique test identifier. Used as part of the hash key for isolation between concurrent tests. */
37
+ testId: string;
38
+ /** Ordered list of variants. Weights must sum to 1.0. */
39
+ variants: ABVariant<T>[];
40
+ };
41
+ /**
42
+ * Result of resolving an entity to a variant.
43
+ * @typeParam T - The compiled ruleset type
44
+ */
45
+ export type ResolvedVariant<T> = {
46
+ /** The variant ID the entity was bucketed into */
47
+ variantId: string;
48
+ /** The compiled ruleset for this variant */
49
+ ruleset: T;
50
+ /** The entity ID that was resolved */
51
+ entityId: string;
52
+ /** The test ID this resolution belongs to */
53
+ testId: string;
54
+ /** The raw hash value in [0, 1) — useful for debugging distribution */
55
+ hashValue: number;
56
+ };
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/abtesting/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IAEX,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IAEf,0EAA0E;IAC1E,OAAO,EAAE,CAAC,CAAC;CACZ,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,mGAAmG;IACnG,MAAM,EAAE,MAAM,CAAC;IAEf,yDAAyD;IACzD,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;CAC1B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,4CAA4C;IAC5C,OAAO,EAAE,CAAC,CAAC;IAEX,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IAEjB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IAEf,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * A/B Testing Types
4
+ *
5
+ * Deterministic variant resolution for ruleset A/B testing.
6
+ * Works with any BOE engine type — the generic parameter T
7
+ * carries the compiled ruleset type through resolution.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/abtesting/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
package/dist/index.d.ts CHANGED
@@ -58,4 +58,5 @@ export type { ErrorContext } from './core/errors';
58
58
  export { calculateDecayMultiplier, resolveDecayTimestamp } from './core/evaluation/decay';
59
59
  export type { DecayCurve, DecayTimeUnit, DecayConfig, DecayInfo } from './core/evaluation/decay';
60
60
  export * from './qfacts';
61
+ export * from './abtesting';
61
62
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMlD,cAAc,QAAQ,CAAC;AAOvB,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACb,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,cAAc,EACd,aAAa,EACd,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,cAAc,EACd,SAAS,EACT,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACb,sBAAsB,EACtB,cAAc,EACd,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,SAAS,EACT,oBAAoB,EACpB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,UAAU,EACV,UAAU,EACV,YAAY,EACZ,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,6BAA6B,EAC7B,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,8BAA8B,EAC9B,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,aAAa,EACb,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,SAAS,EACT,WAAW,EACX,oBAAoB,EACrB,MAAM,kBAAkB,CAAC;AAO1B,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,YAAY,EACZ,aAAa,EACb,KAAK,EACL,iBAAiB,EACjB,WAAW,EAEX,UAAU,EACV,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAEV,YAAY,EACZ,YAAY,EAEZ,WAAW,EACX,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,cAAc,EACd,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,KAAK,EACL,iBAAiB,EACjB,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,MAAM,EACN,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,WAAW,EAEX,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EAEd,cAAc,EACd,aAAa,EACb,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG7E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACzE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACtB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,UAAU,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACV,MAAM,yBAAyB,CAAC;AAMjC,cAAc,UAAU,CAAC;AAMzB,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -183,4 +183,8 @@ Object.defineProperty(exports, "resolveDecayTimestamp", { enumerable: true, get:
183
183
  // QFacts - Probabilistic Fact Hydration
184
184
  // ========================================
185
185
  __exportStar(require("./qfacts"), exports);
186
+ // ========================================
187
+ // A/B Testing - Deterministic Variant Resolution
188
+ // ========================================
189
+ __exportStar(require("./abtesting"), exports);
186
190
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@higher.archi/boe",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "description": "A multi-strategy rule engine supporting forward chaining, backward chaining, scoring, sequential, fuzzy logic, and Bayesian inference",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,12 @@
1
+ /**
2
+ * FNV-1a 32-bit hash. Pure JS, zero dependencies, browser-safe.
3
+ * Returns a float in [0.0, 1.0) for deterministic bucket resolution.
4
+ */
5
+ export function fnv1a(input: string): number {
6
+ let hash = 0x811c9dc5; // FNV offset basis
7
+ for (let i = 0; i < input.length; i++) {
8
+ hash ^= input.charCodeAt(i);
9
+ hash = Math.imul(hash, 0x01000193); // FNV prime
10
+ }
11
+ return (hash >>> 0) / 0x100000000;
12
+ }
@@ -0,0 +1,8 @@
1
+ // Types
2
+ export type { ABVariant, ABTestConfig, ResolvedVariant } from './types';
3
+
4
+ // Core resolver
5
+ export { resolveVariant } from './resolver';
6
+
7
+ // Hash (exported for advanced use / testing)
8
+ export { fnv1a } from './hash';
@@ -0,0 +1,86 @@
1
+ /**
2
+ * A/B Test Variant Resolver
3
+ *
4
+ * Deterministic: the same entityId + testId always resolves to the same variant.
5
+ * Engine-agnostic: works with any compiled ruleset type.
6
+ */
7
+
8
+ import type { ABTestConfig, ResolvedVariant } from './types';
9
+ import { fnv1a } from './hash';
10
+
11
+ /**
12
+ * Validates that an ABTestConfig is well-formed.
13
+ * @throws if variants are empty, weights don't sum to ~1.0, or IDs are duplicated
14
+ */
15
+ function validateConfig<T>(config: ABTestConfig<T>): void {
16
+ if (!config.variants.length) {
17
+ throw new Error(`ABTest "${config.testId}": must have at least one variant`);
18
+ }
19
+
20
+ const total = config.variants.reduce((sum, v) => sum + v.weight, 0);
21
+ if (Math.abs(total - 1.0) > 0.001) {
22
+ throw new Error(
23
+ `ABTest "${config.testId}": variant weights must sum to 1.0 (got ${total})`
24
+ );
25
+ }
26
+
27
+ const ids = new Set<string>();
28
+ for (const v of config.variants) {
29
+ if (ids.has(v.id)) {
30
+ throw new Error(`ABTest "${config.testId}": duplicate variant id "${v.id}"`);
31
+ }
32
+ ids.add(v.id);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Resolves an entity to a variant. Deterministic: same entityId + testId
38
+ * always returns the same variant.
39
+ *
40
+ * The hash key includes testId so the same entity can be independently
41
+ * bucketed across concurrent tests.
42
+ *
43
+ * @typeParam T - The compiled ruleset type
44
+ * @param config - The A/B test configuration with variants and weights
45
+ * @param entityId - The entity identifier to bucket (user ID, account ID, etc.)
46
+ * @returns The resolved variant with its compiled ruleset
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const { variantId, ruleset } = resolveVariant(test, applicationId);
51
+ * const engine = new ScoringEngine(ruleset);
52
+ * const result = engine.execute(facts);
53
+ * ```
54
+ */
55
+ export function resolveVariant<T>(
56
+ config: ABTestConfig<T>,
57
+ entityId: string
58
+ ): ResolvedVariant<T> {
59
+ validateConfig(config);
60
+
61
+ const hashValue = fnv1a(`${config.testId}:${entityId}`);
62
+
63
+ let cumulative = 0;
64
+ for (const variant of config.variants) {
65
+ cumulative += variant.weight;
66
+ if (hashValue < cumulative) {
67
+ return {
68
+ variantId: variant.id,
69
+ ruleset: variant.ruleset,
70
+ entityId,
71
+ testId: config.testId,
72
+ hashValue,
73
+ };
74
+ }
75
+ }
76
+
77
+ // Fallback to last variant (floating-point edge case)
78
+ const last = config.variants[config.variants.length - 1];
79
+ return {
80
+ variantId: last.id,
81
+ ruleset: last.ruleset,
82
+ entityId,
83
+ testId: config.testId,
84
+ hashValue,
85
+ };
86
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A/B Testing Types
3
+ *
4
+ * Deterministic variant resolution for ruleset A/B testing.
5
+ * Works with any BOE engine type — the generic parameter T
6
+ * carries the compiled ruleset type through resolution.
7
+ */
8
+
9
+ /**
10
+ * A single variant in an A/B test configuration.
11
+ * @typeParam T - The compiled ruleset type (e.g., CompiledScoringRuleSet)
12
+ */
13
+ export type ABVariant<T> = {
14
+ /** Unique identifier for this variant (e.g., "control", "challenger-v2") */
15
+ id: string;
16
+
17
+ /** Traffic weight as a decimal (0.0 to 1.0). All weights in a test must sum to 1.0. */
18
+ weight: number;
19
+
20
+ /** The compiled ruleset to use for entities bucketed into this variant */
21
+ ruleset: T;
22
+ };
23
+
24
+ /**
25
+ * Configuration for an A/B test over compiled rulesets.
26
+ * @typeParam T - The compiled ruleset type
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const test: ABTestConfig<CompiledScoringRuleSet> = {
31
+ * testId: 'scoring-v2-rollout',
32
+ * variants: [
33
+ * { id: 'control', weight: 0.8, ruleset: controlRuleset },
34
+ * { id: 'challenger', weight: 0.2, ruleset: challengerRuleset },
35
+ * ],
36
+ * };
37
+ * ```
38
+ */
39
+ export type ABTestConfig<T> = {
40
+ /** Unique test identifier. Used as part of the hash key for isolation between concurrent tests. */
41
+ testId: string;
42
+
43
+ /** Ordered list of variants. Weights must sum to 1.0. */
44
+ variants: ABVariant<T>[];
45
+ };
46
+
47
+ /**
48
+ * Result of resolving an entity to a variant.
49
+ * @typeParam T - The compiled ruleset type
50
+ */
51
+ export type ResolvedVariant<T> = {
52
+ /** The variant ID the entity was bucketed into */
53
+ variantId: string;
54
+
55
+ /** The compiled ruleset for this variant */
56
+ ruleset: T;
57
+
58
+ /** The entity ID that was resolved */
59
+ entityId: string;
60
+
61
+ /** The test ID this resolution belongs to */
62
+ testId: string;
63
+
64
+ /** The raw hash value in [0, 1) — useful for debugging distribution */
65
+ hashValue: number;
66
+ };
package/src/index.ts CHANGED
@@ -406,3 +406,9 @@ export type {
406
406
  // ========================================
407
407
 
408
408
  export * from './qfacts';
409
+
410
+ // ========================================
411
+ // A/B Testing - Deterministic Variant Resolution
412
+ // ========================================
413
+
414
+ export * from './abtesting';