@higher.archi/boe 1.0.29 → 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 (241) 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/compiler.d.ts +11 -0
  58. package/dist/engines/loyalty/compiler.d.ts.map +1 -0
  59. package/dist/engines/loyalty/compiler.js +144 -0
  60. package/dist/engines/loyalty/compiler.js.map +1 -0
  61. package/dist/engines/loyalty/engine.d.ts +76 -0
  62. package/dist/engines/loyalty/engine.d.ts.map +1 -0
  63. package/dist/engines/loyalty/engine.js +132 -0
  64. package/dist/engines/loyalty/engine.js.map +1 -0
  65. package/dist/engines/loyalty/index.d.ts +9 -0
  66. package/dist/engines/loyalty/index.d.ts.map +1 -0
  67. package/dist/engines/loyalty/index.js +24 -0
  68. package/dist/engines/loyalty/index.js.map +1 -0
  69. package/dist/engines/loyalty/strategy.d.ts +35 -0
  70. package/dist/engines/loyalty/strategy.d.ts.map +1 -0
  71. package/dist/engines/loyalty/strategy.js +405 -0
  72. package/dist/engines/loyalty/strategy.js.map +1 -0
  73. package/dist/engines/loyalty/types.d.ts +221 -0
  74. package/dist/engines/loyalty/types.d.ts.map +1 -0
  75. package/dist/engines/loyalty/types.js +51 -0
  76. package/dist/engines/loyalty/types.js.map +1 -0
  77. package/dist/engines/menu-engineering/compiler.d.ts +11 -0
  78. package/dist/engines/menu-engineering/compiler.d.ts.map +1 -0
  79. package/dist/engines/menu-engineering/compiler.js +119 -0
  80. package/dist/engines/menu-engineering/compiler.js.map +1 -0
  81. package/dist/engines/menu-engineering/engine.d.ts +32 -0
  82. package/dist/engines/menu-engineering/engine.d.ts.map +1 -0
  83. package/dist/engines/menu-engineering/engine.js +40 -0
  84. package/dist/engines/menu-engineering/engine.js.map +1 -0
  85. package/dist/engines/menu-engineering/index.d.ts +9 -0
  86. package/dist/engines/menu-engineering/index.d.ts.map +1 -0
  87. package/dist/engines/menu-engineering/index.js +21 -0
  88. package/dist/engines/menu-engineering/index.js.map +1 -0
  89. package/dist/engines/menu-engineering/strategy.d.ts +18 -0
  90. package/dist/engines/menu-engineering/strategy.d.ts.map +1 -0
  91. package/dist/engines/menu-engineering/strategy.js +318 -0
  92. package/dist/engines/menu-engineering/strategy.js.map +1 -0
  93. package/dist/engines/menu-engineering/types.d.ts +187 -0
  94. package/dist/engines/menu-engineering/types.d.ts.map +1 -0
  95. package/dist/engines/menu-engineering/types.js +27 -0
  96. package/dist/engines/menu-engineering/types.js.map +1 -0
  97. package/dist/engines/monte-carlo/index.d.ts +1 -1
  98. package/dist/engines/monte-carlo/index.d.ts.map +1 -1
  99. package/dist/engines/monte-carlo/index.js +5 -1
  100. package/dist/engines/monte-carlo/index.js.map +1 -1
  101. package/dist/engines/monte-carlo/types.d.ts +16 -1
  102. package/dist/engines/monte-carlo/types.d.ts.map +1 -1
  103. package/dist/engines/monte-carlo/types.js +23 -1
  104. package/dist/engines/monte-carlo/types.js.map +1 -1
  105. package/dist/engines/negotiation/index.d.ts +1 -0
  106. package/dist/engines/negotiation/index.d.ts.map +1 -1
  107. package/dist/engines/negotiation/index.js +7 -1
  108. package/dist/engines/negotiation/index.js.map +1 -1
  109. package/dist/engines/negotiation/types.d.ts +23 -4
  110. package/dist/engines/negotiation/types.d.ts.map +1 -1
  111. package/dist/engines/negotiation/types.js +27 -0
  112. package/dist/engines/negotiation/types.js.map +1 -1
  113. package/dist/engines/prediction/index.d.ts +1 -1
  114. package/dist/engines/prediction/index.d.ts.map +1 -1
  115. package/dist/engines/prediction/index.js +6 -1
  116. package/dist/engines/prediction/index.js.map +1 -1
  117. package/dist/engines/prediction/types.d.ts +35 -5
  118. package/dist/engines/prediction/types.d.ts.map +1 -1
  119. package/dist/engines/prediction/types.js +39 -1
  120. package/dist/engines/prediction/types.js.map +1 -1
  121. package/dist/engines/pricing/index.d.ts +2 -2
  122. package/dist/engines/pricing/index.d.ts.map +1 -1
  123. package/dist/engines/pricing/index.js +3 -1
  124. package/dist/engines/pricing/index.js.map +1 -1
  125. package/dist/engines/pricing/types.d.ts +15 -1
  126. package/dist/engines/pricing/types.d.ts.map +1 -1
  127. package/dist/engines/pricing/types.js +16 -1
  128. package/dist/engines/pricing/types.js.map +1 -1
  129. package/dist/engines/ranking/index.d.ts +1 -1
  130. package/dist/engines/ranking/index.d.ts.map +1 -1
  131. package/dist/engines/ranking/index.js +6 -1
  132. package/dist/engines/ranking/index.js.map +1 -1
  133. package/dist/engines/ranking/types.d.ts +32 -5
  134. package/dist/engines/ranking/types.d.ts.map +1 -1
  135. package/dist/engines/ranking/types.js +36 -1
  136. package/dist/engines/ranking/types.js.map +1 -1
  137. package/dist/engines/recipe-costing/compiler.d.ts +11 -0
  138. package/dist/engines/recipe-costing/compiler.d.ts.map +1 -0
  139. package/dist/engines/recipe-costing/compiler.js +177 -0
  140. package/dist/engines/recipe-costing/compiler.js.map +1 -0
  141. package/dist/engines/recipe-costing/engine.d.ts +32 -0
  142. package/dist/engines/recipe-costing/engine.d.ts.map +1 -0
  143. package/dist/engines/recipe-costing/engine.js +40 -0
  144. package/dist/engines/recipe-costing/engine.js.map +1 -0
  145. package/dist/engines/recipe-costing/index.d.ts +9 -0
  146. package/dist/engines/recipe-costing/index.d.ts.map +1 -0
  147. package/dist/engines/recipe-costing/index.js +21 -0
  148. package/dist/engines/recipe-costing/index.js.map +1 -0
  149. package/dist/engines/recipe-costing/strategy.d.ts +20 -0
  150. package/dist/engines/recipe-costing/strategy.d.ts.map +1 -0
  151. package/dist/engines/recipe-costing/strategy.js +265 -0
  152. package/dist/engines/recipe-costing/strategy.js.map +1 -0
  153. package/dist/engines/recipe-costing/types.d.ts +213 -0
  154. package/dist/engines/recipe-costing/types.d.ts.map +1 -0
  155. package/dist/engines/recipe-costing/types.js +36 -0
  156. package/dist/engines/recipe-costing/types.js.map +1 -0
  157. package/dist/engines/scoring/index.d.ts +1 -1
  158. package/dist/engines/scoring/index.d.ts.map +1 -1
  159. package/dist/engines/scoring/index.js +3 -1
  160. package/dist/engines/scoring/index.js.map +1 -1
  161. package/dist/engines/scoring/types.d.ts +8 -1
  162. package/dist/engines/scoring/types.d.ts.map +1 -1
  163. package/dist/engines/scoring/types.js +18 -1
  164. package/dist/engines/scoring/types.js.map +1 -1
  165. package/dist/engines/sentiment/index.d.ts +1 -1
  166. package/dist/engines/sentiment/index.d.ts.map +1 -1
  167. package/dist/engines/sentiment/index.js +3 -1
  168. package/dist/engines/sentiment/index.js.map +1 -1
  169. package/dist/engines/sentiment/types.d.ts +13 -2
  170. package/dist/engines/sentiment/types.d.ts.map +1 -1
  171. package/dist/engines/sentiment/types.js +17 -1
  172. package/dist/engines/sentiment/types.js.map +1 -1
  173. package/dist/engines/state-machine/index.d.ts +1 -1
  174. package/dist/engines/state-machine/index.d.ts.map +1 -1
  175. package/dist/engines/state-machine/index.js +5 -1
  176. package/dist/engines/state-machine/index.js.map +1 -1
  177. package/dist/engines/state-machine/types.d.ts +7 -0
  178. package/dist/engines/state-machine/types.d.ts.map +1 -1
  179. package/dist/engines/state-machine/types.js +14 -0
  180. package/dist/engines/state-machine/types.js.map +1 -1
  181. package/dist/engines/utility/index.d.ts +2 -2
  182. package/dist/engines/utility/index.d.ts.map +1 -1
  183. package/dist/engines/utility/index.js +4 -1
  184. package/dist/engines/utility/index.js.map +1 -1
  185. package/dist/engines/utility/types.d.ts +21 -3
  186. package/dist/engines/utility/types.d.ts.map +1 -1
  187. package/dist/engines/utility/types.js +37 -1
  188. package/dist/engines/utility/types.js.map +1 -1
  189. package/dist/index.d.ts +30 -21
  190. package/dist/index.d.ts.map +1 -1
  191. package/dist/index.js +80 -3
  192. package/dist/index.js.map +1 -1
  193. package/package.json +1 -1
  194. package/src/core/evaluation/decay.ts +13 -2
  195. package/src/core/types/rule.ts +25 -1
  196. package/src/engines/bayesian/index.ts +1 -0
  197. package/src/engines/bayesian/types.ts +10 -8
  198. package/src/engines/constraint/types.ts +40 -11
  199. package/src/engines/decay/index.ts +4 -0
  200. package/src/engines/decay/types.ts +26 -4
  201. package/src/engines/defeasible/index.ts +7 -0
  202. package/src/engines/defeasible/types.ts +42 -18
  203. package/src/engines/ensemble/index.ts +6 -0
  204. package/src/engines/ensemble/types.ts +17 -13
  205. package/src/engines/expert/index.ts +1 -0
  206. package/src/engines/expert/types.ts +11 -9
  207. package/src/engines/fuzzy/fuzzy.types.ts +65 -31
  208. package/src/engines/loyalty/compiler.ts +174 -0
  209. package/src/engines/loyalty/engine.ts +174 -0
  210. package/src/engines/loyalty/index.ts +52 -0
  211. package/src/engines/loyalty/strategy.ts +532 -0
  212. package/src/engines/loyalty/types.ts +283 -0
  213. package/src/engines/menu-engineering/compiler.ts +145 -0
  214. package/src/engines/menu-engineering/engine.ts +48 -0
  215. package/src/engines/menu-engineering/index.ts +47 -0
  216. package/src/engines/menu-engineering/strategy.ts +414 -0
  217. package/src/engines/menu-engineering/types.ts +242 -0
  218. package/src/engines/monte-carlo/index.ts +1 -0
  219. package/src/engines/monte-carlo/types.ts +16 -21
  220. package/src/engines/negotiation/index.ts +8 -0
  221. package/src/engines/negotiation/types.ts +23 -4
  222. package/src/engines/prediction/index.ts +5 -0
  223. package/src/engines/prediction/types.ts +35 -5
  224. package/src/engines/pricing/index.ts +3 -1
  225. package/src/engines/pricing/types.ts +17 -1
  226. package/src/engines/ranking/index.ts +5 -0
  227. package/src/engines/ranking/types.ts +32 -11
  228. package/src/engines/recipe-costing/compiler.ts +219 -0
  229. package/src/engines/recipe-costing/engine.ts +48 -0
  230. package/src/engines/recipe-costing/index.ts +48 -0
  231. package/src/engines/recipe-costing/strategy.ts +357 -0
  232. package/src/engines/recipe-costing/types.ts +269 -0
  233. package/src/engines/scoring/index.ts +2 -0
  234. package/src/engines/scoring/types.ts +8 -6
  235. package/src/engines/sentiment/index.ts +2 -0
  236. package/src/engines/sentiment/types.ts +13 -2
  237. package/src/engines/state-machine/index.ts +3 -0
  238. package/src/engines/state-machine/types.ts +8 -0
  239. package/src/engines/utility/index.ts +5 -0
  240. package/src/engines/utility/types.ts +23 -3
  241. package/src/index.ts +182 -7
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ /**
3
+ * Menu Engineering Engine Strategy
4
+ *
5
+ * Core execution logic for all menu engineering strategies:
6
+ * - classify: categorize items into Stars/Plowhorses/Puzzles/Dogs
7
+ * - price-optimization: model price change impacts with elasticity
8
+ * - mix-analysis: analyze category/daypart mix with divergence detection
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.menuEngineeringStrategy = exports.MenuEngineeringExecutor = void 0;
12
+ // ========================================
13
+ // Helpers
14
+ // ========================================
15
+ function round(value, decimals) {
16
+ const factor = Math.pow(10, decimals);
17
+ return Math.round(value * factor) / factor;
18
+ }
19
+ function classifyItem(salesMixPct, contributionMargin, mixThreshold, marginThreshold) {
20
+ const highMix = salesMixPct >= mixThreshold;
21
+ const highMargin = contributionMargin >= marginThreshold;
22
+ if (highMix && highMargin)
23
+ return 'star';
24
+ if (highMix && !highMargin)
25
+ return 'plowhorse';
26
+ if (!highMix && highMargin)
27
+ return 'puzzle';
28
+ return 'dog';
29
+ }
30
+ function getRecommendation(classification) {
31
+ switch (classification) {
32
+ case 'star':
33
+ return 'Maintain quality and visibility. Signature item -- protect pricing and placement.';
34
+ case 'plowhorse':
35
+ return 'Popular but low margin. Consider portion adjustments, ingredient substitution, or slight price increase.';
36
+ case 'puzzle':
37
+ return 'High margin but low sales. Improve menu placement, rename, or bundle with popular items.';
38
+ case 'dog':
39
+ return 'Low popularity and low margin. Consider removing, repositioning, or reworking the recipe.';
40
+ }
41
+ }
42
+ function computeClassifiedItems(items, mixThreshold, marginThreshold) {
43
+ const totalSalesCount = items.reduce((sum, item) => sum + item.salesCount, 0);
44
+ const classifiedItems = items.map(item => {
45
+ const contributionMargin = round(item.sellingPrice - item.plateCost, 2);
46
+ const foodCostPct = item.sellingPrice > 0
47
+ ? round((item.plateCost / item.sellingPrice) * 100, 2)
48
+ : 0;
49
+ const salesMixPct = totalSalesCount > 0
50
+ ? round((item.salesCount / totalSalesCount) * 100, 2)
51
+ : 0;
52
+ const classification = classifyItem(salesMixPct, contributionMargin, mixThreshold, marginThreshold);
53
+ return {
54
+ id: item.id,
55
+ name: item.name,
56
+ category: item.category,
57
+ sellingPrice: item.sellingPrice,
58
+ plateCost: item.plateCost,
59
+ salesCount: item.salesCount,
60
+ contributionMargin,
61
+ foodCostPct,
62
+ salesMixPct,
63
+ classification,
64
+ recommendation: getRecommendation(classification)
65
+ };
66
+ });
67
+ return { classifiedItems, totalSalesCount };
68
+ }
69
+ function computeSummary(items) {
70
+ const totalItems = items.length;
71
+ const totalSalesCount = items.reduce((sum, i) => sum + i.salesCount, 0);
72
+ const totalRevenue = items.reduce((sum, i) => sum + i.sellingPrice * i.salesCount, 0);
73
+ const totalCost = items.reduce((sum, i) => sum + i.plateCost * i.salesCount, 0);
74
+ const totalProfit = round(totalRevenue - totalCost, 2);
75
+ const avgContributionMargin = totalItems > 0
76
+ ? round(items.reduce((sum, i) => sum + i.contributionMargin, 0) / totalItems, 2)
77
+ : 0;
78
+ const avgFoodCostPct = totalItems > 0
79
+ ? round(items.reduce((sum, i) => sum + i.foodCostPct, 0) / totalItems, 2)
80
+ : 0;
81
+ const avgSalesMixPct = totalItems > 0
82
+ ? round(100 / totalItems, 2)
83
+ : 0;
84
+ const classificationCounts = {
85
+ star: 0,
86
+ plowhorse: 0,
87
+ puzzle: 0,
88
+ dog: 0
89
+ };
90
+ for (const item of items) {
91
+ classificationCounts[item.classification]++;
92
+ }
93
+ return {
94
+ totalItems,
95
+ totalSalesCount,
96
+ totalRevenue: round(totalRevenue, 2),
97
+ totalCost: round(totalCost, 2),
98
+ totalProfit,
99
+ avgContributionMargin,
100
+ avgFoodCostPct,
101
+ avgSalesMixPct,
102
+ classificationCounts
103
+ };
104
+ }
105
+ // ========================================
106
+ // Strategy Executor
107
+ // ========================================
108
+ class MenuEngineeringExecutor {
109
+ run(ruleSet, _options = {}) {
110
+ switch (ruleSet.strategy) {
111
+ case 'classify':
112
+ return this.runClassify(ruleSet);
113
+ case 'price-optimization':
114
+ return this.runPriceOptimization(ruleSet);
115
+ case 'mix-analysis':
116
+ return this.runMixAnalysis(ruleSet);
117
+ default:
118
+ throw new Error(`Unknown menu engineering strategy: '${ruleSet.strategy}'`);
119
+ }
120
+ }
121
+ // ========================================
122
+ // Classify Strategy
123
+ // ========================================
124
+ runClassify(ruleSet) {
125
+ const startTime = performance.now();
126
+ // Compute thresholds
127
+ const items = ruleSet.items;
128
+ const totalSalesCount = items.reduce((sum, i) => sum + i.salesCount, 0);
129
+ const margins = items.map(i => i.sellingPrice - i.plateCost);
130
+ const mixPcts = items.map(i => totalSalesCount > 0 ? (i.salesCount / totalSalesCount) * 100 : 0);
131
+ const avgMargin = margins.reduce((sum, m) => sum + m, 0) / margins.length;
132
+ const avgMix = mixPcts.reduce((sum, m) => sum + m, 0) / mixPcts.length;
133
+ const mixThreshold = ruleSet.config.mixThresholdMode === 'custom'
134
+ ? ruleSet.config.customMixThreshold
135
+ : avgMix;
136
+ const marginThreshold = ruleSet.config.marginThresholdMode === 'custom'
137
+ ? ruleSet.config.customMarginThreshold
138
+ : avgMargin;
139
+ const { classifiedItems } = computeClassifiedItems(items, mixThreshold, marginThreshold);
140
+ const summary = computeSummary(classifiedItems);
141
+ const executionTimeMs = round((performance.now() - startTime) * 100, 0) / 100;
142
+ return {
143
+ items: classifiedItems,
144
+ summary,
145
+ executionTimeMs
146
+ };
147
+ }
148
+ // ========================================
149
+ // Price Optimization Strategy
150
+ // ========================================
151
+ runPriceOptimization(ruleSet) {
152
+ const startTime = performance.now();
153
+ // Run baseline classify
154
+ const items = ruleSet.items;
155
+ const totalSalesCount = items.reduce((sum, i) => sum + i.salesCount, 0);
156
+ const margins = items.map(i => i.sellingPrice - i.plateCost);
157
+ const mixPcts = items.map(i => totalSalesCount > 0 ? (i.salesCount / totalSalesCount) * 100 : 0);
158
+ const avgMargin = margins.reduce((sum, m) => sum + m, 0) / margins.length;
159
+ const avgMix = mixPcts.reduce((sum, m) => sum + m, 0) / mixPcts.length;
160
+ const { classifiedItems: baselineItems } = computeClassifiedItems(items, avgMix, avgMargin);
161
+ // Build lookup maps
162
+ const baselineMap = new Map(baselineItems.map(i => [i.id, i]));
163
+ const priceChangeMap = new Map(ruleSet.config.priceChanges.map(pc => [pc.itemId, pc]));
164
+ const elasticityMap = new Map();
165
+ for (const e of ruleSet.config.elasticities) {
166
+ if (e.itemId) {
167
+ elasticityMap.set(`item:${e.itemId}`, e.elasticity);
168
+ }
169
+ if (e.category) {
170
+ elasticityMap.set(`cat:${e.category}`, e.elasticity);
171
+ }
172
+ }
173
+ // Apply price changes and compute new projected items
174
+ const modifiedItems = items.map(item => {
175
+ const change = priceChangeMap.get(item.id);
176
+ if (!change)
177
+ return item;
178
+ return { ...item, sellingPrice: change.newPrice };
179
+ });
180
+ // Estimate new sales counts based on elasticity
181
+ const projectedItems = modifiedItems.map(item => {
182
+ const change = priceChangeMap.get(item.id);
183
+ if (!change)
184
+ return item;
185
+ const originalItem = items.find(i => i.id === item.id);
186
+ const priceChangePct = (change.newPrice - originalItem.sellingPrice) / originalItem.sellingPrice;
187
+ // Resolve elasticity: item-specific > category > default
188
+ let elasticity = ruleSet.config.defaultElasticity;
189
+ if (elasticityMap.has(`item:${item.id}`)) {
190
+ elasticity = elasticityMap.get(`item:${item.id}`);
191
+ }
192
+ else if (item.category && elasticityMap.has(`cat:${item.category}`)) {
193
+ elasticity = elasticityMap.get(`cat:${item.category}`);
194
+ }
195
+ const estimatedNewSalesCount = Math.max(0, Math.round(originalItem.salesCount * (1 + elasticity * priceChangePct)));
196
+ return { ...item, salesCount: estimatedNewSalesCount };
197
+ });
198
+ // Re-classify with new data
199
+ const newTotalSalesCount = projectedItems.reduce((sum, i) => sum + i.salesCount, 0);
200
+ const newMargins = projectedItems.map(i => i.sellingPrice - i.plateCost);
201
+ const newMixPcts = projectedItems.map(i => newTotalSalesCount > 0 ? (i.salesCount / newTotalSalesCount) * 100 : 0);
202
+ const newAvgMargin = newMargins.reduce((sum, m) => sum + m, 0) / newMargins.length;
203
+ const newAvgMix = newMixPcts.reduce((sum, m) => sum + m, 0) / newMixPcts.length;
204
+ const { classifiedItems: newClassifiedItems } = computeClassifiedItems(projectedItems, newAvgMix, newAvgMargin);
205
+ const newClassifiedMap = new Map(newClassifiedItems.map(i => [i.id, i]));
206
+ // Build optimization results for changed items
207
+ const optimizationItems = [];
208
+ for (const change of ruleSet.config.priceChanges) {
209
+ const baseline = baselineMap.get(change.itemId);
210
+ const projected = newClassifiedMap.get(change.itemId);
211
+ const originalItem = items.find(i => i.id === change.itemId);
212
+ const priceChangePct = round(((change.newPrice - originalItem.sellingPrice) / originalItem.sellingPrice) * 100, 2);
213
+ const originalRevenue = originalItem.sellingPrice * originalItem.salesCount;
214
+ const originalProfit = baseline.contributionMargin * originalItem.salesCount;
215
+ const projectedRevenue = projected.sellingPrice * projected.salesCount;
216
+ const projectedProfit = projected.contributionMargin * projected.salesCount;
217
+ optimizationItems.push({
218
+ id: change.itemId,
219
+ name: baseline.name,
220
+ originalPrice: originalItem.sellingPrice,
221
+ newPrice: change.newPrice,
222
+ priceChangePct,
223
+ originalMargin: baseline.contributionMargin,
224
+ newMargin: projected.contributionMargin,
225
+ estimatedNewSalesCount: projected.salesCount,
226
+ originalClassification: baseline.classification,
227
+ newClassification: projected.classification,
228
+ projectedRevenueChange: round(projectedRevenue - originalRevenue, 2),
229
+ projectedProfitChange: round(projectedProfit - originalProfit, 2)
230
+ });
231
+ }
232
+ const summary = computeSummary(newClassifiedItems);
233
+ const executionTimeMs = round((performance.now() - startTime) * 100, 0) / 100;
234
+ return {
235
+ items: optimizationItems,
236
+ summary,
237
+ executionTimeMs
238
+ };
239
+ }
240
+ // ========================================
241
+ // Mix Analysis Strategy
242
+ // ========================================
243
+ runMixAnalysis(ruleSet) {
244
+ const startTime = performance.now();
245
+ const items = ruleSet.items;
246
+ const groupField = ruleSet.config.groupBy === 'daypart'
247
+ ? ruleSet.config.daypartField
248
+ : 'category';
249
+ // Group items
250
+ const groups = new Map();
251
+ for (const item of items) {
252
+ const key = item[groupField] ?? 'uncategorized';
253
+ if (!groups.has(key)) {
254
+ groups.set(key, []);
255
+ }
256
+ groups.get(key).push(item);
257
+ }
258
+ // Compute overall totals for mix percentages
259
+ const overallTotalSalesCount = items.reduce((sum, i) => sum + i.salesCount, 0);
260
+ const overallTotalRevenue = items.reduce((sum, i) => sum + i.sellingPrice * i.salesCount, 0);
261
+ const overallTotalProfit = items.reduce((sum, i) => sum + (i.sellingPrice - i.plateCost) * i.salesCount, 0);
262
+ // Run classify within each group and compute category-level metrics
263
+ const categories = [];
264
+ for (const [category, groupItems] of groups) {
265
+ // Classify within group
266
+ const totalGroupSales = groupItems.reduce((sum, i) => sum + i.salesCount, 0);
267
+ const groupMargins = groupItems.map(i => i.sellingPrice - i.plateCost);
268
+ const groupMixPcts = groupItems.map(i => totalGroupSales > 0 ? (i.salesCount / totalGroupSales) * 100 : 0);
269
+ const groupAvgMargin = groupMargins.reduce((sum, m) => sum + m, 0) / groupMargins.length;
270
+ const groupAvgMix = groupMixPcts.reduce((sum, m) => sum + m, 0) / groupMixPcts.length;
271
+ const { classifiedItems } = computeClassifiedItems(groupItems, groupAvgMix, groupAvgMargin);
272
+ const totalRevenue = groupItems.reduce((sum, i) => sum + i.sellingPrice * i.salesCount, 0);
273
+ const totalCost = groupItems.reduce((sum, i) => sum + i.plateCost * i.salesCount, 0);
274
+ const totalProfit = totalRevenue - totalCost;
275
+ const avgContributionMargin = groupItems.length > 0
276
+ ? round(groupItems.reduce((sum, i) => sum + (i.sellingPrice - i.plateCost), 0) / groupItems.length, 2)
277
+ : 0;
278
+ categories.push({
279
+ category,
280
+ itemCount: groupItems.length,
281
+ totalSalesCount: totalGroupSales,
282
+ totalRevenue: round(totalRevenue, 2),
283
+ totalCost: round(totalCost, 2),
284
+ totalProfit: round(totalProfit, 2),
285
+ avgContributionMargin,
286
+ salesMixPct: overallTotalSalesCount > 0
287
+ ? round((totalGroupSales / overallTotalSalesCount) * 100, 2)
288
+ : 0,
289
+ revenueMixPct: overallTotalRevenue > 0
290
+ ? round((totalRevenue / overallTotalRevenue) * 100, 2)
291
+ : 0,
292
+ profitMixPct: overallTotalProfit > 0
293
+ ? round((totalProfit / overallTotalProfit) * 100, 2)
294
+ : 0,
295
+ items: classifiedItems
296
+ });
297
+ }
298
+ // Sort categories by revenue descending
299
+ categories.sort((a, b) => b.totalRevenue - a.totalRevenue);
300
+ // Compute overall summary using all items classified globally
301
+ const allMargins = items.map(i => i.sellingPrice - i.plateCost);
302
+ const allMixPcts = items.map(i => overallTotalSalesCount > 0 ? (i.salesCount / overallTotalSalesCount) * 100 : 0);
303
+ const overallAvgMargin = allMargins.reduce((sum, m) => sum + m, 0) / allMargins.length;
304
+ const overallAvgMix = allMixPcts.reduce((sum, m) => sum + m, 0) / allMixPcts.length;
305
+ const { classifiedItems: allClassified } = computeClassifiedItems(items, overallAvgMix, overallAvgMargin);
306
+ const summary = computeSummary(allClassified);
307
+ const executionTimeMs = round((performance.now() - startTime) * 100, 0) / 100;
308
+ return {
309
+ categories,
310
+ summary,
311
+ executionTimeMs
312
+ };
313
+ }
314
+ }
315
+ exports.MenuEngineeringExecutor = MenuEngineeringExecutor;
316
+ /** Singleton instance */
317
+ exports.menuEngineeringStrategy = new MenuEngineeringExecutor();
318
+ //# sourceMappingURL=strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../../src/engines/menu-engineering/strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Menu Engineering Engine Types
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
+ /** Menu engineering strategy to use */
9
+ export declare const MenuEngineeringStrategies: {
10
+ readonly classify: "classify";
11
+ readonly priceOptimization: "price-optimization";
12
+ readonly mixAnalysis: "mix-analysis";
13
+ };
14
+ export type MenuEngineeringStrategy = typeof MenuEngineeringStrategies[keyof typeof MenuEngineeringStrategies];
15
+ /** Menu item classification quadrant */
16
+ export declare const MenuClassifications: {
17
+ readonly star: "star";
18
+ readonly plowhorse: "plowhorse";
19
+ readonly puzzle: "puzzle";
20
+ readonly dog: "dog";
21
+ };
22
+ export type MenuClassification = typeof MenuClassifications[keyof typeof MenuClassifications];
23
+ /** A menu item with sales and cost data */
24
+ export type MenuItem = {
25
+ id: string;
26
+ name: string;
27
+ category?: string;
28
+ sellingPrice: number;
29
+ plateCost: number;
30
+ salesCount: number;
31
+ };
32
+ /** Price elasticity for an item or category */
33
+ export type PriceElasticity = {
34
+ itemId?: string;
35
+ category?: string;
36
+ elasticity: number;
37
+ };
38
+ /** A proposed price change for a menu item */
39
+ export type PriceChange = {
40
+ itemId: string;
41
+ newPrice: number;
42
+ };
43
+ /** Configuration for classify strategy */
44
+ export type ClassifyConfig = {
45
+ mixThresholdMode?: 'average' | 'custom';
46
+ customMixThreshold?: number;
47
+ marginThresholdMode?: 'average' | 'custom';
48
+ customMarginThreshold?: number;
49
+ };
50
+ /** Configuration for price-optimization strategy */
51
+ export type PriceOptimizationConfig = {
52
+ priceChanges: PriceChange[];
53
+ elasticities?: PriceElasticity[];
54
+ defaultElasticity?: number;
55
+ };
56
+ /** Configuration for mix-analysis strategy */
57
+ export type MixAnalysisConfig = {
58
+ groupBy?: 'category' | 'daypart';
59
+ daypartField?: string;
60
+ };
61
+ type MenuEngineeringRuleSetBase = {
62
+ id: string;
63
+ name?: string;
64
+ mode: 'menu-engineering';
65
+ items: MenuItem[];
66
+ };
67
+ /** Classify strategy: categorize items into quadrants */
68
+ export type ClassifyRuleSet = MenuEngineeringRuleSetBase & {
69
+ strategy: 'classify';
70
+ config?: ClassifyConfig;
71
+ };
72
+ /** Price-optimization strategy: model price change impacts */
73
+ export type PriceOptimizationRuleSet = MenuEngineeringRuleSetBase & {
74
+ strategy: 'price-optimization';
75
+ config: PriceOptimizationConfig;
76
+ };
77
+ /** Mix-analysis strategy: analyze category/daypart mix */
78
+ export type MixAnalysisRuleSet = MenuEngineeringRuleSetBase & {
79
+ strategy: 'mix-analysis';
80
+ config?: MixAnalysisConfig;
81
+ };
82
+ export type MenuEngineeringRuleSet = ClassifyRuleSet | PriceOptimizationRuleSet | MixAnalysisRuleSet;
83
+ type CompiledMenuEngineeringRuleSetBase = {
84
+ id: string;
85
+ name?: string;
86
+ mode: 'menu-engineering';
87
+ items: MenuItem[];
88
+ };
89
+ export type CompiledClassifyRuleSet = CompiledMenuEngineeringRuleSetBase & {
90
+ strategy: 'classify';
91
+ config: Required<ClassifyConfig>;
92
+ };
93
+ export type CompiledPriceOptimizationRuleSet = CompiledMenuEngineeringRuleSetBase & {
94
+ strategy: 'price-optimization';
95
+ config: {
96
+ priceChanges: PriceChange[];
97
+ elasticities: PriceElasticity[];
98
+ defaultElasticity: number;
99
+ };
100
+ };
101
+ export type CompiledMixAnalysisRuleSet = CompiledMenuEngineeringRuleSetBase & {
102
+ strategy: 'mix-analysis';
103
+ config: {
104
+ groupBy: 'category' | 'daypart';
105
+ daypartField: string;
106
+ };
107
+ };
108
+ export type CompiledMenuEngineeringRuleSet = CompiledClassifyRuleSet | CompiledPriceOptimizationRuleSet | CompiledMixAnalysisRuleSet;
109
+ /** A classified menu item with computed metrics */
110
+ export type ClassifiedItem = {
111
+ id: string;
112
+ name: string;
113
+ category?: string;
114
+ sellingPrice: number;
115
+ plateCost: number;
116
+ salesCount: number;
117
+ contributionMargin: number;
118
+ foodCostPct: number;
119
+ salesMixPct: number;
120
+ classification: MenuClassification;
121
+ recommendation: string;
122
+ };
123
+ /** Summary statistics for the menu */
124
+ export type MenuSummary = {
125
+ totalItems: number;
126
+ totalSalesCount: number;
127
+ totalRevenue: number;
128
+ totalCost: number;
129
+ totalProfit: number;
130
+ avgContributionMargin: number;
131
+ avgFoodCostPct: number;
132
+ avgSalesMixPct: number;
133
+ classificationCounts: Record<MenuClassification, number>;
134
+ };
135
+ /** A price-optimized menu item with projected impact */
136
+ export type PriceOptimizationItem = {
137
+ id: string;
138
+ name: string;
139
+ originalPrice: number;
140
+ newPrice: number;
141
+ priceChangePct: number;
142
+ originalMargin: number;
143
+ newMargin: number;
144
+ estimatedNewSalesCount: number;
145
+ originalClassification: MenuClassification;
146
+ newClassification: MenuClassification;
147
+ projectedRevenueChange: number;
148
+ projectedProfitChange: number;
149
+ };
150
+ /** Category-level mix analysis result */
151
+ export type CategoryMixResult = {
152
+ category: string;
153
+ itemCount: number;
154
+ totalSalesCount: number;
155
+ totalRevenue: number;
156
+ totalCost: number;
157
+ totalProfit: number;
158
+ avgContributionMargin: number;
159
+ salesMixPct: number;
160
+ revenueMixPct: number;
161
+ profitMixPct: number;
162
+ items: ClassifiedItem[];
163
+ };
164
+ /** Result from classify strategy */
165
+ export type ClassifyResult = {
166
+ items: ClassifiedItem[];
167
+ summary: MenuSummary;
168
+ executionTimeMs: number;
169
+ };
170
+ /** Result from price-optimization strategy */
171
+ export type PriceOptimizationResult = {
172
+ items: PriceOptimizationItem[];
173
+ summary: MenuSummary;
174
+ executionTimeMs: number;
175
+ };
176
+ /** Result from mix-analysis strategy */
177
+ export type MixAnalysisResult = {
178
+ categories: CategoryMixResult[];
179
+ summary: MenuSummary;
180
+ executionTimeMs: number;
181
+ };
182
+ /** Union of all menu engineering results */
183
+ export type MenuEngineeringResult = ClassifyResult | PriceOptimizationResult | MixAnalysisResult;
184
+ /** Runtime options */
185
+ export type MenuEngineeringOptions = Record<string, never>;
186
+ export {};
187
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/engines/menu-engineering/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /**
3
+ * Menu Engineering Engine Types
4
+ *
5
+ * Classifies menu items into Stars/Plowhorses/Puzzles/Dogs based on
6
+ * sales mix percentage and contribution margin. Supports price optimization
7
+ * with elasticity modeling and category-level mix analysis.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.MenuClassifications = exports.MenuEngineeringStrategies = void 0;
11
+ // ========================================
12
+ // Semantic Types
13
+ // ========================================
14
+ /** Menu engineering strategy to use */
15
+ exports.MenuEngineeringStrategies = {
16
+ classify: 'classify',
17
+ priceOptimization: 'price-optimization',
18
+ mixAnalysis: 'mix-analysis',
19
+ };
20
+ /** Menu item classification quadrant */
21
+ exports.MenuClassifications = {
22
+ star: 'star',
23
+ plowhorse: 'plowhorse',
24
+ puzzle: 'puzzle',
25
+ dog: 'dog',
26
+ };
27
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/engines/menu-engineering/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,2CAA2C;AAC3C,iBAAiB;AACjB,2CAA2C;AAE3C,uCAAuC;AAC1B,QAAA,yBAAyB,GAAG;IACvC,QAAQ,EAAE,UAAU;IACpB,iBAAiB,EAAE,oBAAoB;IACvC,WAAW,EAAE,cAAc;CACnB,CAAC;AAGX,wCAAwC;AAC3B,QAAA,mBAAmB,GAAG;IACjC,IAAI,EAAE,MAAM;IACZ,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;IAChB,GAAG,EAAE,KAAK;CACF,CAAC"}
@@ -5,7 +5,7 @@
5
5
  * Run thousands of simulations with probabilistic inputs to get
6
6
  * statistical distributions of possible outcomes.
7
7
  */
8
- export { EstimateType, PercentOrNumber, TriangularVariable, NormalVariable, UniformVariable, DiscreteVariable, MonteCarloVariable, MonteCarloOutput, MonteCarloRuleSet, MonteCarloConfig, CompiledVariable, CompiledOutput, CompiledMonteCarloRuleSet, MonteCarloOptions, OutputStatistics, HistogramBin, SensitivityAnalysis, MonteCarloResult } from './types';
8
+ export { EstimateTypes, EstimateType, PercentOrNumber, TriangularVariable, NormalVariable, UniformVariable, DiscreteVariable, MonteCarloVariable, MonteCarloOutput, MonteCarloRuleSet, MonteCarloConfig, CompiledVariable, CompiledOutput, CompiledMonteCarloRuleSet, MonteCarloOptions, OutputStatistics, HistogramBin, SensitivityAnalysis, MonteCarloResult } from './types';
9
9
  export { compileMonteCarloRuleSet } from './compiler';
10
10
  export { MonteCarloStrategy, monteCarloStrategy } from './strategy';
11
11
  export { MonteCarloEngine } from './engine';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engines/monte-carlo/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAEL,YAAY,EACZ,eAAe,EAEf,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAElB,gBAAgB,EAEhB,iBAAiB,EACjB,gBAAgB,EAEhB,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EAEzB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engines/monte-carlo/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAEL,aAAa,EACb,YAAY,EACZ,eAAe,EAEf,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAElB,gBAAgB,EAEhB,iBAAiB,EACjB,gBAAgB,EAEhB,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EAEzB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
@@ -7,7 +7,11 @@
7
7
  * statistical distributions of possible outcomes.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.MonteCarloEngine = exports.monteCarloStrategy = exports.MonteCarloStrategy = exports.compileMonteCarloRuleSet = void 0;
10
+ exports.MonteCarloEngine = exports.monteCarloStrategy = exports.MonteCarloStrategy = exports.compileMonteCarloRuleSet = exports.EstimateTypes = void 0;
11
+ // Types
12
+ var types_1 = require("./types");
13
+ // Estimate types
14
+ Object.defineProperty(exports, "EstimateTypes", { enumerable: true, get: function () { return types_1.EstimateTypes; } });
11
15
  // Compiler
12
16
  var compiler_1 = require("./compiler");
13
17
  Object.defineProperty(exports, "compileMonteCarloRuleSet", { enumerable: true, get: function () { return compiler_1.compileMonteCarloRuleSet; } });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engines/monte-carlo/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AA8BH,WAAW;AACX,uCAAsD;AAA7C,oHAAA,wBAAwB,OAAA;AAEjC,WAAW;AACX,uCAAoE;AAA3D,8GAAA,kBAAkB,OAAA;AAAE,8GAAA,kBAAkB,OAAA;AAE/C,SAAS;AACT,mCAA4C;AAAnC,0GAAA,gBAAgB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engines/monte-carlo/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,QAAQ;AACR,iCA0BiB;AAzBf,iBAAiB;AACjB,sGAAA,aAAa,OAAA;AA0Bf,WAAW;AACX,uCAAsD;AAA7C,oHAAA,wBAAwB,OAAA;AAEjC,WAAW;AACX,uCAAoE;AAA3D,8GAAA,kBAAkB,OAAA;AAAE,8GAAA,kBAAkB,OAAA;AAE/C,SAAS;AACT,mCAA4C;AAAnC,0GAAA,gBAAgB,OAAA"}
@@ -33,7 +33,22 @@ export declare const ITERATION_PRESETS: Record<IterationPreset, number>;
33
33
  * Estimate type determines the probability distribution shape.
34
34
  * Multiple aliases supported for different audiences.
35
35
  */
36
- export type EstimateType = 'best-likely-worst' | 'low-mid-high' | 'min-expected-max' | 'optimistic-realistic-pessimistic' | 'typically-around' | 'bell-curve' | 'normal' | 'anywhere-from' | 'uniform' | 'any-between' | 'one-of' | 'weighted' | 'choice';
36
+ export declare const EstimateTypes: {
37
+ readonly bestLikelyWorst: "best-likely-worst";
38
+ readonly lowMidHigh: "low-mid-high";
39
+ readonly minExpectedMax: "min-expected-max";
40
+ readonly optimisticRealisticPessimistic: "optimistic-realistic-pessimistic";
41
+ readonly typicallyAround: "typically-around";
42
+ readonly bellCurve: "bell-curve";
43
+ readonly normal: "normal";
44
+ readonly anywhereFrom: "anywhere-from";
45
+ readonly uniform: "uniform";
46
+ readonly anyBetween: "any-between";
47
+ readonly oneOf: "one-of";
48
+ readonly weighted: "weighted";
49
+ readonly choice: "choice";
50
+ };
51
+ export type EstimateType = typeof EstimateTypes[keyof typeof EstimateTypes];
37
52
  /**
38
53
  * Percent or number value
39
54
  * Strings ending in '%' are parsed: '50%' -> 0.50