@higher.archi/boe 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/promotion/index.d.ts +3 -0
- package/dist/promotion/index.d.ts.map +1 -0
- package/dist/promotion/index.js +9 -0
- package/dist/promotion/index.js.map +1 -0
- package/dist/promotion/promotion.d.ts +68 -0
- package/dist/promotion/promotion.d.ts.map +1 -0
- package/dist/promotion/promotion.js +225 -0
- package/dist/promotion/promotion.js.map +1 -0
- package/dist/promotion/types.d.ts +46 -0
- package/dist/promotion/types.d.ts.map +1 -0
- package/dist/promotion/types.js +9 -0
- package/dist/promotion/types.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +6 -0
- package/src/promotion/index.ts +5 -0
- package/src/promotion/promotion.ts +260 -0
- package/src/promotion/types.ts +47 -0
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -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":"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"}
|
package/dist/index.js
CHANGED
|
@@ -191,4 +191,8 @@ __exportStar(require("./abtesting"), exports);
|
|
|
191
191
|
// Compare - Ruleset Comparison Utility
|
|
192
192
|
// ========================================
|
|
193
193
|
__exportStar(require("./compare"), exports);
|
|
194
|
+
// ========================================
|
|
195
|
+
// Promotion — Counterfactual Scoring Analysis
|
|
196
|
+
// ========================================
|
|
197
|
+
__exportStar(require("./promotion"), exports);
|
|
194
198
|
//# 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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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/promotion/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGvI,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.summarizeCategoryBreakdown = exports.summarizePromotionPath = exports.promotionPath = void 0;
|
|
4
|
+
// Core promotion path
|
|
5
|
+
var promotion_1 = require("./promotion");
|
|
6
|
+
Object.defineProperty(exports, "promotionPath", { enumerable: true, get: function () { return promotion_1.promotionPath; } });
|
|
7
|
+
Object.defineProperty(exports, "summarizePromotionPath", { enumerable: true, get: function () { return promotion_1.summarizePromotionPath; } });
|
|
8
|
+
Object.defineProperty(exports, "summarizeCategoryBreakdown", { enumerable: true, get: function () { return promotion_1.summarizeCategoryBreakdown; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/promotion/index.ts"],"names":[],"mappings":";;;AAGA,sBAAsB;AACtB,yCAAgG;AAAvF,0GAAA,aAAa,OAAA;AAAE,mHAAA,sBAAsB,OAAA;AAAE,uHAAA,0BAA0B,OAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion Path — Counterfactual Scoring Analysis
|
|
3
|
+
*
|
|
4
|
+
* Analyzes unfired rules in a scoring result to generate ranked,
|
|
5
|
+
* actionable improvement roadmaps. Given a ruleset, facts, and a
|
|
6
|
+
* target (tier or score), identifies what scoring opportunities
|
|
7
|
+
* remain and how much each could contribute.
|
|
8
|
+
*/
|
|
9
|
+
import type { CompiledScoringRuleSet, ScoringOptions, TierDefinition } from '../engines/scoring/types';
|
|
10
|
+
import type { FactInput } from '../core';
|
|
11
|
+
import type { PromotionTarget, PromotionResult, PromotionSummaryOptions, CategorySummaryOptions } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Compute a promotion path — the ranked set of unfired rules that could
|
|
14
|
+
* close the gap between a current score and a target score or tier.
|
|
15
|
+
*
|
|
16
|
+
* @param ruleset - Compiled scoring ruleset to analyze
|
|
17
|
+
* @param facts - Facts to score against the ruleset
|
|
18
|
+
* @param target - Target tier or score to reach
|
|
19
|
+
* @param options - Optional scoring options passed to engine execution
|
|
20
|
+
* @returns Promotion result with gap analysis and ranked opportunities
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const path = promotionPath(vendorRuleset, vendorFacts, { tier: 'preferred' });
|
|
25
|
+
*
|
|
26
|
+
* console.log(`Current: ${path.currentScore} (${path.currentTier})`);
|
|
27
|
+
* console.log(`Target: ${path.targetScore} (${path.targetTier})`);
|
|
28
|
+
* console.log(`Gap: ${path.gap} points`);
|
|
29
|
+
*
|
|
30
|
+
* for (const opp of path.opportunities) {
|
|
31
|
+
* const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
32
|
+
* console.log(` ${opp.ruleId}: ${impact} — ${opp.reason ?? 'no reason'}`);
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function promotionPath<T extends TierDefinition = TierDefinition>(ruleset: CompiledScoringRuleSet<T>, facts: FactInput[], target: PromotionTarget, options?: ScoringOptions): PromotionResult<T>;
|
|
37
|
+
/**
|
|
38
|
+
* Generate a human-readable summary string from a PromotionResult.
|
|
39
|
+
*
|
|
40
|
+
* @param path - The promotion result to summarize
|
|
41
|
+
* @param options - Optional display settings
|
|
42
|
+
* @returns Formatted multi-line summary string
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const path = promotionPath(ruleset, facts, { tier: 'preferred' });
|
|
47
|
+
* console.log(summarizePromotionPath(path));
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function summarizePromotionPath(path: PromotionResult, options?: PromotionSummaryOptions): string;
|
|
51
|
+
/**
|
|
52
|
+
* Generate a human-readable category breakdown from a PromotionResult.
|
|
53
|
+
*
|
|
54
|
+
* Groups opportunities by category and shows per-category recoverable
|
|
55
|
+
* points with individual opportunity details.
|
|
56
|
+
*
|
|
57
|
+
* @param path - The promotion result to summarize
|
|
58
|
+
* @param options - Optional display settings
|
|
59
|
+
* @returns Formatted multi-line category breakdown string
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const path = promotionPath(ruleset, facts, { tier: 'elite' });
|
|
64
|
+
* console.log(summarizeCategoryBreakdown(path));
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function summarizeCategoryBreakdown(path: PromotionResult, options?: CategorySummaryOptions): string;
|
|
68
|
+
//# sourceMappingURL=promotion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotion.d.ts","sourceRoot":"","sources":["../../src/promotion/promotion.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,sBAAsB,EACtB,cAAc,EACd,cAAc,EACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAwB,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEvI;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EACrE,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,EAClC,KAAK,EAAE,SAAS,EAAE,EAClB,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,cAAmB,GAC3B,eAAe,CAAC,CAAC,CAAC,CAmGpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,eAAe,EACrB,OAAO,GAAE,uBAA4B,GACpC,MAAM,CAqCR;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,eAAe,EACrB,OAAO,GAAE,sBAA2B,GACnC,MAAM,CAqCR"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Promotion Path — Counterfactual Scoring Analysis
|
|
4
|
+
*
|
|
5
|
+
* Analyzes unfired rules in a scoring result to generate ranked,
|
|
6
|
+
* actionable improvement roadmaps. Given a ruleset, facts, and a
|
|
7
|
+
* target (tier or score), identifies what scoring opportunities
|
|
8
|
+
* remain and how much each could contribute.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.promotionPath = promotionPath;
|
|
12
|
+
exports.summarizePromotionPath = summarizePromotionPath;
|
|
13
|
+
exports.summarizeCategoryBreakdown = summarizeCategoryBreakdown;
|
|
14
|
+
const engine_1 = require("../engines/scoring/engine");
|
|
15
|
+
/**
|
|
16
|
+
* Compute a promotion path — the ranked set of unfired rules that could
|
|
17
|
+
* close the gap between a current score and a target score or tier.
|
|
18
|
+
*
|
|
19
|
+
* @param ruleset - Compiled scoring ruleset to analyze
|
|
20
|
+
* @param facts - Facts to score against the ruleset
|
|
21
|
+
* @param target - Target tier or score to reach
|
|
22
|
+
* @param options - Optional scoring options passed to engine execution
|
|
23
|
+
* @returns Promotion result with gap analysis and ranked opportunities
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const path = promotionPath(vendorRuleset, vendorFacts, { tier: 'preferred' });
|
|
28
|
+
*
|
|
29
|
+
* console.log(`Current: ${path.currentScore} (${path.currentTier})`);
|
|
30
|
+
* console.log(`Target: ${path.targetScore} (${path.targetTier})`);
|
|
31
|
+
* console.log(`Gap: ${path.gap} points`);
|
|
32
|
+
*
|
|
33
|
+
* for (const opp of path.opportunities) {
|
|
34
|
+
* const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
35
|
+
* console.log(` ${opp.ruleId}: ${impact} — ${opp.reason ?? 'no reason'}`);
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
function promotionPath(ruleset, facts, target, options = {}) {
|
|
40
|
+
const start = performance.now();
|
|
41
|
+
// 1. Execute scoring engine
|
|
42
|
+
const engine = new engine_1.ScoringEngine();
|
|
43
|
+
for (const fact of facts) {
|
|
44
|
+
engine.add(fact);
|
|
45
|
+
}
|
|
46
|
+
const result = engine.execute(ruleset, options);
|
|
47
|
+
// 2. Resolve target score
|
|
48
|
+
let targetScore;
|
|
49
|
+
let targetTier;
|
|
50
|
+
if ('tier' in target && target.tier !== undefined) {
|
|
51
|
+
targetTier = target.tier;
|
|
52
|
+
const tiers = ruleset.config.tiers;
|
|
53
|
+
if (!tiers || tiers.length === 0) {
|
|
54
|
+
throw new Error(`Cannot target tier "${target.tier}": no tiers configured in ruleset`);
|
|
55
|
+
}
|
|
56
|
+
const tierDef = tiers.find(t => t.id === target.tier);
|
|
57
|
+
if (!tierDef) {
|
|
58
|
+
const available = tiers.map(t => t.id).join(', ');
|
|
59
|
+
throw new Error(`Tier "${target.tier}" not found. Available: ${available}`);
|
|
60
|
+
}
|
|
61
|
+
const threshold = tierDef.threshold;
|
|
62
|
+
targetScore = threshold === '-Infinity' ? 0 : threshold;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
targetScore = target.score;
|
|
66
|
+
}
|
|
67
|
+
// 3. Compute gap
|
|
68
|
+
const currentScore = result.totalScore;
|
|
69
|
+
const gap = Math.max(0, targetScore - currentScore);
|
|
70
|
+
const alreadyMet = currentScore >= targetScore;
|
|
71
|
+
// 4. Identify unfired rules and extract opportunities
|
|
72
|
+
const firedSet = new Set(result.fired);
|
|
73
|
+
const opportunities = [];
|
|
74
|
+
for (const rule of ruleset.rules) {
|
|
75
|
+
if (firedSet.has(rule.id))
|
|
76
|
+
continue;
|
|
77
|
+
const score = rule.action.score;
|
|
78
|
+
const weight = rule.action.weight ?? 1;
|
|
79
|
+
let potentialScore;
|
|
80
|
+
let dynamic;
|
|
81
|
+
if (typeof score === 'number') {
|
|
82
|
+
potentialScore = score * weight;
|
|
83
|
+
dynamic = false;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// string (function name) or CompiledCondition (expression)
|
|
87
|
+
potentialScore = null;
|
|
88
|
+
dynamic = true;
|
|
89
|
+
}
|
|
90
|
+
opportunities.push({
|
|
91
|
+
ruleId: rule.id,
|
|
92
|
+
ruleName: rule.name,
|
|
93
|
+
category: rule.category,
|
|
94
|
+
potentialScore,
|
|
95
|
+
reason: rule.action.reason,
|
|
96
|
+
dynamic,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// 5. Sort: static scores descending, dynamic (nulls) at end
|
|
100
|
+
opportunities.sort((a, b) => {
|
|
101
|
+
if (a.potentialScore !== null && b.potentialScore !== null) {
|
|
102
|
+
return b.potentialScore - a.potentialScore;
|
|
103
|
+
}
|
|
104
|
+
if (a.potentialScore !== null)
|
|
105
|
+
return -1;
|
|
106
|
+
if (b.potentialScore !== null)
|
|
107
|
+
return 1;
|
|
108
|
+
return 0;
|
|
109
|
+
});
|
|
110
|
+
// 6. Sum static recoverable scores
|
|
111
|
+
let totalRecoverable = 0;
|
|
112
|
+
for (const opp of opportunities) {
|
|
113
|
+
if (opp.potentialScore !== null) {
|
|
114
|
+
totalRecoverable += opp.potentialScore;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const executionTimeMs = performance.now() - start;
|
|
118
|
+
return {
|
|
119
|
+
currentScore,
|
|
120
|
+
currentTier: result.tier?.id,
|
|
121
|
+
targetScore,
|
|
122
|
+
targetTier,
|
|
123
|
+
gap,
|
|
124
|
+
alreadyMet,
|
|
125
|
+
opportunities,
|
|
126
|
+
totalRecoverable,
|
|
127
|
+
result,
|
|
128
|
+
executionTimeMs,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Generate a human-readable summary string from a PromotionResult.
|
|
133
|
+
*
|
|
134
|
+
* @param path - The promotion result to summarize
|
|
135
|
+
* @param options - Optional display settings
|
|
136
|
+
* @returns Formatted multi-line summary string
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* const path = promotionPath(ruleset, facts, { tier: 'preferred' });
|
|
141
|
+
* console.log(summarizePromotionPath(path));
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
function summarizePromotionPath(path, options = {}) {
|
|
145
|
+
const { maxOpportunities } = options;
|
|
146
|
+
const lines = [];
|
|
147
|
+
const currentLabel = path.currentTier ? `${path.currentScore} (${path.currentTier})` : `${path.currentScore}`;
|
|
148
|
+
const targetLabel = path.targetTier ? `${path.targetScore} (${path.targetTier})` : `${path.targetScore}`;
|
|
149
|
+
lines.push(`Current: ${currentLabel}`);
|
|
150
|
+
lines.push(`Target: ${targetLabel}`);
|
|
151
|
+
lines.push(`Gap: ${path.gap} points`);
|
|
152
|
+
lines.push(`Recoverable: ${path.totalRecoverable} points from ${path.opportunities.length} opportunities`);
|
|
153
|
+
if (path.alreadyMet) {
|
|
154
|
+
lines.push('');
|
|
155
|
+
lines.push('Target already met.');
|
|
156
|
+
return lines.join('\n');
|
|
157
|
+
}
|
|
158
|
+
const opps = maxOpportunities != null
|
|
159
|
+
? path.opportunities.slice(0, maxOpportunities)
|
|
160
|
+
: path.opportunities;
|
|
161
|
+
if (opps.length > 0) {
|
|
162
|
+
lines.push('');
|
|
163
|
+
for (const opp of opps) {
|
|
164
|
+
const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
165
|
+
lines.push(` [${impact}] ${opp.ruleName ?? opp.ruleId}`);
|
|
166
|
+
if (opp.reason)
|
|
167
|
+
lines.push(` ${opp.reason}`);
|
|
168
|
+
}
|
|
169
|
+
if (maxOpportunities != null && path.opportunities.length > maxOpportunities) {
|
|
170
|
+
const remaining = path.opportunities.length - maxOpportunities;
|
|
171
|
+
lines.push(` ... and ${remaining} more`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return lines.join('\n');
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Generate a human-readable category breakdown from a PromotionResult.
|
|
178
|
+
*
|
|
179
|
+
* Groups opportunities by category and shows per-category recoverable
|
|
180
|
+
* points with individual opportunity details.
|
|
181
|
+
*
|
|
182
|
+
* @param path - The promotion result to summarize
|
|
183
|
+
* @param options - Optional display settings
|
|
184
|
+
* @returns Formatted multi-line category breakdown string
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* const path = promotionPath(ruleset, facts, { tier: 'elite' });
|
|
189
|
+
* console.log(summarizeCategoryBreakdown(path));
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
function summarizeCategoryBreakdown(path, options = {}) {
|
|
193
|
+
const { maxPerCategory } = options;
|
|
194
|
+
const lines = [];
|
|
195
|
+
// Group by category
|
|
196
|
+
const byCategory = new Map();
|
|
197
|
+
for (const opp of path.opportunities) {
|
|
198
|
+
const cat = opp.category ?? '(uncategorized)';
|
|
199
|
+
if (!byCategory.has(cat))
|
|
200
|
+
byCategory.set(cat, []);
|
|
201
|
+
byCategory.get(cat).push(opp);
|
|
202
|
+
}
|
|
203
|
+
for (const [category, opps] of byCategory) {
|
|
204
|
+
const categoryTotal = opps.reduce((sum, o) => sum + (o.potentialScore ?? 0), 0);
|
|
205
|
+
lines.push(`${category} (${categoryTotal} recoverable points):`);
|
|
206
|
+
const displayed = maxPerCategory != null ? opps.slice(0, maxPerCategory) : opps;
|
|
207
|
+
for (const opp of displayed) {
|
|
208
|
+
const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
209
|
+
lines.push(` [${impact}] ${opp.ruleName ?? opp.ruleId}`);
|
|
210
|
+
if (opp.reason)
|
|
211
|
+
lines.push(` ${opp.reason}`);
|
|
212
|
+
}
|
|
213
|
+
if (maxPerCategory != null && opps.length > maxPerCategory) {
|
|
214
|
+
const remaining = opps.length - maxPerCategory;
|
|
215
|
+
lines.push(` ... and ${remaining} more`);
|
|
216
|
+
}
|
|
217
|
+
lines.push('');
|
|
218
|
+
}
|
|
219
|
+
// Remove trailing blank line
|
|
220
|
+
if (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
221
|
+
lines.pop();
|
|
222
|
+
}
|
|
223
|
+
return lines.join('\n');
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=promotion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promotion.js","sourceRoot":"","sources":["../../src/promotion/promotion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion Path Types
|
|
3
|
+
*
|
|
4
|
+
* Types for counterfactual scoring analysis — identifying unfired rules
|
|
5
|
+
* and ranking them by potential impact to generate promotion roadmaps.
|
|
6
|
+
*/
|
|
7
|
+
import type { ScoringResult, TierDefinition } from '../engines/scoring/types';
|
|
8
|
+
/** A single unfired rule representing a scoring opportunity */
|
|
9
|
+
export type PromotionOpportunity = {
|
|
10
|
+
ruleId: string;
|
|
11
|
+
ruleName?: string;
|
|
12
|
+
category?: string;
|
|
13
|
+
potentialScore: number | null;
|
|
14
|
+
reason?: string;
|
|
15
|
+
dynamic: boolean;
|
|
16
|
+
};
|
|
17
|
+
/** Target specification — reach a tier or a raw score threshold */
|
|
18
|
+
export type PromotionTarget = {
|
|
19
|
+
tier: string;
|
|
20
|
+
score?: never;
|
|
21
|
+
} | {
|
|
22
|
+
score: number;
|
|
23
|
+
tier?: never;
|
|
24
|
+
};
|
|
25
|
+
/** Options for summarizePromotionPath */
|
|
26
|
+
export type PromotionSummaryOptions = {
|
|
27
|
+
maxOpportunities?: number;
|
|
28
|
+
};
|
|
29
|
+
/** Options for summarizeCategoryBreakdown */
|
|
30
|
+
export type CategorySummaryOptions = {
|
|
31
|
+
maxPerCategory?: number;
|
|
32
|
+
};
|
|
33
|
+
/** Promotion path result */
|
|
34
|
+
export type PromotionResult<T extends TierDefinition = TierDefinition> = {
|
|
35
|
+
currentScore: number;
|
|
36
|
+
currentTier?: string;
|
|
37
|
+
targetScore: number;
|
|
38
|
+
targetTier?: string;
|
|
39
|
+
gap: number;
|
|
40
|
+
alreadyMet: boolean;
|
|
41
|
+
opportunities: PromotionOpportunity[];
|
|
42
|
+
totalRecoverable: number;
|
|
43
|
+
result: ScoringResult<T>;
|
|
44
|
+
executionTimeMs: number;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/promotion/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE9E,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,mEAAmE;AACnE,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC/B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAEpC,yCAAyC;AACzC,MAAM,MAAM,uBAAuB,GAAG;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,6CAA6C;AAC7C,MAAM,MAAM,sBAAsB,GAAG;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,4BAA4B;AAC5B,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAAI;IACvE,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,oBAAoB,EAAE,CAAC;IACtC,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Promotion Path Types
|
|
4
|
+
*
|
|
5
|
+
* Types for counterfactual scoring analysis — identifying unfired rules
|
|
6
|
+
* and ranking them by potential impact to generate promotion roadmaps.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/promotion/types.ts"],"names":[],"mappings":";AAAA;;;;;GAKG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@higher.archi/boe",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
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",
|
package/src/index.ts
CHANGED
|
@@ -418,3 +418,9 @@ export * from './abtesting';
|
|
|
418
418
|
// ========================================
|
|
419
419
|
|
|
420
420
|
export * from './compare';
|
|
421
|
+
|
|
422
|
+
// ========================================
|
|
423
|
+
// Promotion — Counterfactual Scoring Analysis
|
|
424
|
+
// ========================================
|
|
425
|
+
|
|
426
|
+
export * from './promotion';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Types
|
|
2
|
+
export type { PromotionOpportunity, PromotionTarget, PromotionResult, PromotionSummaryOptions, CategorySummaryOptions } from './types';
|
|
3
|
+
|
|
4
|
+
// Core promotion path
|
|
5
|
+
export { promotionPath, summarizePromotionPath, summarizeCategoryBreakdown } from './promotion';
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion Path — Counterfactual Scoring Analysis
|
|
3
|
+
*
|
|
4
|
+
* Analyzes unfired rules in a scoring result to generate ranked,
|
|
5
|
+
* actionable improvement roadmaps. Given a ruleset, facts, and a
|
|
6
|
+
* target (tier or score), identifies what scoring opportunities
|
|
7
|
+
* remain and how much each could contribute.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { ScoringEngine } from '../engines/scoring/engine';
|
|
11
|
+
import type {
|
|
12
|
+
CompiledScoringRuleSet,
|
|
13
|
+
ScoringOptions,
|
|
14
|
+
TierDefinition
|
|
15
|
+
} from '../engines/scoring/types';
|
|
16
|
+
import type { FactInput } from '../core';
|
|
17
|
+
import type { PromotionTarget, PromotionResult, PromotionOpportunity, PromotionSummaryOptions, CategorySummaryOptions } from './types';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compute a promotion path — the ranked set of unfired rules that could
|
|
21
|
+
* close the gap between a current score and a target score or tier.
|
|
22
|
+
*
|
|
23
|
+
* @param ruleset - Compiled scoring ruleset to analyze
|
|
24
|
+
* @param facts - Facts to score against the ruleset
|
|
25
|
+
* @param target - Target tier or score to reach
|
|
26
|
+
* @param options - Optional scoring options passed to engine execution
|
|
27
|
+
* @returns Promotion result with gap analysis and ranked opportunities
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const path = promotionPath(vendorRuleset, vendorFacts, { tier: 'preferred' });
|
|
32
|
+
*
|
|
33
|
+
* console.log(`Current: ${path.currentScore} (${path.currentTier})`);
|
|
34
|
+
* console.log(`Target: ${path.targetScore} (${path.targetTier})`);
|
|
35
|
+
* console.log(`Gap: ${path.gap} points`);
|
|
36
|
+
*
|
|
37
|
+
* for (const opp of path.opportunities) {
|
|
38
|
+
* const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
39
|
+
* console.log(` ${opp.ruleId}: ${impact} — ${opp.reason ?? 'no reason'}`);
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function promotionPath<T extends TierDefinition = TierDefinition>(
|
|
44
|
+
ruleset: CompiledScoringRuleSet<T>,
|
|
45
|
+
facts: FactInput[],
|
|
46
|
+
target: PromotionTarget,
|
|
47
|
+
options: ScoringOptions = {}
|
|
48
|
+
): PromotionResult<T> {
|
|
49
|
+
const start = performance.now();
|
|
50
|
+
|
|
51
|
+
// 1. Execute scoring engine
|
|
52
|
+
const engine = new ScoringEngine();
|
|
53
|
+
for (const fact of facts) {
|
|
54
|
+
engine.add(fact);
|
|
55
|
+
}
|
|
56
|
+
const result = engine.execute(ruleset, options);
|
|
57
|
+
|
|
58
|
+
// 2. Resolve target score
|
|
59
|
+
let targetScore: number;
|
|
60
|
+
let targetTier: string | undefined;
|
|
61
|
+
|
|
62
|
+
if ('tier' in target && target.tier !== undefined) {
|
|
63
|
+
targetTier = target.tier;
|
|
64
|
+
const tiers = ruleset.config.tiers;
|
|
65
|
+
if (!tiers || tiers.length === 0) {
|
|
66
|
+
throw new Error(`Cannot target tier "${target.tier}": no tiers configured in ruleset`);
|
|
67
|
+
}
|
|
68
|
+
const tierDef = tiers.find(t => t.id === target.tier);
|
|
69
|
+
if (!tierDef) {
|
|
70
|
+
const available = tiers.map(t => t.id).join(', ');
|
|
71
|
+
throw new Error(`Tier "${target.tier}" not found. Available: ${available}`);
|
|
72
|
+
}
|
|
73
|
+
const threshold = tierDef.threshold;
|
|
74
|
+
targetScore = threshold === '-Infinity' ? 0 : threshold;
|
|
75
|
+
} else {
|
|
76
|
+
targetScore = target.score;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 3. Compute gap
|
|
80
|
+
const currentScore = result.totalScore;
|
|
81
|
+
const gap = Math.max(0, targetScore - currentScore);
|
|
82
|
+
const alreadyMet = currentScore >= targetScore;
|
|
83
|
+
|
|
84
|
+
// 4. Identify unfired rules and extract opportunities
|
|
85
|
+
const firedSet = new Set(result.fired);
|
|
86
|
+
const opportunities: PromotionOpportunity[] = [];
|
|
87
|
+
|
|
88
|
+
for (const rule of ruleset.rules) {
|
|
89
|
+
if (firedSet.has(rule.id)) continue;
|
|
90
|
+
|
|
91
|
+
const score = rule.action.score;
|
|
92
|
+
const weight = rule.action.weight ?? 1;
|
|
93
|
+
let potentialScore: number | null;
|
|
94
|
+
let dynamic: boolean;
|
|
95
|
+
|
|
96
|
+
if (typeof score === 'number') {
|
|
97
|
+
potentialScore = score * weight;
|
|
98
|
+
dynamic = false;
|
|
99
|
+
} else {
|
|
100
|
+
// string (function name) or CompiledCondition (expression)
|
|
101
|
+
potentialScore = null;
|
|
102
|
+
dynamic = true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
opportunities.push({
|
|
106
|
+
ruleId: rule.id,
|
|
107
|
+
ruleName: rule.name,
|
|
108
|
+
category: rule.category,
|
|
109
|
+
potentialScore,
|
|
110
|
+
reason: rule.action.reason,
|
|
111
|
+
dynamic,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 5. Sort: static scores descending, dynamic (nulls) at end
|
|
116
|
+
opportunities.sort((a, b) => {
|
|
117
|
+
if (a.potentialScore !== null && b.potentialScore !== null) {
|
|
118
|
+
return b.potentialScore - a.potentialScore;
|
|
119
|
+
}
|
|
120
|
+
if (a.potentialScore !== null) return -1;
|
|
121
|
+
if (b.potentialScore !== null) return 1;
|
|
122
|
+
return 0;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// 6. Sum static recoverable scores
|
|
126
|
+
let totalRecoverable = 0;
|
|
127
|
+
for (const opp of opportunities) {
|
|
128
|
+
if (opp.potentialScore !== null) {
|
|
129
|
+
totalRecoverable += opp.potentialScore;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const executionTimeMs = performance.now() - start;
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
currentScore,
|
|
137
|
+
currentTier: result.tier?.id,
|
|
138
|
+
targetScore,
|
|
139
|
+
targetTier,
|
|
140
|
+
gap,
|
|
141
|
+
alreadyMet,
|
|
142
|
+
opportunities,
|
|
143
|
+
totalRecoverable,
|
|
144
|
+
result,
|
|
145
|
+
executionTimeMs,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generate a human-readable summary string from a PromotionResult.
|
|
151
|
+
*
|
|
152
|
+
* @param path - The promotion result to summarize
|
|
153
|
+
* @param options - Optional display settings
|
|
154
|
+
* @returns Formatted multi-line summary string
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* const path = promotionPath(ruleset, facts, { tier: 'preferred' });
|
|
159
|
+
* console.log(summarizePromotionPath(path));
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export function summarizePromotionPath(
|
|
163
|
+
path: PromotionResult,
|
|
164
|
+
options: PromotionSummaryOptions = {}
|
|
165
|
+
): string {
|
|
166
|
+
const { maxOpportunities } = options;
|
|
167
|
+
const lines: string[] = [];
|
|
168
|
+
|
|
169
|
+
const currentLabel = path.currentTier ? `${path.currentScore} (${path.currentTier})` : `${path.currentScore}`;
|
|
170
|
+
const targetLabel = path.targetTier ? `${path.targetScore} (${path.targetTier})` : `${path.targetScore}`;
|
|
171
|
+
|
|
172
|
+
lines.push(`Current: ${currentLabel}`);
|
|
173
|
+
lines.push(`Target: ${targetLabel}`);
|
|
174
|
+
lines.push(`Gap: ${path.gap} points`);
|
|
175
|
+
lines.push(`Recoverable: ${path.totalRecoverable} points from ${path.opportunities.length} opportunities`);
|
|
176
|
+
|
|
177
|
+
if (path.alreadyMet) {
|
|
178
|
+
lines.push('');
|
|
179
|
+
lines.push('Target already met.');
|
|
180
|
+
return lines.join('\n');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const opps = maxOpportunities != null
|
|
184
|
+
? path.opportunities.slice(0, maxOpportunities)
|
|
185
|
+
: path.opportunities;
|
|
186
|
+
|
|
187
|
+
if (opps.length > 0) {
|
|
188
|
+
lines.push('');
|
|
189
|
+
for (const opp of opps) {
|
|
190
|
+
const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
191
|
+
lines.push(` [${impact}] ${opp.ruleName ?? opp.ruleId}`);
|
|
192
|
+
if (opp.reason) lines.push(` ${opp.reason}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (maxOpportunities != null && path.opportunities.length > maxOpportunities) {
|
|
196
|
+
const remaining = path.opportunities.length - maxOpportunities;
|
|
197
|
+
lines.push(` ... and ${remaining} more`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return lines.join('\n');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generate a human-readable category breakdown from a PromotionResult.
|
|
206
|
+
*
|
|
207
|
+
* Groups opportunities by category and shows per-category recoverable
|
|
208
|
+
* points with individual opportunity details.
|
|
209
|
+
*
|
|
210
|
+
* @param path - The promotion result to summarize
|
|
211
|
+
* @param options - Optional display settings
|
|
212
|
+
* @returns Formatted multi-line category breakdown string
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* const path = promotionPath(ruleset, facts, { tier: 'elite' });
|
|
217
|
+
* console.log(summarizeCategoryBreakdown(path));
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export function summarizeCategoryBreakdown(
|
|
221
|
+
path: PromotionResult,
|
|
222
|
+
options: CategorySummaryOptions = {}
|
|
223
|
+
): string {
|
|
224
|
+
const { maxPerCategory } = options;
|
|
225
|
+
const lines: string[] = [];
|
|
226
|
+
|
|
227
|
+
// Group by category
|
|
228
|
+
const byCategory = new Map<string, PromotionOpportunity[]>();
|
|
229
|
+
for (const opp of path.opportunities) {
|
|
230
|
+
const cat = opp.category ?? '(uncategorized)';
|
|
231
|
+
if (!byCategory.has(cat)) byCategory.set(cat, []);
|
|
232
|
+
byCategory.get(cat)!.push(opp);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (const [category, opps] of byCategory) {
|
|
236
|
+
const categoryTotal = opps.reduce((sum, o) => sum + (o.potentialScore ?? 0), 0);
|
|
237
|
+
lines.push(`${category} (${categoryTotal} recoverable points):`);
|
|
238
|
+
|
|
239
|
+
const displayed = maxPerCategory != null ? opps.slice(0, maxPerCategory) : opps;
|
|
240
|
+
for (const opp of displayed) {
|
|
241
|
+
const impact = opp.dynamic ? 'variable' : `+${opp.potentialScore}`;
|
|
242
|
+
lines.push(` [${impact}] ${opp.ruleName ?? opp.ruleId}`);
|
|
243
|
+
if (opp.reason) lines.push(` ${opp.reason}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (maxPerCategory != null && opps.length > maxPerCategory) {
|
|
247
|
+
const remaining = opps.length - maxPerCategory;
|
|
248
|
+
lines.push(` ... and ${remaining} more`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
lines.push('');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Remove trailing blank line
|
|
255
|
+
if (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
256
|
+
lines.pop();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return lines.join('\n');
|
|
260
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion Path Types
|
|
3
|
+
*
|
|
4
|
+
* Types for counterfactual scoring analysis — identifying unfired rules
|
|
5
|
+
* and ranking them by potential impact to generate promotion roadmaps.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ScoringResult, TierDefinition } from '../engines/scoring/types';
|
|
9
|
+
|
|
10
|
+
/** A single unfired rule representing a scoring opportunity */
|
|
11
|
+
export type PromotionOpportunity = {
|
|
12
|
+
ruleId: string;
|
|
13
|
+
ruleName?: string;
|
|
14
|
+
category?: string;
|
|
15
|
+
potentialScore: number | null; // null = dynamic (expression/function)
|
|
16
|
+
reason?: string; // from ScoringAction.reason
|
|
17
|
+
dynamic: boolean; // true if score is expression/function
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Target specification — reach a tier or a raw score threshold */
|
|
21
|
+
export type PromotionTarget =
|
|
22
|
+
| { tier: string; score?: never }
|
|
23
|
+
| { score: number; tier?: never };
|
|
24
|
+
|
|
25
|
+
/** Options for summarizePromotionPath */
|
|
26
|
+
export type PromotionSummaryOptions = {
|
|
27
|
+
maxOpportunities?: number; // max opportunities to display (default: all)
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** Options for summarizeCategoryBreakdown */
|
|
31
|
+
export type CategorySummaryOptions = {
|
|
32
|
+
maxPerCategory?: number; // max opportunities per category (default: all)
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** Promotion path result */
|
|
36
|
+
export type PromotionResult<T extends TierDefinition = TierDefinition> = {
|
|
37
|
+
currentScore: number;
|
|
38
|
+
currentTier?: string;
|
|
39
|
+
targetScore: number; // resolved threshold of target tier, or explicit score
|
|
40
|
+
targetTier?: string;
|
|
41
|
+
gap: number; // targetScore - currentScore (0 if already met)
|
|
42
|
+
alreadyMet: boolean; // true if current score/tier already meets target
|
|
43
|
+
opportunities: PromotionOpportunity[]; // ranked by potentialScore desc (nulls last)
|
|
44
|
+
totalRecoverable: number; // sum of all static potentialScores
|
|
45
|
+
result: ScoringResult<T>; // the full scoring result for reference
|
|
46
|
+
executionTimeMs: number;
|
|
47
|
+
};
|