@higher.archi/boe 1.0.30 → 1.0.31

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.
Files changed (226) hide show
  1. package/dist/core/evaluation/decay.d.ts +13 -2
  2. package/dist/core/evaluation/decay.d.ts.map +1 -1
  3. package/dist/core/evaluation/decay.js +24 -0
  4. package/dist/core/evaluation/decay.js.map +1 -1
  5. package/dist/core/types/rule.d.ts +25 -1
  6. package/dist/core/types/rule.d.ts.map +1 -1
  7. package/dist/core/types/rule.js +28 -0
  8. package/dist/core/types/rule.js.map +1 -1
  9. package/dist/engines/bayesian/index.d.ts +1 -1
  10. package/dist/engines/bayesian/index.d.ts.map +1 -1
  11. package/dist/engines/bayesian/index.js +2 -1
  12. package/dist/engines/bayesian/index.js.map +1 -1
  13. package/dist/engines/bayesian/types.d.ts +10 -1
  14. package/dist/engines/bayesian/types.d.ts.map +1 -1
  15. package/dist/engines/bayesian/types.js +16 -1
  16. package/dist/engines/bayesian/types.js.map +1 -1
  17. package/dist/engines/constraint/types.d.ts +36 -5
  18. package/dist/engines/constraint/types.d.ts.map +1 -1
  19. package/dist/engines/constraint/types.js +44 -1
  20. package/dist/engines/constraint/types.js.map +1 -1
  21. package/dist/engines/decay/index.d.ts +1 -1
  22. package/dist/engines/decay/index.d.ts.map +1 -1
  23. package/dist/engines/decay/index.js +5 -1
  24. package/dist/engines/decay/index.js.map +1 -1
  25. package/dist/engines/decay/types.d.ts +26 -4
  26. package/dist/engines/decay/types.d.ts.map +1 -1
  27. package/dist/engines/decay/types.js +30 -1
  28. package/dist/engines/decay/types.js.map +1 -1
  29. package/dist/engines/defeasible/index.d.ts +1 -1
  30. package/dist/engines/defeasible/index.d.ts.map +1 -1
  31. package/dist/engines/defeasible/index.js +8 -1
  32. package/dist/engines/defeasible/index.js.map +1 -1
  33. package/dist/engines/defeasible/types.d.ts +40 -5
  34. package/dist/engines/defeasible/types.d.ts.map +1 -1
  35. package/dist/engines/defeasible/types.js +56 -1
  36. package/dist/engines/defeasible/types.js.map +1 -1
  37. package/dist/engines/ensemble/index.d.ts +1 -0
  38. package/dist/engines/ensemble/index.d.ts.map +1 -1
  39. package/dist/engines/ensemble/index.js +5 -1
  40. package/dist/engines/ensemble/index.js.map +1 -1
  41. package/dist/engines/ensemble/types.d.ts +17 -2
  42. package/dist/engines/ensemble/types.d.ts.map +1 -1
  43. package/dist/engines/ensemble/types.js +23 -0
  44. package/dist/engines/ensemble/types.js.map +1 -1
  45. package/dist/engines/expert/index.d.ts +1 -1
  46. package/dist/engines/expert/index.d.ts.map +1 -1
  47. package/dist/engines/expert/index.js +3 -1
  48. package/dist/engines/expert/index.js.map +1 -1
  49. package/dist/engines/expert/types.d.ts +11 -1
  50. package/dist/engines/expert/types.d.ts.map +1 -1
  51. package/dist/engines/expert/types.js +18 -1
  52. package/dist/engines/expert/types.js.map +1 -1
  53. package/dist/engines/fuzzy/fuzzy.types.d.ts +65 -8
  54. package/dist/engines/fuzzy/fuzzy.types.d.ts.map +1 -1
  55. package/dist/engines/fuzzy/fuzzy.types.js +89 -1
  56. package/dist/engines/fuzzy/fuzzy.types.js.map +1 -1
  57. package/dist/engines/loyalty/index.d.ts +1 -0
  58. package/dist/engines/loyalty/index.d.ts.map +1 -1
  59. package/dist/engines/loyalty/index.js +8 -1
  60. package/dist/engines/loyalty/index.js.map +1 -1
  61. package/dist/engines/loyalty/types.d.ts +36 -5
  62. package/dist/engines/loyalty/types.d.ts.map +1 -1
  63. package/dist/engines/loyalty/types.js +40 -0
  64. package/dist/engines/loyalty/types.js.map +1 -1
  65. package/dist/engines/menu-engineering/compiler.d.ts +11 -0
  66. package/dist/engines/menu-engineering/compiler.d.ts.map +1 -0
  67. package/dist/engines/menu-engineering/compiler.js +119 -0
  68. package/dist/engines/menu-engineering/compiler.js.map +1 -0
  69. package/dist/engines/menu-engineering/engine.d.ts +32 -0
  70. package/dist/engines/menu-engineering/engine.d.ts.map +1 -0
  71. package/dist/engines/menu-engineering/engine.js +40 -0
  72. package/dist/engines/menu-engineering/engine.js.map +1 -0
  73. package/dist/engines/menu-engineering/index.d.ts +9 -0
  74. package/dist/engines/menu-engineering/index.d.ts.map +1 -0
  75. package/dist/engines/menu-engineering/index.js +21 -0
  76. package/dist/engines/menu-engineering/index.js.map +1 -0
  77. package/dist/engines/menu-engineering/strategy.d.ts +18 -0
  78. package/dist/engines/menu-engineering/strategy.d.ts.map +1 -0
  79. package/dist/engines/menu-engineering/strategy.js +318 -0
  80. package/dist/engines/menu-engineering/strategy.js.map +1 -0
  81. package/dist/engines/menu-engineering/types.d.ts +187 -0
  82. package/dist/engines/menu-engineering/types.d.ts.map +1 -0
  83. package/dist/engines/menu-engineering/types.js +27 -0
  84. package/dist/engines/menu-engineering/types.js.map +1 -0
  85. package/dist/engines/monte-carlo/index.d.ts +1 -1
  86. package/dist/engines/monte-carlo/index.d.ts.map +1 -1
  87. package/dist/engines/monte-carlo/index.js +5 -1
  88. package/dist/engines/monte-carlo/index.js.map +1 -1
  89. package/dist/engines/monte-carlo/types.d.ts +16 -1
  90. package/dist/engines/monte-carlo/types.d.ts.map +1 -1
  91. package/dist/engines/monte-carlo/types.js +23 -1
  92. package/dist/engines/monte-carlo/types.js.map +1 -1
  93. package/dist/engines/negotiation/index.d.ts +1 -0
  94. package/dist/engines/negotiation/index.d.ts.map +1 -1
  95. package/dist/engines/negotiation/index.js +7 -1
  96. package/dist/engines/negotiation/index.js.map +1 -1
  97. package/dist/engines/negotiation/types.d.ts +23 -4
  98. package/dist/engines/negotiation/types.d.ts.map +1 -1
  99. package/dist/engines/negotiation/types.js +27 -0
  100. package/dist/engines/negotiation/types.js.map +1 -1
  101. package/dist/engines/prediction/index.d.ts +1 -1
  102. package/dist/engines/prediction/index.d.ts.map +1 -1
  103. package/dist/engines/prediction/index.js +6 -1
  104. package/dist/engines/prediction/index.js.map +1 -1
  105. package/dist/engines/prediction/types.d.ts +35 -5
  106. package/dist/engines/prediction/types.d.ts.map +1 -1
  107. package/dist/engines/prediction/types.js +39 -1
  108. package/dist/engines/prediction/types.js.map +1 -1
  109. package/dist/engines/pricing/index.d.ts +2 -2
  110. package/dist/engines/pricing/index.d.ts.map +1 -1
  111. package/dist/engines/pricing/index.js +3 -1
  112. package/dist/engines/pricing/index.js.map +1 -1
  113. package/dist/engines/pricing/types.d.ts +15 -1
  114. package/dist/engines/pricing/types.d.ts.map +1 -1
  115. package/dist/engines/pricing/types.js +16 -1
  116. package/dist/engines/pricing/types.js.map +1 -1
  117. package/dist/engines/ranking/index.d.ts +1 -1
  118. package/dist/engines/ranking/index.d.ts.map +1 -1
  119. package/dist/engines/ranking/index.js +6 -1
  120. package/dist/engines/ranking/index.js.map +1 -1
  121. package/dist/engines/ranking/types.d.ts +32 -5
  122. package/dist/engines/ranking/types.d.ts.map +1 -1
  123. package/dist/engines/ranking/types.js +36 -1
  124. package/dist/engines/ranking/types.js.map +1 -1
  125. package/dist/engines/recipe-costing/compiler.d.ts +11 -0
  126. package/dist/engines/recipe-costing/compiler.d.ts.map +1 -0
  127. package/dist/engines/recipe-costing/compiler.js +177 -0
  128. package/dist/engines/recipe-costing/compiler.js.map +1 -0
  129. package/dist/engines/recipe-costing/engine.d.ts +32 -0
  130. package/dist/engines/recipe-costing/engine.d.ts.map +1 -0
  131. package/dist/engines/recipe-costing/engine.js +40 -0
  132. package/dist/engines/recipe-costing/engine.js.map +1 -0
  133. package/dist/engines/recipe-costing/index.d.ts +9 -0
  134. package/dist/engines/recipe-costing/index.d.ts.map +1 -0
  135. package/dist/engines/recipe-costing/index.js +21 -0
  136. package/dist/engines/recipe-costing/index.js.map +1 -0
  137. package/dist/engines/recipe-costing/strategy.d.ts +20 -0
  138. package/dist/engines/recipe-costing/strategy.d.ts.map +1 -0
  139. package/dist/engines/recipe-costing/strategy.js +265 -0
  140. package/dist/engines/recipe-costing/strategy.js.map +1 -0
  141. package/dist/engines/recipe-costing/types.d.ts +213 -0
  142. package/dist/engines/recipe-costing/types.d.ts.map +1 -0
  143. package/dist/engines/recipe-costing/types.js +36 -0
  144. package/dist/engines/recipe-costing/types.js.map +1 -0
  145. package/dist/engines/scoring/index.d.ts +1 -1
  146. package/dist/engines/scoring/index.d.ts.map +1 -1
  147. package/dist/engines/scoring/index.js +3 -1
  148. package/dist/engines/scoring/index.js.map +1 -1
  149. package/dist/engines/scoring/types.d.ts +8 -1
  150. package/dist/engines/scoring/types.d.ts.map +1 -1
  151. package/dist/engines/scoring/types.js +18 -1
  152. package/dist/engines/scoring/types.js.map +1 -1
  153. package/dist/engines/sentiment/index.d.ts +1 -1
  154. package/dist/engines/sentiment/index.d.ts.map +1 -1
  155. package/dist/engines/sentiment/index.js +3 -1
  156. package/dist/engines/sentiment/index.js.map +1 -1
  157. package/dist/engines/sentiment/types.d.ts +13 -2
  158. package/dist/engines/sentiment/types.d.ts.map +1 -1
  159. package/dist/engines/sentiment/types.js +17 -1
  160. package/dist/engines/sentiment/types.js.map +1 -1
  161. package/dist/engines/state-machine/index.d.ts +1 -1
  162. package/dist/engines/state-machine/index.d.ts.map +1 -1
  163. package/dist/engines/state-machine/index.js +5 -1
  164. package/dist/engines/state-machine/index.js.map +1 -1
  165. package/dist/engines/state-machine/types.d.ts +7 -0
  166. package/dist/engines/state-machine/types.d.ts.map +1 -1
  167. package/dist/engines/state-machine/types.js +14 -0
  168. package/dist/engines/state-machine/types.js.map +1 -1
  169. package/dist/engines/utility/index.d.ts +2 -2
  170. package/dist/engines/utility/index.d.ts.map +1 -1
  171. package/dist/engines/utility/index.js +4 -1
  172. package/dist/engines/utility/index.js.map +1 -1
  173. package/dist/engines/utility/types.d.ts +21 -3
  174. package/dist/engines/utility/types.d.ts.map +1 -1
  175. package/dist/engines/utility/types.js +37 -1
  176. package/dist/engines/utility/types.js.map +1 -1
  177. package/dist/index.d.ts +28 -22
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +73 -3
  180. package/dist/index.js.map +1 -1
  181. package/package.json +1 -1
  182. package/src/core/evaluation/decay.ts +13 -2
  183. package/src/core/types/rule.ts +25 -1
  184. package/src/engines/bayesian/index.ts +1 -0
  185. package/src/engines/bayesian/types.ts +10 -8
  186. package/src/engines/constraint/types.ts +40 -11
  187. package/src/engines/decay/index.ts +4 -0
  188. package/src/engines/decay/types.ts +26 -4
  189. package/src/engines/defeasible/index.ts +7 -0
  190. package/src/engines/defeasible/types.ts +42 -18
  191. package/src/engines/ensemble/index.ts +6 -0
  192. package/src/engines/ensemble/types.ts +17 -13
  193. package/src/engines/expert/index.ts +1 -0
  194. package/src/engines/expert/types.ts +11 -9
  195. package/src/engines/fuzzy/fuzzy.types.ts +65 -31
  196. package/src/engines/loyalty/index.ts +9 -0
  197. package/src/engines/loyalty/types.ts +36 -5
  198. package/src/engines/menu-engineering/compiler.ts +145 -0
  199. package/src/engines/menu-engineering/engine.ts +48 -0
  200. package/src/engines/menu-engineering/index.ts +47 -0
  201. package/src/engines/menu-engineering/strategy.ts +414 -0
  202. package/src/engines/menu-engineering/types.ts +242 -0
  203. package/src/engines/monte-carlo/index.ts +1 -0
  204. package/src/engines/monte-carlo/types.ts +16 -21
  205. package/src/engines/negotiation/index.ts +8 -0
  206. package/src/engines/negotiation/types.ts +23 -4
  207. package/src/engines/prediction/index.ts +5 -0
  208. package/src/engines/prediction/types.ts +35 -5
  209. package/src/engines/pricing/index.ts +3 -1
  210. package/src/engines/pricing/types.ts +17 -1
  211. package/src/engines/ranking/index.ts +5 -0
  212. package/src/engines/ranking/types.ts +32 -11
  213. package/src/engines/recipe-costing/compiler.ts +219 -0
  214. package/src/engines/recipe-costing/engine.ts +48 -0
  215. package/src/engines/recipe-costing/index.ts +48 -0
  216. package/src/engines/recipe-costing/strategy.ts +357 -0
  217. package/src/engines/recipe-costing/types.ts +269 -0
  218. package/src/engines/scoring/index.ts +2 -0
  219. package/src/engines/scoring/types.ts +8 -6
  220. package/src/engines/sentiment/index.ts +2 -0
  221. package/src/engines/sentiment/types.ts +13 -2
  222. package/src/engines/state-machine/index.ts +3 -0
  223. package/src/engines/state-machine/types.ts +8 -0
  224. package/src/engines/utility/index.ts +5 -0
  225. package/src/engines/utility/types.ts +23 -3
  226. package/src/index.ts +146 -8
@@ -36,17 +36,24 @@ import { DecayConfig, DecayInfo } from '../../core/evaluation/decay';
36
36
  * - defeasible: Can be defeated by other rules
37
37
  * - defeater: Only blocks conclusions, doesn't assert anything
38
38
  */
39
- export type RuleStrength = 'strict' | 'defeasible' | 'defeater';
39
+ export const RuleStrengths = {
40
+ strict: 'strict',
41
+ defeasible: 'defeasible',
42
+ defeater: 'defeater',
43
+ } as const;
44
+ export type RuleStrength = typeof RuleStrengths[keyof typeof RuleStrengths];
40
45
 
41
46
  /**
42
47
  * Conclusion status after evaluation
43
48
  */
44
- export type ConclusionStatus =
45
- | 'definitely' // Proven by strict rule (cannot be defeated)
46
- | 'defeasibly' // Proven by defeasible rule (not currently defeated)
47
- | 'defeated' // Was concluded but defeated by another rule
48
- | 'blocked' // Blocked by a defeater
49
- | 'undecided'; // No applicable rules
49
+ export const ConclusionStatuses = {
50
+ definitely: 'definitely',
51
+ defeasibly: 'defeasibly',
52
+ defeated: 'defeated',
53
+ blocked: 'blocked',
54
+ undecided: 'undecided',
55
+ } as const;
56
+ export type ConclusionStatus = typeof ConclusionStatuses[keyof typeof ConclusionStatuses];
50
57
 
51
58
  // ========================================
52
59
  // Defeat Strength Types
@@ -55,11 +62,13 @@ export type ConclusionStatus =
55
62
  /**
56
63
  * Semantic defeat strength labels - human-readable
57
64
  */
58
- export type SemanticDefeatStrength =
59
- | 'completely' // 1.0 - fully defeats
60
- | 'strongly' // 0.85
61
- | 'moderately' // 0.6
62
- | 'weakly'; // 0.3
65
+ export const SemanticDefeatStrengths = {
66
+ completely: 'completely',
67
+ strongly: 'strongly',
68
+ moderately: 'moderately',
69
+ weakly: 'weakly',
70
+ } as const;
71
+ export type SemanticDefeatStrength = typeof SemanticDefeatStrengths[keyof typeof SemanticDefeatStrengths];
63
72
 
64
73
  /**
65
74
  * Semantic strength to numeric mapping
@@ -91,6 +100,12 @@ export type Credibility =
91
100
  | 'medium' // 0.7
92
101
  | 'low'; // 0.4
93
102
 
103
+ export const SemanticCredibilityLevels = {
104
+ high: 'high',
105
+ medium: 'medium',
106
+ low: 'low',
107
+ } as const;
108
+
94
109
  /**
95
110
  * Credibility to numeric mapping
96
111
  */
@@ -192,11 +207,20 @@ export type SuperiorityRelation = {
192
207
  /**
193
208
  * Aggregation strategy for confidence calculation
194
209
  */
195
- export type AggregationStrategy =
196
- | 'average' // Mean of supporters vs mean of attackers
197
- | 'max-min' // Strongest support vs strongest attack
198
- | 'weighted-sum' // Sum with normalization to 0-1
199
- | 'probabilistic'; // Independent probability combination
210
+ export const DefeasibleAggregations = {
211
+ average: 'average',
212
+ maxMin: 'max-min',
213
+ weightedSum: 'weighted-sum',
214
+ probabilistic: 'probabilistic',
215
+ } as const;
216
+ export type AggregationStrategy = typeof DefeasibleAggregations[keyof typeof DefeasibleAggregations];
217
+
218
+ export const ConflictResolutions = {
219
+ specificity: 'specificity',
220
+ priority: 'priority',
221
+ explicit: 'explicit',
222
+ } as const;
223
+ export type ConflictResolution = typeof ConflictResolutions[keyof typeof ConflictResolutions];
200
224
 
201
225
  /**
202
226
  * Defeasible engine configuration
@@ -222,7 +246,7 @@ export type DefeasibleConfig = {
222
246
  * - 'explicit': Only explicit defeats/superiority apply
223
247
  * Default: 'specificity'
224
248
  */
225
- conflictResolution?: 'specificity' | 'priority' | 'explicit';
249
+ conflictResolution?: ConflictResolution;
226
250
 
227
251
  /**
228
252
  * Maximum iterations for computing defeat cycles (default: 100)
@@ -22,6 +22,12 @@ export type {
22
22
  EnsembleSummaryOptions
23
23
  } from './types';
24
24
 
25
+ // Constants
26
+ export {
27
+ FusionStrategies,
28
+ AgreementLevels
29
+ } from './types';
30
+
25
31
  // Compiler
26
32
  export { compileEnsembleRuleSet } from './compiler';
27
33
 
@@ -18,13 +18,15 @@ import type { FactInput } from '../../core';
18
18
  // Fusion Strategy
19
19
  // ========================================
20
20
 
21
- export type FusionStrategy =
22
- | 'weighted-average' // weighted mean of member scores
23
- | 'median' // middle value, robust to outliers
24
- | 'min' // most conservative member score
25
- | 'max' // most optimistic member score
26
- | 'voting' // highest confidence*weight member wins
27
- | 'stacking'; // second-layer scoring ruleset over member scores
21
+ export const FusionStrategies = {
22
+ weightedAverage: 'weighted-average',
23
+ median: 'median',
24
+ min: 'min',
25
+ max: 'max',
26
+ voting: 'voting',
27
+ stacking: 'stacking',
28
+ } as const;
29
+ export type FusionStrategy = typeof FusionStrategies[keyof typeof FusionStrategies];
28
30
 
29
31
  // ========================================
30
32
  // Member Definitions (Source)
@@ -123,12 +125,14 @@ export type MemberResult = {
123
125
  // ========================================
124
126
 
125
127
  /** Semantic agreement levels based on coefficient of variation */
126
- export type AgreementLevel =
127
- | 'unanimous' // agreement = 1.0 (all identical)
128
- | 'strong' // agreement >= 0.90
129
- | 'moderate' // agreement >= 0.70
130
- | 'weak' // agreement >= 0.50
131
- | 'divided'; // agreement < 0.50
128
+ export const AgreementLevels = {
129
+ unanimous: 'unanimous',
130
+ strong: 'strong',
131
+ moderate: 'moderate',
132
+ weak: 'weak',
133
+ divided: 'divided',
134
+ } as const;
135
+ export type AgreementLevel = typeof AgreementLevels[keyof typeof AgreementLevels];
132
136
 
133
137
  /** Ensemble result — mirrors ScoringResult shape for downstream compatibility */
134
138
  export type EnsembleResult<T extends TierDefinition = TierDefinition> = {
@@ -32,6 +32,7 @@
32
32
  // Types
33
33
  export {
34
34
  // Semantic confidence
35
+ SemanticConfidences,
35
36
  SemanticConfidence,
36
37
  SEMANTIC_CONFIDENCES,
37
38
  Confidence,
@@ -32,15 +32,17 @@ import {
32
32
  * Semantic confidence labels for human-readable rule authoring.
33
33
  * Maps to numeric values between 0.0 and 1.0.
34
34
  */
35
- export type SemanticConfidence =
36
- | 'certain' // 1.0 - Absolute certainty (e.g., mathematical facts)
37
- | 'very-high' // 0.95 - Near certain (e.g., well-established patterns)
38
- | 'high' // 0.85 - Strong confidence (e.g., clear evidence)
39
- | 'likely' // 0.75 - Probable (e.g., good indicators)
40
- | 'moderate' // 0.65 - Moderate confidence (e.g., partial evidence)
41
- | 'possible' // 0.50 - Even odds (e.g., uncertain)
42
- | 'unlikely' // 0.35 - Improbable (e.g., weak evidence)
43
- | 'low'; // 0.20 - Low confidence (e.g., minimal support)
35
+ export const SemanticConfidences = {
36
+ certain: 'certain',
37
+ veryHigh: 'very-high',
38
+ high: 'high',
39
+ likely: 'likely',
40
+ moderate: 'moderate',
41
+ possible: 'possible',
42
+ unlikely: 'unlikely',
43
+ low: 'low',
44
+ } as const;
45
+ export type SemanticConfidence = typeof SemanticConfidences[keyof typeof SemanticConfidences];
44
46
 
45
47
  /**
46
48
  * Mapping from semantic labels to numeric confidence values.
@@ -15,22 +15,48 @@ import { BindingContext } from '../../core';
15
15
  * Membership function shapes
16
16
  * These define how membership degree (0-1) is calculated from a crisp value
17
17
  */
18
- export type MembershipShape = 'triangle' | 'trapezoid' | 'gaussian' | 'shoulder' | 'block';
18
+ export const MembershipShapes = {
19
+ triangle: 'triangle',
20
+ trapezoid: 'trapezoid',
21
+ gaussian: 'gaussian',
22
+ shoulder: 'shoulder',
23
+ block: 'block',
24
+ } as const;
25
+ export type MembershipShape = typeof MembershipShapes[keyof typeof MembershipShapes];
19
26
 
20
27
  /**
21
28
  * Semantic position within domain (compiles to numeric center)
22
29
  */
23
- export type PositionSemantic = 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
30
+ export const PositionSemantics = {
31
+ veryLow: 'very-low',
32
+ low: 'low',
33
+ medium: 'medium',
34
+ high: 'high',
35
+ veryHigh: 'very-high',
36
+ } as const;
37
+ export type PositionSemantic = typeof PositionSemantics[keyof typeof PositionSemantics];
24
38
 
25
39
  /**
26
40
  * Semantic width/spread (compiles to numeric spread as % of domain)
27
41
  */
28
- export type WidthSemantic = 'tight' | 'narrow' | 'medium' | 'wide' | 'very-wide';
42
+ export const WidthSemantics = {
43
+ tight: 'tight',
44
+ narrow: 'narrow',
45
+ medium: 'medium',
46
+ wide: 'wide',
47
+ veryWide: 'very-wide',
48
+ } as const;
49
+ export type WidthSemantic = typeof WidthSemantics[keyof typeof WidthSemantics];
29
50
 
30
51
  /**
31
52
  * Edge behavior for shoulder/block shapes
32
53
  */
33
- export type EdgeSemantic = 'open-left' | 'open-right' | 'closed';
54
+ export const EdgeSemantics = {
55
+ openLeft: 'open-left',
56
+ openRight: 'open-right',
57
+ closed: 'closed',
58
+ } as const;
59
+ export type EdgeSemantic = typeof EdgeSemantics[keyof typeof EdgeSemantics];
34
60
 
35
61
  // ========================================
36
62
  // Fuzzy Term Definitions
@@ -127,33 +153,39 @@ export type CompiledFuzzyVariable = {
127
153
  /**
128
154
  * Aggregation methods - combine multiple rule activations for same output
129
155
  */
130
- export type AggregationMethod =
131
- | 'max' // Maximum membership (standard fuzzy OR)
132
- | 'sum' // Sum memberships (can exceed 1)
133
- | 'probor' // Probabilistic OR: a + b - ab
134
- | 'bound' // Bounded sum: min(1, a + b)
135
- | 'min'; // Intersection (rare)
156
+ export const AggregationMethods = {
157
+ max: 'max',
158
+ sum: 'sum',
159
+ probor: 'probor',
160
+ bound: 'bound',
161
+ min: 'min',
162
+ } as const;
163
+ export type AggregationMethod = typeof AggregationMethods[keyof typeof AggregationMethods];
136
164
 
137
165
  /**
138
166
  * Defuzzification methods - convert fuzzy output to crisp value
139
167
  */
140
- export type DefuzzifyMethod =
141
- | 'centroid' // Center of gravity (most common)
142
- | 'bisector' // Line that divides area in half
143
- | 'mom' // Mean of maximum
144
- | 'som' // Smallest of maximum
145
- | 'lom' // Largest of maximum
146
- | 'wtaver'; // Weighted average of term centers
168
+ export const DefuzzifyMethods = {
169
+ centroid: 'centroid',
170
+ bisector: 'bisector',
171
+ mom: 'mom',
172
+ som: 'som',
173
+ lom: 'lom',
174
+ wtaver: 'wtaver',
175
+ } as const;
176
+ export type DefuzzifyMethod = typeof DefuzzifyMethods[keyof typeof DefuzzifyMethods];
147
177
 
148
178
  /**
149
179
  * Transform methods - post-process the crisp output
150
180
  */
151
- export type TransformMethod =
152
- | 'clamp' // Enforce output bounds
153
- | 'round' // Round to integer
154
- | 'deadband' // Zero out small values
155
- | 'scale' // Scale to different range
156
- | 'quantize'; // Snap to discrete steps
181
+ export const TransformMethods = {
182
+ clamp: 'clamp',
183
+ round: 'round',
184
+ deadband: 'deadband',
185
+ scale: 'scale',
186
+ quantize: 'quantize',
187
+ } as const;
188
+ export type TransformMethod = typeof TransformMethods[keyof typeof TransformMethods];
157
189
 
158
190
  /**
159
191
  * Any defuzzification pipeline stage
@@ -163,14 +195,16 @@ export type DefuzzifyStage = AggregationMethod | DefuzzifyMethod | TransformMeth
163
195
  /**
164
196
  * Named presets that expand to full pipelines
165
197
  */
166
- export type DefuzzifyPreset =
167
- | 'balanced' // ['max', 'centroid', 'clamp'] - general purpose
168
- | 'smooth' // ['probor', 'centroid', 'clamp'] - gradual transitions
169
- | 'decisive' // ['max', 'mom'] - snappy response
170
- | 'cautious' // ['max', 'som', 'clamp'] - conservative
171
- | 'aggressive' // ['max', 'lom', 'clamp'] - responsive
172
- | 'discrete' // ['max', 'centroid', 'clamp', 'round'] - integer outputs
173
- | 'stable'; // ['max', 'centroid', 'deadband', 'clamp'] - reduce chatter
198
+ export const DefuzzifyPresets = {
199
+ balanced: 'balanced',
200
+ smooth: 'smooth',
201
+ decisive: 'decisive',
202
+ cautious: 'cautious',
203
+ aggressive: 'aggressive',
204
+ discrete: 'discrete',
205
+ stable: 'stable',
206
+ } as const;
207
+ export type DefuzzifyPreset = typeof DefuzzifyPresets[keyof typeof DefuzzifyPresets];
174
208
 
175
209
  /**
176
210
  * Defuzzification pipeline configuration
@@ -33,6 +33,15 @@ export type {
33
33
  LoyaltyIngestResult
34
34
  } from './types';
35
35
 
36
+ // Constants
37
+ export {
38
+ LoyaltyStrategies,
39
+ PointTransactionTypes,
40
+ TierStatuses,
41
+ QualifyingMetrics,
42
+ EvaluationPeriods
43
+ } from './types';
44
+
36
45
  // Compiler
37
46
  export { compileLoyaltyRuleSet } from './compiler';
38
47
 
@@ -14,19 +14,50 @@ import type { Condition } from '../../core/types/condition';
14
14
  // ========================================
15
15
 
16
16
  /** Loyalty strategy to use */
17
- export type LoyaltyStrategy = 'earning' | 'redemption' | 'tier-evaluation';
17
+ export const LoyaltyStrategies = {
18
+ earning: 'earning',
19
+ redemption: 'redemption',
20
+ tierEvaluation: 'tier-evaluation',
21
+ } as const;
22
+ export type LoyaltyStrategy = typeof LoyaltyStrategies[keyof typeof LoyaltyStrategies];
18
23
 
19
24
  /** Point transaction type */
20
- export type PointTransactionType = 'earn' | 'redeem' | 'expire' | 'transfer' | 'adjust';
25
+ export const PointTransactionTypes = {
26
+ earn: 'earn',
27
+ redeem: 'redeem',
28
+ expire: 'expire',
29
+ transfer: 'transfer',
30
+ adjust: 'adjust',
31
+ } as const;
32
+ export type PointTransactionType = typeof PointTransactionTypes[keyof typeof PointTransactionTypes];
21
33
 
22
34
  /** Member tier status */
23
- export type TierStatus = 'qualified' | 'at-risk' | 'downgrade-pending' | 'locked';
35
+ export const TierStatuses = {
36
+ qualified: 'qualified',
37
+ atRisk: 'at-risk',
38
+ downgradePending: 'downgrade-pending',
39
+ locked: 'locked',
40
+ } as const;
41
+ export type TierStatus = typeof TierStatuses[keyof typeof TierStatuses];
24
42
 
25
43
  /** Qualifying metric for tier evaluation */
26
- export type QualifyingMetric = 'points-earned' | 'qualifying-spend' | 'qualifying-nights' | 'qualifying-flights';
44
+ export const QualifyingMetrics = {
45
+ pointsEarned: 'points-earned',
46
+ qualifyingSpend: 'qualifying-spend',
47
+ qualifyingNights: 'qualifying-nights',
48
+ qualifyingFlights: 'qualifying-flights',
49
+ qualifyingRentalDays: 'qualifying-rental-days',
50
+ qualifyingCruiseDays: 'qualifying-cruise-days',
51
+ } as const;
52
+ export type QualifyingMetric = typeof QualifyingMetrics[keyof typeof QualifyingMetrics];
27
53
 
28
54
  /** Evaluation period for tier assessment */
29
- export type EvaluationPeriod = 'rolling-12-months' | 'calendar-year' | 'custom';
55
+ export const EvaluationPeriods = {
56
+ rolling12Months: 'rolling-12-months',
57
+ calendarYear: 'calendar-year',
58
+ custom: 'custom',
59
+ } as const;
60
+ export type EvaluationPeriod = typeof EvaluationPeriods[keyof typeof EvaluationPeriods];
30
61
 
31
62
  // ========================================
32
63
  // Core Domain Types
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Menu Engineering Engine Compiler
3
+ *
4
+ * Validates menu engineering rulesets and resolves defaults.
5
+ */
6
+
7
+ import { CompilationError } from '../../core/errors';
8
+
9
+ import type {
10
+ MenuEngineeringRuleSet,
11
+ CompiledMenuEngineeringRuleSet,
12
+ CompiledClassifyRuleSet,
13
+ CompiledPriceOptimizationRuleSet,
14
+ CompiledMixAnalysisRuleSet
15
+ } from './types';
16
+
17
+ /**
18
+ * Compile and validate a menu engineering ruleset.
19
+ */
20
+ export function compileMenuEngineeringRuleSet(
21
+ ruleSet: MenuEngineeringRuleSet
22
+ ): CompiledMenuEngineeringRuleSet {
23
+ if (!ruleSet.id) {
24
+ throw new CompilationError('Menu engineering ruleset requires an id');
25
+ }
26
+
27
+ if (ruleSet.mode !== 'menu-engineering') {
28
+ throw new CompilationError(`Expected mode 'menu-engineering', got '${ruleSet.mode}'`);
29
+ }
30
+
31
+ if (!ruleSet.items || ruleSet.items.length === 0) {
32
+ throw new CompilationError('Menu engineering ruleset requires at least one menu item');
33
+ }
34
+
35
+ // Validate unique item IDs
36
+ const itemIds = new Set<string>();
37
+ for (const item of ruleSet.items) {
38
+ if (!item.id) {
39
+ throw new CompilationError('Each menu item requires an id');
40
+ }
41
+ if (itemIds.has(item.id)) {
42
+ throw new CompilationError(`Duplicate menu item id: '${item.id}'`);
43
+ }
44
+ if (item.sellingPrice < 0) {
45
+ throw new CompilationError(`Menu item '${item.id}' sellingPrice must be non-negative`);
46
+ }
47
+ if (item.plateCost < 0) {
48
+ throw new CompilationError(`Menu item '${item.id}' plateCost must be non-negative`);
49
+ }
50
+ if (item.salesCount < 0) {
51
+ throw new CompilationError(`Menu item '${item.id}' salesCount must be non-negative`);
52
+ }
53
+ itemIds.add(item.id);
54
+ }
55
+
56
+ switch (ruleSet.strategy) {
57
+ case 'classify':
58
+ return compileClassify(ruleSet);
59
+ case 'price-optimization':
60
+ return compilePriceOptimization(ruleSet);
61
+ case 'mix-analysis':
62
+ return compileMixAnalysis(ruleSet);
63
+ default:
64
+ throw new CompilationError(`Unknown menu engineering strategy: '${(ruleSet as any).strategy}'`);
65
+ }
66
+ }
67
+
68
+ function compileClassify(
69
+ ruleSet: MenuEngineeringRuleSet & { strategy: 'classify' }
70
+ ): CompiledClassifyRuleSet {
71
+ const config = ruleSet.config ?? {};
72
+
73
+ return {
74
+ id: ruleSet.id,
75
+ name: ruleSet.name,
76
+ mode: 'menu-engineering',
77
+ strategy: 'classify',
78
+ items: ruleSet.items,
79
+ config: {
80
+ mixThresholdMode: config.mixThresholdMode ?? 'average',
81
+ customMixThreshold: config.customMixThreshold ?? 0,
82
+ marginThresholdMode: config.marginThresholdMode ?? 'average',
83
+ customMarginThreshold: config.customMarginThreshold ?? 0
84
+ }
85
+ };
86
+ }
87
+
88
+ function compilePriceOptimization(
89
+ ruleSet: MenuEngineeringRuleSet & { strategy: 'price-optimization' }
90
+ ): CompiledPriceOptimizationRuleSet {
91
+ if (!ruleSet.config || !ruleSet.config.priceChanges || ruleSet.config.priceChanges.length === 0) {
92
+ throw new CompilationError('Price-optimization strategy requires at least one price change');
93
+ }
94
+
95
+ // Validate price changes reference existing items
96
+ const itemIds = new Set(ruleSet.items.map(i => i.id));
97
+ for (const change of ruleSet.config.priceChanges) {
98
+ if (!itemIds.has(change.itemId)) {
99
+ throw new CompilationError(`Price change references unknown item: '${change.itemId}'`);
100
+ }
101
+ if (change.newPrice < 0) {
102
+ throw new CompilationError(`Price change for '${change.itemId}' newPrice must be non-negative`);
103
+ }
104
+ }
105
+
106
+ return {
107
+ id: ruleSet.id,
108
+ name: ruleSet.name,
109
+ mode: 'menu-engineering',
110
+ strategy: 'price-optimization',
111
+ items: ruleSet.items,
112
+ config: {
113
+ priceChanges: ruleSet.config.priceChanges,
114
+ elasticities: ruleSet.config.elasticities ?? [],
115
+ defaultElasticity: ruleSet.config.defaultElasticity ?? -1.0
116
+ }
117
+ };
118
+ }
119
+
120
+ function compileMixAnalysis(
121
+ ruleSet: MenuEngineeringRuleSet & { strategy: 'mix-analysis' }
122
+ ): CompiledMixAnalysisRuleSet {
123
+ const config = ruleSet.config ?? {};
124
+ const groupBy = config.groupBy ?? 'category';
125
+
126
+ if (groupBy === 'category') {
127
+ // Verify at least some items have categories
128
+ const hasCategories = ruleSet.items.some(i => i.category);
129
+ if (!hasCategories) {
130
+ throw new CompilationError('Mix-analysis with groupBy "category" requires items with category values');
131
+ }
132
+ }
133
+
134
+ return {
135
+ id: ruleSet.id,
136
+ name: ruleSet.name,
137
+ mode: 'menu-engineering',
138
+ strategy: 'mix-analysis',
139
+ items: ruleSet.items,
140
+ config: {
141
+ groupBy,
142
+ daypartField: config.daypartField ?? 'daypart'
143
+ }
144
+ };
145
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Menu Engineering Engine
3
+ *
4
+ * Classifies menu items into Stars/Plowhorses/Puzzles/Dogs based on
5
+ * sales mix percentage and contribution margin. Supports price optimization
6
+ * with elasticity modeling and category-level mix analysis.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const engine = new MenuEngineeringEngine();
11
+ *
12
+ * const result = engine.execute(compiledMenuEngineering);
13
+ * // result.items -> classified menu items with recommendations
14
+ * ```
15
+ */
16
+
17
+ import type {
18
+ CompiledMenuEngineeringRuleSet,
19
+ MenuEngineeringOptions,
20
+ MenuEngineeringResult
21
+ } from './types';
22
+
23
+ import { MenuEngineeringExecutor } from './strategy';
24
+
25
+ export class MenuEngineeringEngine {
26
+ private strategy: MenuEngineeringExecutor;
27
+
28
+ constructor() {
29
+ this.strategy = new MenuEngineeringExecutor();
30
+ }
31
+
32
+ /**
33
+ * Execute a menu engineering ruleset.
34
+ *
35
+ * Classifies menu items, optimizes prices, or analyzes category mix
36
+ * depending on the strategy.
37
+ *
38
+ * @param ruleSet - Compiled menu engineering ruleset
39
+ * @param options - Runtime options
40
+ * @returns Menu engineering result
41
+ */
42
+ execute(
43
+ ruleSet: CompiledMenuEngineeringRuleSet,
44
+ options: MenuEngineeringOptions = {}
45
+ ): MenuEngineeringResult {
46
+ return this.strategy.run(ruleSet, options);
47
+ }
48
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Menu Engineering Engine -- Menu Item Classification & Optimization
3
+ */
4
+
5
+ // Types
6
+ export type {
7
+ MenuEngineeringStrategy,
8
+ MenuClassification,
9
+ MenuItem,
10
+ PriceElasticity,
11
+ PriceChange,
12
+ ClassifyConfig,
13
+ PriceOptimizationConfig,
14
+ MixAnalysisConfig,
15
+ ClassifyRuleSet,
16
+ PriceOptimizationRuleSet,
17
+ MixAnalysisRuleSet,
18
+ MenuEngineeringRuleSet,
19
+ CompiledClassifyRuleSet,
20
+ CompiledPriceOptimizationRuleSet,
21
+ CompiledMixAnalysisRuleSet,
22
+ CompiledMenuEngineeringRuleSet,
23
+ ClassifiedItem,
24
+ MenuSummary,
25
+ PriceOptimizationItem,
26
+ CategoryMixResult,
27
+ ClassifyResult,
28
+ PriceOptimizationResult,
29
+ MixAnalysisResult,
30
+ MenuEngineeringResult,
31
+ MenuEngineeringOptions
32
+ } from './types';
33
+
34
+ // Constants
35
+ export {
36
+ MenuEngineeringStrategies,
37
+ MenuClassifications
38
+ } from './types';
39
+
40
+ // Compiler
41
+ export { compileMenuEngineeringRuleSet } from './compiler';
42
+
43
+ // Strategy
44
+ export { MenuEngineeringExecutor, menuEngineeringStrategy } from './strategy';
45
+
46
+ // Engine
47
+ export { MenuEngineeringEngine } from './engine';