@orkestrel/rater 0.0.13 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,17 @@
1
1
  # @orkestrel/rater
2
2
 
3
- A typed **quantitative rating layer** over [`@orkestrel/reason`](https://github.com/orkestrel/reason):
4
- authored **lines** — each a plain reason `QuantitativeDefinition` joined to display
5
- metadata — are rated against a **subject** (a plain data record) to produce a
6
- `LineResult` per line (an `amount` plus its `Worksheet` audit trail) and one
7
- `RatingResult` (every line's outcome plus a derived `total`). The caller decides
8
- which lines to rate; `Rater` only evaluates what it is given. Rating never mutates
9
- its inputs — every result is a fresh object. Environment-agnostic — no I/O, no
10
- browser or server assumptions. Part of the `@orkestrel` line.
3
+ > A typed quantitative rating layer over `@orkestrel/reason`'s shared engine: authored
4
+ > lines, each a plain reason `QuantitativeDefinition` joined to display metadata, rated
5
+ > against one subject to produce a `LineResult` per line — an `amount` and its
6
+ > `Worksheet` audit trail — and one `RatingResult` carrying every line's outcome and a
7
+ > derived `total`.
8
+
9
+ Create a rater with the `createRater` function, hand it the lines a subject is rated
10
+ against, and read the `LineResult` rows and the `total` it derives. Inject a
11
+ [`@orkestrel/reason`](https://github.com/orkestrel/reason) `ReasonInterface` where the
12
+ rating shares an engine with the rest of your reasoning, and call `destroy()` when the
13
+ rater's work is done. Environment-agnostic — no I/O, no browser or server assumptions.
14
+ Part of the `@orkestrel` line.
11
15
 
12
16
  ## Install
13
17
 
@@ -50,7 +54,7 @@ rater.destroy()
50
54
  ```
51
55
 
52
56
  `rate` accepts a plain `LineDefinition[]` or a full `RatingDefinition` plus one
53
- subject — both overloads rate a single subject. Every `rate` call fires once
57
+ subject, and each overload rates that single subject. Every `rate` call fires once
54
58
  through `rater.emitter` (`rate`).
55
59
 
56
60
  ## Guide
@@ -9,7 +9,8 @@ let _orkestrel_emitter = require("@orkestrel/emitter");
9
9
  * @remarks
10
10
  * `DEFINITION` — the `rate` input failed both the array-of-lines and rating
11
11
  * definition validation. `MISMATCH` — a rated subject is not a record.
12
- * `DESTROYED` — use of a destroyed entity.
12
+ * `DESTROYED` — use of a destroyed entity. `context` carries optional
13
+ * structured detail beside the message.
13
14
  *
14
15
  * @example
15
16
  * ```ts
@@ -46,13 +47,17 @@ var RaterError = class extends Error {
46
47
  * ```
47
48
  */
48
49
  function isRaterError(value) {
49
- return value instanceof RaterError;
50
+ return (0, _orkestrel_contract.isInstance)(value, RaterError);
50
51
  }
51
52
  //#endregion
52
53
  //#region src/core/validators.ts
53
54
  /**
54
55
  * Determines whether a value is a {@link Stage} literal.
55
56
  *
57
+ * @remarks
58
+ * A scalar union has no open or exact axis, so this guard accepts one of the
59
+ * `Stage` literals and leaves nothing unchecked.
60
+ *
56
61
  * @param value - The value to test
57
62
  * @returns True if `value` is `'factor'`, `'group'`, or `'total'`; false otherwise
58
63
  *
@@ -69,8 +74,11 @@ var isStage = (0, _orkestrel_contract.literalOf)("factor", "group", "total");
69
74
  * Determines whether a value is an exact {@link LineDefinition} record.
70
75
  *
71
76
  * @remarks
72
- * Total guard: adversarial input (cycles, hostile prototypes) returns `false`,
73
- * never throws. The record shape is EXACT — an extra key fails.
77
+ * Every `LineDefinition` member is checked, including its quantitative
78
+ * definition. Total guard: adversarial input (cycles, hostile prototypes)
79
+ * returns `false`, never throws. The record shape is exact — this package owns
80
+ * the authored input record, so an extra key fails and nothing is left
81
+ * unchecked.
74
82
  *
75
83
  * @param value - The value to test
76
84
  * @returns True if `value` is a `LineDefinition`; false otherwise
@@ -96,8 +104,11 @@ function isLineDefinition(value) {
96
104
  * Determines whether a value is an exact {@link RatingDefinition} record.
97
105
  *
98
106
  * @remarks
99
- * Total guard: adversarial input (cycles, hostile prototypes) returns `false`,
100
- * never throws. The record shape is EXACT — an extra key fails.
107
+ * Every `RatingDefinition` member is checked, including each nested line
108
+ * definition. Total guard: adversarial input (cycles, hostile prototypes)
109
+ * returns `false`, never throws. The record shape is exact — this package owns
110
+ * the authored input record, so an extra key fails and nothing is left
111
+ * unchecked.
101
112
  *
102
113
  * @param value - The value to test
103
114
  * @returns True if `value` is a `RatingDefinition`; false otherwise
@@ -122,10 +133,13 @@ function isRatingDefinition(value) {
122
133
  * Determines whether a value is an open result-side {@link Evidence} object.
123
134
  *
124
135
  * @remarks
136
+ * Optional `field` is checked as a `FieldPath`, `label` as a string,
137
+ * `comparison` as a `Comparison`, and `met` as a boolean, each when defined.
125
138
  * Unknown members, prototypes, and class instances are admitted. Arrays are
126
139
  * refused. `expected` and `actual` are `unknown`, so this guard does not read or
127
- * check them; either member may also be absent because `objectOf` reads declared
128
- * members rather than requiring or enumerating own keys.
140
+ * check them and a borrowed result is never narrowed on them; either member may
141
+ * also be absent because `objectOf` reads declared members rather than
142
+ * requiring or enumerating own keys.
129
143
  *
130
144
  * @param value - The value to test
131
145
  * @returns True if every checked `Evidence` member conforms; false otherwise
@@ -154,8 +168,11 @@ function isEvidence(value) {
154
168
  * Determines whether a value is an open {@link WorksheetFactor} result object.
155
169
  *
156
170
  * @remarks
157
- * Unknown members, prototypes, and class instances are admitted. Arrays are
158
- * refused. Optional members may be absent or read as `undefined`.
171
+ * `id`, the optional authored text, `applied`, an optional plain-number
172
+ * `value`, and each `Evidence` entry are checked. Unknown members, prototypes,
173
+ * and class instances are admitted and left unchecked, because a borrowed
174
+ * result implementation may add them. Arrays are refused. Optional members may
175
+ * be absent or read as `undefined`.
159
176
  *
160
177
  * @param value - The value to test
161
178
  * @returns True if every published worksheet-factor member conforms; false otherwise
@@ -185,8 +202,11 @@ function isWorksheetFactor(value) {
185
202
  * Determines whether a value is an open {@link WorksheetGroup} result object.
186
203
  *
187
204
  * @remarks
188
- * Unknown members, prototypes, and class instances are admitted. Arrays are
189
- * refused. Optional members may be absent or read as `undefined`.
205
+ * `id`, the optional authored text, `applied`, a plain-number `value`, and each
206
+ * `WorksheetFactor` entry are checked. Unknown members, prototypes, and class
207
+ * instances are admitted and left unchecked, because a borrowed result
208
+ * implementation may add them. Arrays are refused. Optional members may be
209
+ * absent or read as `undefined`.
190
210
  *
191
211
  * @param value - The value to test
192
212
  * @returns True if every published worksheet-group member conforms; false otherwise
@@ -212,8 +232,11 @@ function isWorksheetGroup(value) {
212
232
  * Determines whether a value is an open {@link Step} result object.
213
233
  *
214
234
  * @remarks
215
- * Unknown members, prototypes, and class instances are admitted. Arrays are
216
- * refused. Optional members may be absent or read as `undefined`.
235
+ * `stage` is checked through `isStage`, `id`, `name`, and `expression` when
236
+ * defined, and `value` as a plain number. Unknown members, prototypes, and
237
+ * class instances are admitted and left unchecked, because a borrowed result
238
+ * implementation may add them. Arrays are refused. Optional members may be
239
+ * absent or read as `undefined`.
217
240
  *
218
241
  * @param value - The value to test
219
242
  * @returns True if every published worksheet-step member conforms; false otherwise
@@ -242,8 +265,12 @@ function isStep(value) {
242
265
  * Determines whether a value is an open {@link Worksheet} result object.
243
266
  *
244
267
  * @remarks
245
- * Unknown members, prototypes, and class instances are admitted. Arrays are
246
- * refused. Optional members may be absent or read as `undefined`.
268
+ * Identity, `aggregation` through reason's `isAggregation`, an optional
269
+ * plain-number `precision`, a plain-number `value`, the nested groups and steps,
270
+ * `trace`, `errors`, and `success` are checked. Unknown members, prototypes, and
271
+ * class instances are admitted and left unchecked, because a borrowed result
272
+ * implementation may add them. Arrays are refused. Optional members may be
273
+ * absent or read as `undefined`.
247
274
  *
248
275
  * @param value - The value to test
249
276
  * @returns True if every published worksheet member conforms; false otherwise
@@ -273,10 +300,14 @@ function isWorksheet(value) {
273
300
  * Determines whether a value is an open {@link LineResult} object.
274
301
  *
275
302
  * @remarks
276
- * Unknown members, prototypes, and class instances are admitted. Arrays are
277
- * refused. `amount` may be absent or read as `undefined`; when present it stays
278
- * a plain JavaScript `number` without a finite or range refinement. The line's
279
- * outcome lives on `worksheet`, so `worksheet.success` carries it.
303
+ * Identity, an optional plain-number `amount`, and the nested `Worksheet` that
304
+ * carries the line's outcome are checked. Unknown members, prototypes, and
305
+ * class instances are admitted and left unchecked, because a borrowed result
306
+ * implementation may add them, and so is the relationship between `amount` and
307
+ * `worksheet.success`, which the published interface types independently.
308
+ * Arrays are refused. `amount` may be absent or read as `undefined`; when
309
+ * present it stays a plain JavaScript `number` without a finite or range
310
+ * refinement.
280
311
  *
281
312
  * @param value - The value to test
282
313
  * @returns True if every published line-result member conforms; false otherwise
@@ -300,10 +331,13 @@ function isLineResult(value) {
300
331
  * Determines whether a value is an open {@link RatingResult} object.
301
332
  *
302
333
  * @remarks
303
- * Use this guard for a result returned by a borrowed `RaterInterface`. Unknown
304
- * members, prototypes, and class instances are admitted. Arrays are refused.
305
- * `total` may be absent or read as `undefined`; when present it stays a plain
306
- * JavaScript `number` without a finite or range refinement.
334
+ * Use this guard for a result returned by a borrowed `RaterInterface`. Every
335
+ * nested `LineResult`, an optional plain-number `total`, and a boolean `success`
336
+ * are checked. Unknown members, prototypes, and class instances are admitted and
337
+ * left unchecked, and so are the relationships among totals, lines, and success,
338
+ * because the borrowed interface publishes only their member types. Arrays are
339
+ * refused. `total` may be absent or read as `undefined`; when present it stays a
340
+ * plain JavaScript `number` without a finite or range refinement.
307
341
  *
308
342
  * @param value - The value to test
309
343
  * @returns True if every published rating-result member conforms; false otherwise
@@ -325,7 +359,9 @@ function isRatingResult(value) {
325
359
  //#endregion
326
360
  //#region src/core/helpers.ts
327
361
  /**
328
- * Builds a {@link LineDefinition}.
362
+ * Builds a fresh {@link LineDefinition} from a line id, a display name, and the
363
+ * line's quantitative rating definition, with `overrides` merged over those
364
+ * defaults.
329
365
  *
330
366
  * @param id - The line id
331
367
  * @param name - The display name
@@ -350,7 +386,8 @@ function buildLineDefinition(id, name, rate, overrides) {
350
386
  };
351
387
  }
352
388
  /**
353
- * Builds a {@link RatingDefinition}.
389
+ * Builds a fresh {@link RatingDefinition} from a rating id, a display name, and
390
+ * the rating's ordered lines, with `overrides` merged over those defaults.
354
391
  *
355
392
  * @param id - The rating id
356
393
  * @param name - The display name
@@ -636,12 +673,12 @@ function sumAmounts(lines) {
636
673
  * reasoning engine and projects results into the rating domain vocabulary.
637
674
  *
638
675
  * @remarks
639
- * When no `engine` is injected, `Rater` builds and OWNS its own
640
- * quantitative-only engine (`bail: false`) — Rater performs NO evaluation
676
+ * When no `engine` is injected, `Rater` builds and owns its own
677
+ * quantitative-only engine (`bail: false`) — Rater performs no evaluation
641
678
  * arithmetic of its own; it only orchestrates and projects. The
642
- * array-of-lines `rate` overload is declared FIRST so a plain line list
643
- * resolves to that form. `destroy()` destroys an OWNED engine, then the
644
- * emitter LAST; an INJECTED engine is never destroyed. Afterwards every
679
+ * array-of-lines `rate` overload is declared first so a plain line list
680
+ * resolves to that form. `destroy()` destroys an owned engine, then the
681
+ * emitter last; an injected engine is never destroyed. Afterwards every
645
682
  * other method throws {@link RaterError} `'DESTROYED'`.
646
683
  *
647
684
  * @example
@@ -736,12 +773,13 @@ var Rater = class {
736
773
  //#endregion
737
774
  //#region src/core/factories.ts
738
775
  /**
739
- * Creates a rating orchestrator.
776
+ * Creates a rating orchestrator over the shared quantitative engine, seeded
777
+ * from {@link RaterOptions} and returning a {@link RaterInterface}.
740
778
  *
741
779
  * @param options - Optional total handler, labels, injected engine, and emitter hooks
742
780
  * @returns A {@link RaterInterface}
743
781
  *
744
- * @example
782
+ * @example Create a rater
745
783
  * ```ts
746
784
  * import { createRater } from '@orkestrel/rater'
747
785
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["#emitter","#engine","#owned","#total","#labels","#ensureAlive","#normalize","#rateLine","#destroyed","#reasonQuantitative"],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Rater.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { RaterErrorCode } from './types.js'\n\n/**\n * Represents a coded programmer error thrown by the rating layer.\n *\n * @remarks\n * `DEFINITION` — the `rate` input failed both the array-of-lines and rating\n * definition validation. `MISMATCH` — a rated subject is not a record.\n * `DESTROYED` — use of a destroyed entity.\n *\n * @example\n * ```ts\n * import { RaterError } from '@orkestrel/rater'\n *\n * throw new RaterError('MISMATCH', 'Subject must be a record')\n * ```\n */\nexport class RaterError extends Error {\n\treadonly code: RaterErrorCode\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(code: RaterErrorCode, message: string, context?: Readonly<Record<string, unknown>>) {\n\t\tsuper(message)\n\t\tthis.name = 'RaterError'\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Narrows a caught value to a {@link RaterError}.\n *\n * @param value - The caught value to test\n * @returns True if `value` is a `RaterError`; false otherwise\n *\n * @example\n * ```ts\n * import { isRaterError, RaterError } from '@orkestrel/rater'\n *\n * try {\n * \tthrow new RaterError('DESTROYED', 'Rater has been destroyed')\n * } catch (error) {\n * \tif (isRaterError(error)) error.code // 'DESTROYED'\n * }\n * ```\n */\nexport function isRaterError(value: unknown): value is RaterError {\n\treturn value instanceof RaterError\n}\n","import type { Guard } from '@orkestrel/contract'\nimport type {\n\tEvidence,\n\tLineDefinition,\n\tLineResult,\n\tRatingDefinition,\n\tRatingResult,\n\tStage,\n\tStep,\n\tWorksheet,\n\tWorksheetFactor,\n\tWorksheetGroup,\n} from './types.js'\nimport {\n\tarrayOf,\n\tisBoolean,\n\tisJSONValue,\n\tisNumber,\n\tisString,\n\tliteralOf,\n\tobjectOf,\n\trecordOf,\n} from '@orkestrel/contract'\nimport {\n\tisAggregation,\n\tisComparison,\n\tisFieldPath,\n\tisQuantitativeDefinition,\n} from '@orkestrel/reason'\n\n/**\n * Determines whether a value is a {@link Stage} literal.\n *\n * @param value - The value to test\n * @returns True if `value` is `'factor'`, `'group'`, or `'total'`; false otherwise\n *\n * @example\n * ```ts\n * import { isStage } from '@orkestrel/rater'\n *\n * isStage('group') // true\n * isStage('step') // false\n * ```\n */\nexport const isStage: Guard<Stage> = literalOf('factor', 'group', 'total')\n\n/**\n * Determines whether a value is an exact {@link LineDefinition} record.\n *\n * @remarks\n * Total guard: adversarial input (cycles, hostile prototypes) returns `false`,\n * never throws. The record shape is EXACT — an extra key fails.\n *\n * @param value - The value to test\n * @returns True if `value` is a `LineDefinition`; false otherwise\n *\n * @example\n * ```ts\n * import { createQuantitativeDefinition } from '@orkestrel/reason'\n * import { isLineDefinition } from '@orkestrel/rater'\n *\n * isLineDefinition({ id: 'base', name: 'Base', rate: createQuantitativeDefinition('base', 'Base', []) }) // true\n * ```\n */\nexport function isLineDefinition(value: unknown): value is LineDefinition {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\trate: isQuantitativeDefinition,\n\t\t\tmetadata: isJSONValue,\n\t\t},\n\t\t['description', 'metadata'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an exact {@link RatingDefinition} record.\n *\n * @remarks\n * Total guard: adversarial input (cycles, hostile prototypes) returns `false`,\n * never throws. The record shape is EXACT — an extra key fails.\n *\n * @param value - The value to test\n * @returns True if `value` is a `RatingDefinition`; false otherwise\n *\n * @example\n * ```ts\n * import { isRatingDefinition } from '@orkestrel/rater'\n *\n * isRatingDefinition({ id: 'r1', name: 'Rating', lines: [] }) // true\n * ```\n */\nexport function isRatingDefinition(value: unknown): value is RatingDefinition {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tlines: arrayOf(isLineDefinition),\n\t\t\tmetadata: isJSONValue,\n\t\t},\n\t\t['description', 'metadata'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open result-side {@link Evidence} object.\n *\n * @remarks\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. `expected` and `actual` are `unknown`, so this guard does not read or\n * check them; either member may also be absent because `objectOf` reads declared\n * members rather than requiring or enumerating own keys.\n *\n * @param value - The value to test\n * @returns True if every checked `Evidence` member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isEvidence } from '@orkestrel/rater'\n *\n * isEvidence({ field: 'age', comparison: 'above', expected: 18, actual: 25, met: true }) // true\n * ```\n */\nexport function isEvidence(value: unknown): value is Evidence {\n\treturn objectOf(\n\t\t{\n\t\t\tfield: isFieldPath,\n\t\t\tlabel: isString,\n\t\t\tcomparison: isComparison,\n\t\t\tmet: isBoolean,\n\t\t},\n\t\t['field', 'label', 'comparison', 'met'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link WorksheetFactor} result object.\n *\n * @remarks\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. Optional members may be absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet-factor member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isWorksheetFactor } from '@orkestrel/rater'\n *\n * isWorksheetFactor({ id: 'base', applied: true, value: 100, evidence: [] }) // true\n * ```\n */\nexport function isWorksheetFactor(value: unknown): value is WorksheetFactor {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tapplied: isBoolean,\n\t\t\tvalue: isNumber,\n\t\t\tevidence: arrayOf(isEvidence),\n\t\t},\n\t\t['name', 'description', 'value'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link WorksheetGroup} result object.\n *\n * @remarks\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. Optional members may be absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet-group member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isWorksheetGroup } from '@orkestrel/rater'\n *\n * isWorksheetGroup({ id: 'charges', applied: true, value: 100, factors: [] }) // true\n * ```\n */\nexport function isWorksheetGroup(value: unknown): value is WorksheetGroup {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tapplied: isBoolean,\n\t\t\tvalue: isNumber,\n\t\t\tfactors: arrayOf(isWorksheetFactor),\n\t\t},\n\t\t['name', 'description'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link Step} result object.\n *\n * @remarks\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. Optional members may be absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet-step member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isStep } from '@orkestrel/rater'\n *\n * isStep({ stage: 'total', value: 100 }) // true\n * ```\n */\nexport function isStep(value: unknown): value is Step {\n\treturn objectOf(\n\t\t{\n\t\t\tstage: isStage,\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tvalue: isNumber,\n\t\t\texpression: isString,\n\t\t},\n\t\t['id', 'name', 'expression'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link Worksheet} result object.\n *\n * @remarks\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. Optional members may be absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isWorksheet } from '@orkestrel/rater'\n *\n * isWorksheet({ id: 'quote', name: 'Quote', aggregation: 'sum', value: 0, groups: [], steps: [], trace: [], errors: [], success: true }) // true\n * ```\n */\nexport function isWorksheet(value: unknown): value is Worksheet {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\taggregation: isAggregation,\n\t\t\tprecision: isNumber,\n\t\t\tvalue: isNumber,\n\t\t\tgroups: arrayOf(isWorksheetGroup),\n\t\t\tsteps: arrayOf(isStep),\n\t\t\ttrace: arrayOf(isString),\n\t\t\terrors: arrayOf(isString),\n\t\t\tsuccess: isBoolean,\n\t\t},\n\t\t['precision'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link LineResult} object.\n *\n * @remarks\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. `amount` may be absent or read as `undefined`; when present it stays\n * a plain JavaScript `number` without a finite or range refinement. The line's\n * outcome lives on `worksheet`, so `worksheet.success` carries it.\n *\n * @param value - The value to test\n * @returns True if every published line-result member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isLineResult } from '@orkestrel/rater'\n *\n * isLineResult({ id: 'base', name: 'Base', worksheet: { id: 'base', name: 'Base', aggregation: 'sum', value: 0, groups: [], steps: [], trace: [], errors: [], success: false } }) // true\n * ```\n */\nexport function isLineResult(value: unknown): value is LineResult {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tamount: isNumber,\n\t\t\tworksheet: isWorksheet,\n\t\t},\n\t\t['amount'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link RatingResult} object.\n *\n * @remarks\n * Use this guard for a result returned by a borrowed `RaterInterface`. Unknown\n * members, prototypes, and class instances are admitted. Arrays are refused.\n * `total` may be absent or read as `undefined`; when present it stays a plain\n * JavaScript `number` without a finite or range refinement.\n *\n * @param value - The value to test\n * @returns True if every published rating-result member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isRatingResult } from '@orkestrel/rater'\n *\n * isRatingResult({ lines: [], success: true }) // true\n * ```\n */\nexport function isRatingResult(value: unknown): value is RatingResult {\n\treturn objectOf(\n\t\t{\n\t\t\tlines: arrayOf(isLineResult),\n\t\t\ttotal: isNumber,\n\t\t\tsuccess: isBoolean,\n\t\t},\n\t\t['total'],\n\t)(value)\n}\n","import type {\n\tCheck,\n\tCheckResult,\n\tFactor,\n\tFactorResult,\n\tGroupResult,\n\tQuantitativeDefinition,\n\tQuantitativeResult,\n} from '@orkestrel/reason'\nimport type {\n\tEvidence,\n\tLineDefinition,\n\tLineResult,\n\tRatingDefinition,\n\tStage,\n\tStep,\n\tWorksheet,\n\tWorksheetFactor,\n\tWorksheetGroup,\n} from './types.js'\nimport { formatField } from '@orkestrel/reason'\n\n/**\n * Builds a {@link LineDefinition}.\n *\n * @param id - The line id\n * @param name - The display name\n * @param rate - The line's quantitative rating definition\n * @param overrides - Optional {@link LineDefinition} fields merged over the defaults\n * @returns A fresh line definition\n *\n * @example\n * ```ts\n * import { createQuantitativeDefinition } from '@orkestrel/reason'\n * import { buildLineDefinition } from '@orkestrel/rater'\n *\n * buildLineDefinition('base', 'Base Amount', createQuantitativeDefinition('base', 'Base', []))\n * ```\n */\nexport function buildLineDefinition(\n\tid: string,\n\tname: string,\n\trate: QuantitativeDefinition,\n\toverrides?: Partial<Omit<LineDefinition, 'id' | 'name' | 'rate'>>,\n): LineDefinition {\n\treturn { id, name, rate, ...overrides }\n}\n\n/**\n * Builds a {@link RatingDefinition}.\n *\n * @param id - The rating id\n * @param name - The display name\n * @param lines - The rating's ordered lines\n * @param overrides - Optional {@link RatingDefinition} fields merged over the defaults\n * @returns A fresh rating definition\n *\n * @example\n * ```ts\n * import { buildLineDefinition, buildRatingDefinition } from '@orkestrel/rater'\n * import { createQuantitativeDefinition } from '@orkestrel/reason'\n *\n * buildRatingDefinition('r1', 'Rating', [\n * \tbuildLineDefinition('base', 'Base Amount', createQuantitativeDefinition('base', 'Base', [])),\n * ])\n * ```\n */\nexport function buildRatingDefinition(\n\tid: string,\n\tname: string,\n\tlines: readonly LineDefinition[],\n\toverrides?: Partial<Omit<RatingDefinition, 'id' | 'name' | 'lines'>>,\n): RatingDefinition {\n\treturn { id, name, lines, ...overrides }\n}\n\n/**\n * Builds an {@link Evidence} row from an evaluated {@link Check}.\n *\n * @param check - The authored check\n * @param actual - The resolved subject value\n * @param met - If `true`, the check was met; if `false`, it was not; absent when the check\n * was not yet evaluated\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh evidence row\n *\n * @example\n * ```ts\n * import { createCheck } from '@orkestrel/reason'\n * import { buildEvidence } from '@orkestrel/rater'\n *\n * const entry = createCheck('age', 'above', 18)\n * buildEvidence(entry, 25, true) // { field: 'age', comparison: 'above', expected: 18, actual: 25, met: true }\n * ```\n */\nexport function buildEvidence(\n\tcheck: Check,\n\tactual: unknown,\n\tmet: boolean | undefined,\n\tlabels?: Readonly<Record<string, string>>,\n): Evidence {\n\tconst field = formatField(check.field)\n\treturn {\n\t\tfield: check.field,\n\t\t...(labels?.[field] === undefined ? {} : { label: labels[field] }),\n\t\tcomparison: check.operator,\n\t\texpected: check.value,\n\t\tactual,\n\t\t...(met === undefined ? {} : { met }),\n\t}\n}\n\n/**\n * Builds one evidence row per authored check of a quantitative factor, joined\n * to that check's evaluated result.\n *\n * @param checks - The factor's authored checks\n * @param results - The corresponding {@link CheckResult}s, in the same order\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh list of evidence rows, one per authored check\n *\n * @example\n * ```ts\n * import { createCheck } from '@orkestrel/reason'\n * import { buildEvidenceRows } from '@orkestrel/rater'\n *\n * const checks = [createCheck('age', 'above', 18)]\n * buildEvidenceRows(checks, [{ field: 'age', met: true, actual: 25 }])\n * ```\n */\nexport function buildEvidenceRows(\n\tchecks: readonly Check[] | undefined,\n\tresults: readonly CheckResult[] | undefined,\n\tlabels?: Readonly<Record<string, string>>,\n): readonly Evidence[] {\n\treturn (checks ?? []).map((check, index) => {\n\t\tconst result = results?.[index]\n\t\treturn buildEvidence(check, result?.actual, result?.met, labels)\n\t})\n}\n\n/**\n * Joins one authored quantitative factor to its evaluated {@link FactorResult}.\n *\n * @param definition - The authored factor\n * @param results - The group's factor results\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh worksheet factor\n *\n * @example\n * ```ts\n * import { createFieldFactor } from '@orkestrel/reason'\n * import { buildWorksheetFactor } from '@orkestrel/rater'\n *\n * const factor = createFieldFactor('seats', 'seats')\n * buildWorksheetFactor(factor, [{ id: 'seats', applied: true, value: 10 }])\n * ```\n */\nexport function buildWorksheetFactor(\n\tdefinition: Factor,\n\tresults: readonly FactorResult[],\n\tlabels?: Readonly<Record<string, string>>,\n): WorksheetFactor {\n\tconst result = results.find((entry) => entry.id === definition.id)\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\t...(definition.description === undefined ? {} : { description: definition.description }),\n\t\tapplied: result?.applied ?? false,\n\t\t...(result?.value === undefined ? {} : { value: result.value }),\n\t\tevidence: buildEvidenceRows(definition.checks, result?.checks, labels),\n\t}\n}\n\n/**\n * Joins one authored quantitative group to its evaluated {@link GroupResult}.\n *\n * @param definition - The authored group\n * @param results - The definition's group results\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh worksheet group\n *\n * @example\n * ```ts\n * import { createFactorGroup, createStaticFactor } from '@orkestrel/reason'\n * import { buildWorksheetGroup } from '@orkestrel/rater'\n *\n * const group = createFactorGroup('charge', 'sum', [createStaticFactor('base', 100)])\n * buildWorksheetGroup(group, [{ id: 'charge', applied: true, value: 100, factors: [] }])\n * ```\n */\nexport function buildWorksheetGroup(\n\tdefinition: QuantitativeDefinition['groups'][number],\n\tresults: readonly GroupResult[],\n\tlabels?: Readonly<Record<string, string>>,\n): WorksheetGroup {\n\tconst result = results.find((entry) => entry.id === definition.id)\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\t...(definition.description === undefined ? {} : { description: definition.description }),\n\t\tapplied: result?.applied ?? false,\n\t\tvalue: result?.value ?? 0,\n\t\tfactors: definition.factors.map((factor) =>\n\t\t\tbuildWorksheetFactor(factor, result?.factors ?? [], labels),\n\t\t),\n\t}\n}\n\n/**\n * Builds one display-neutral {@link Step} row.\n *\n * @param stage - The step's stage\n * @param id - The stage's authored id, when it has one\n * @param name - The stage's authored name, when it has one\n * @param value - The stage's resolved value\n * @param expression - A display-neutral expression string\n * @returns A fresh step\n *\n * @example\n * ```ts\n * import { buildWorksheetStep } from '@orkestrel/rater'\n *\n * buildWorksheetStep('total', 'quote', 'Quote', 110, 'sum = 110')\n * // { stage: 'total', id: 'quote', name: 'Quote', value: 110, expression: 'sum = 110' }\n * ```\n */\nexport function buildWorksheetStep(\n\tstage: Stage,\n\tid: string | undefined,\n\tname: string | undefined,\n\tvalue: number,\n\texpression: string,\n): Step {\n\treturn {\n\t\tstage,\n\t\t...(id === undefined ? {} : { id }),\n\t\t...(name === undefined ? {} : { name }),\n\t\tvalue,\n\t\texpression,\n\t}\n}\n\n/**\n * Builds the ordered {@link Step} rows for a resolved {@link Worksheet}.\n *\n * @param definition - The authored quantitative definition\n * @param result - The evaluated quantitative result\n * @param groups - The definition's already-joined worksheet groups\n * @returns A fresh, ordered list of steps: applied factors, then groups, then the total\n *\n * @example\n * ```ts\n * import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'\n * import { buildWorksheetGroup, buildWorksheetSteps } from '@orkestrel/rater'\n *\n * const definition = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, definition)\n * if (result.reasoning === 'quantitative') {\n * \tbuildWorksheetSteps(definition, result, definition.groups.map((group) => buildWorksheetGroup(group, result.groups)))\n * }\n * ```\n */\nexport function buildWorksheetSteps(\n\tdefinition: QuantitativeDefinition,\n\tresult: QuantitativeResult,\n\tgroups: readonly WorksheetGroup[],\n): readonly Step[] {\n\tconst output: Step[] = []\n\tfor (const group of groups) {\n\t\tfor (const factor of group.factors) {\n\t\t\tif (factor.applied && factor.value !== undefined) {\n\t\t\t\toutput.push(\n\t\t\t\t\tbuildWorksheetStep(\n\t\t\t\t\t\t'factor',\n\t\t\t\t\t\tfactor.id,\n\t\t\t\t\t\tfactor.name,\n\t\t\t\t\t\tfactor.value,\n\t\t\t\t\t\t`${factor.id} = ${factor.value}`,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\toutput.push(\n\t\t\tbuildWorksheetStep(\n\t\t\t\t'group',\n\t\t\t\tgroup.id,\n\t\t\t\tgroup.name,\n\t\t\t\tgroup.value,\n\t\t\t\t`${group.id} = ${group.value}`,\n\t\t\t),\n\t\t)\n\t}\n\toutput.push(\n\t\tbuildWorksheetStep(\n\t\t\t'total',\n\t\t\tdefinition.id,\n\t\t\tdefinition.name,\n\t\t\tresult.value,\n\t\t\t`${definition.aggregation} = ${result.value}`,\n\t\t),\n\t)\n\treturn output\n}\n\n/**\n * Joins a {@link QuantitativeDefinition} and its {@link QuantitativeResult} into\n * a {@link Worksheet} — the rating audit trail.\n *\n * @param definition - The authored quantitative definition\n * @param result - The evaluated quantitative result\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh worksheet\n *\n * @example\n * ```ts\n * import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'\n * import { buildWorksheet } from '@orkestrel/rater'\n *\n * const definition = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, definition)\n * if (result.reasoning === 'quantitative') buildWorksheet(definition, result) // the full audit trail\n * ```\n */\nexport function buildWorksheet(\n\tdefinition: QuantitativeDefinition,\n\tresult: QuantitativeResult,\n\tlabels?: Readonly<Record<string, string>>,\n): Worksheet {\n\tconst groups = definition.groups.map((group) => buildWorksheetGroup(group, result.groups, labels))\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\taggregation: definition.aggregation,\n\t\t...(definition.precision === undefined ? {} : { precision: definition.precision }),\n\t\tvalue: result.value,\n\t\tgroups,\n\t\tsteps: buildWorksheetSteps(definition, result, groups),\n\t\ttrace: result.trace,\n\t\terrors: result.errors,\n\t\tsuccess: result.success,\n\t}\n}\n\n/**\n * Builds a rated {@link LineResult} from a line's evaluated\n * {@link QuantitativeResult}.\n *\n * @param definition - The authored line definition\n * @param result - The evaluated quantitative result\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh line result\n *\n * @example\n * ```ts\n * import { createQuantitativeDefinition, createQuantitativeReasoner, createReason } from '@orkestrel/reason'\n * import { buildLineDefinition, buildLineResult } from '@orkestrel/rater'\n *\n * const line = buildLineDefinition('base', 'Base', createQuantitativeDefinition('base', 'Base', []))\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, line.rate)\n * if (result.reasoning === 'quantitative') buildLineResult(line, result) // amount present only on a successful worksheet\n * ```\n */\nexport function buildLineResult(\n\tdefinition: LineDefinition,\n\tresult: QuantitativeResult,\n\tlabels?: Readonly<Record<string, string>>,\n): LineResult {\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\t...(result.success ? { amount: result.value } : {}),\n\t\tworksheet: buildWorksheet(definition.rate, result, labels),\n\t}\n}\n\n/**\n * Sums defined line amounts.\n *\n * @param lines - The rated lines\n * @returns The sum of every line's `amount`, or `undefined` when no line has one\n *\n * @example\n * ```ts\n * import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'\n * import { buildLineDefinition, buildLineResult, sumAmounts } from '@orkestrel/rater'\n *\n * const rate = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])\n * const line = buildLineDefinition('base', 'Base', rate)\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, rate)\n * if (result.reasoning === 'quantitative') sumAmounts([buildLineResult(line, result)]) // 100\n * ```\n */\nexport function sumAmounts(lines: readonly LineResult[]): number | undefined {\n\tlet total = 0\n\tlet count = 0\n\tfor (const rated of lines) {\n\t\tif (rated.amount !== undefined) {\n\t\t\ttotal += rated.amount\n\t\t\tcount += 1\n\t\t}\n\t}\n\treturn count === 0 ? undefined : total\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tQuantitativeDefinition,\n\tQuantitativeResult,\n\tReasonInterface,\n\tSubject,\n} from '@orkestrel/reason'\nimport type {\n\tLineDefinition,\n\tLineResult,\n\tRaterEventMap,\n\tRaterInterface,\n\tRaterOptions,\n\tRatingDefinition,\n\tRatingResult,\n\tTotalHandler,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { arrayOf, isArray, isRecord } from '@orkestrel/contract'\nimport { buildErrorResult, createQuantitativeReasoner, createReason } from '@orkestrel/reason'\nimport { RaterError } from './errors.js'\nimport { buildLineResult, sumAmounts } from './helpers.js'\nimport { isLineDefinition, isRatingDefinition } from './validators.js'\n\n/**\n * Orchestrates rating — owns (or receives) the shared quantitative\n * reasoning engine and projects results into the rating domain vocabulary.\n *\n * @remarks\n * When no `engine` is injected, `Rater` builds and OWNS its own\n * quantitative-only engine (`bail: false`) — Rater performs NO evaluation\n * arithmetic of its own; it only orchestrates and projects. The\n * array-of-lines `rate` overload is declared FIRST so a plain line list\n * resolves to that form. `destroy()` destroys an OWNED engine, then the\n * emitter LAST; an INJECTED engine is never destroyed. Afterwards every\n * other method throws {@link RaterError} `'DESTROYED'`.\n *\n * @example\n * ```ts\n * import { Rater } from '@orkestrel/rater'\n *\n * const rater = new Rater()\n * rater.rate([], { id: 'subject-1' }) // { lines: [], success: true }\n * rater.destroy()\n * ```\n */\nexport class Rater implements RaterInterface {\n\treadonly #emitter: Emitter<RaterEventMap>\n\treadonly #engine: ReasonInterface\n\treadonly #owned: boolean\n\treadonly #total: TotalHandler | undefined\n\treadonly #labels: Readonly<Record<string, string>> | undefined\n\t#destroyed = false\n\n\tconstructor(options?: RaterOptions) {\n\t\tthis.#emitter = new Emitter<RaterEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t\tif (options?.engine === undefined) {\n\t\t\tthis.#engine = createReason({ reasoners: [createQuantitativeReasoner()], bail: false })\n\t\t\tthis.#owned = true\n\t\t} else {\n\t\t\tthis.#engine = options.engine\n\t\t\tthis.#owned = false\n\t\t}\n\t\tthis.#total = options?.total\n\t\tthis.#labels = options?.labels\n\t}\n\n\tget emitter(): EmitterInterface<RaterEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t// Array overload first so a plain line list resolves to that form.\n\trate(lines: readonly LineDefinition[], subject: Subject): RatingResult\n\trate(definition: RatingDefinition, subject: Subject): RatingResult\n\trate(input: readonly LineDefinition[] | RatingDefinition, subject: Subject): RatingResult {\n\t\tthis.#ensureAlive()\n\t\tconst lines = this.#normalize(input)\n\t\tif (!isRecord(subject)) throw new RaterError('MISMATCH', 'Subject must be a record')\n\t\tconst results = lines.map((line) => this.#rateLine(line, subject))\n\t\tconst total = (this.#total ?? sumAmounts)(results)\n\t\tconst success = results.every((entry) => entry.worksheet.success)\n\t\tconst result: RatingResult = {\n\t\t\tlines: results,\n\t\t\t...(total === undefined ? {} : { total }),\n\t\t\tsuccess,\n\t\t}\n\t\tthis.#emitter.emit('rate', subject, result)\n\t\treturn result\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tif (this.#owned) this.#engine.destroy()\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#normalize(input: readonly LineDefinition[] | RatingDefinition): readonly LineDefinition[] {\n\t\tif (arrayOf(isLineDefinition)(input)) return input\n\t\tif (isRatingDefinition(input)) return input.lines\n\t\tthrow new RaterError(\n\t\t\t'DEFINITION',\n\t\t\t'Rating input must be an array of line definitions or a rating definition',\n\t\t)\n\t}\n\n\t#rateLine(line: LineDefinition, subject: Subject): LineResult {\n\t\tconst result = this.#reasonQuantitative(subject, line.rate)\n\t\treturn buildLineResult(line, result, this.#labels)\n\t}\n\n\t// Narrows the engine's tagged ReasonResult union down to a QuantitativeResult\n\t// for a definition the engine is guaranteed (by dispatch-by-reasoning, given\n\t// only the quantitative reasoner is ever registered) to resolve as such — a\n\t// defensive, total fallback rather than an assertion. A nonconforming\n\t// injected engine result missing (or with a non-array) `errors` contributes\n\t// no errors from that side rather than throwing.\n\t#reasonQuantitative(subject: Subject, definition: QuantitativeDefinition): QuantitativeResult {\n\t\tconst result = this.#engine.reason(subject, definition)\n\t\tif (result.reasoning === 'quantitative') return result\n\t\tconst failure = buildErrorResult(\n\t\t\tdefinition,\n\t\t\t`Expected quantitative result, got ${result.reasoning}`,\n\t\t)\n\t\tconst errors = [...(isArray<string>(result.errors) ? result.errors : []), ...failure.errors]\n\t\tif (failure.reasoning === 'quantitative') return { ...failure, errors }\n\t\treturn {\n\t\t\treasoning: 'quantitative',\n\t\t\tvalue: 0,\n\t\t\tgroups: [],\n\t\t\tcount: 0,\n\t\t\tsuccess: false,\n\t\t\ttrace: [],\n\t\t\terrors,\n\t\t}\n\t}\n\n\t#ensureAlive(): void {\n\t\tif (this.#destroyed) throw new RaterError('DESTROYED', 'Rater has been destroyed')\n\t}\n}\n","import type { RaterInterface, RaterOptions } from './types.js'\nimport { Rater } from './Rater.js'\n\n/**\n * Creates a rating orchestrator.\n *\n * @param options - Optional total handler, labels, injected engine, and emitter hooks\n * @returns A {@link RaterInterface}\n *\n * @example\n * ```ts\n * import { createRater } from '@orkestrel/rater'\n *\n * const rater = createRater()\n * rater.destroy()\n * ```\n */\nexport function createRater(options?: RaterOptions): RaterInterface {\n\treturn new Rater(options)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Rater.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { RaterErrorCode } from './types.js'\nimport { isInstance } from '@orkestrel/contract'\n\n/**\n * Represents a coded programmer error thrown by the rating layer.\n *\n * @remarks\n * `DEFINITION` — the `rate` input failed both the array-of-lines and rating\n * definition validation. `MISMATCH` — a rated subject is not a record.\n * `DESTROYED` — use of a destroyed entity. `context` carries optional\n * structured detail beside the message.\n *\n * @example\n * ```ts\n * import { RaterError } from '@orkestrel/rater'\n *\n * throw new RaterError('MISMATCH', 'Subject must be a record')\n * ```\n */\nexport class RaterError extends Error {\n\treadonly code: RaterErrorCode\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(code: RaterErrorCode, message: string, context?: Readonly<Record<string, unknown>>) {\n\t\tsuper(message)\n\t\tthis.name = 'RaterError'\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Narrows a caught value to a {@link RaterError}.\n *\n * @param value - The caught value to test\n * @returns True if `value` is a `RaterError`; false otherwise\n *\n * @example\n * ```ts\n * import { isRaterError, RaterError } from '@orkestrel/rater'\n *\n * try {\n * \tthrow new RaterError('DESTROYED', 'Rater has been destroyed')\n * } catch (error) {\n * \tif (isRaterError(error)) error.code // 'DESTROYED'\n * }\n * ```\n */\nexport function isRaterError(value: unknown): value is RaterError {\n\treturn isInstance(value, RaterError)\n}\n","import type { Guard } from '@orkestrel/contract'\nimport type {\n\tEvidence,\n\tLineDefinition,\n\tLineResult,\n\tRatingDefinition,\n\tRatingResult,\n\tStage,\n\tStep,\n\tWorksheet,\n\tWorksheetFactor,\n\tWorksheetGroup,\n} from './types.js'\nimport {\n\tarrayOf,\n\tisBoolean,\n\tisJSONValue,\n\tisNumber,\n\tisString,\n\tliteralOf,\n\tobjectOf,\n\trecordOf,\n} from '@orkestrel/contract'\nimport {\n\tisAggregation,\n\tisComparison,\n\tisFieldPath,\n\tisQuantitativeDefinition,\n} from '@orkestrel/reason'\n\n/**\n * Determines whether a value is a {@link Stage} literal.\n *\n * @remarks\n * A scalar union has no open or exact axis, so this guard accepts one of the\n * `Stage` literals and leaves nothing unchecked.\n *\n * @param value - The value to test\n * @returns True if `value` is `'factor'`, `'group'`, or `'total'`; false otherwise\n *\n * @example\n * ```ts\n * import { isStage } from '@orkestrel/rater'\n *\n * isStage('group') // true\n * isStage('step') // false\n * ```\n */\nexport const isStage: Guard<Stage> = literalOf('factor', 'group', 'total')\n\n/**\n * Determines whether a value is an exact {@link LineDefinition} record.\n *\n * @remarks\n * Every `LineDefinition` member is checked, including its quantitative\n * definition. Total guard: adversarial input (cycles, hostile prototypes)\n * returns `false`, never throws. The record shape is exact — this package owns\n * the authored input record, so an extra key fails and nothing is left\n * unchecked.\n *\n * @param value - The value to test\n * @returns True if `value` is a `LineDefinition`; false otherwise\n *\n * @example\n * ```ts\n * import { createQuantitativeDefinition } from '@orkestrel/reason'\n * import { isLineDefinition } from '@orkestrel/rater'\n *\n * isLineDefinition({ id: 'base', name: 'Base', rate: createQuantitativeDefinition('base', 'Base', []) }) // true\n * ```\n */\nexport function isLineDefinition(value: unknown): value is LineDefinition {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\trate: isQuantitativeDefinition,\n\t\t\tmetadata: isJSONValue,\n\t\t},\n\t\t['description', 'metadata'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an exact {@link RatingDefinition} record.\n *\n * @remarks\n * Every `RatingDefinition` member is checked, including each nested line\n * definition. Total guard: adversarial input (cycles, hostile prototypes)\n * returns `false`, never throws. The record shape is exact — this package owns\n * the authored input record, so an extra key fails and nothing is left\n * unchecked.\n *\n * @param value - The value to test\n * @returns True if `value` is a `RatingDefinition`; false otherwise\n *\n * @example\n * ```ts\n * import { isRatingDefinition } from '@orkestrel/rater'\n *\n * isRatingDefinition({ id: 'r1', name: 'Rating', lines: [] }) // true\n * ```\n */\nexport function isRatingDefinition(value: unknown): value is RatingDefinition {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tlines: arrayOf(isLineDefinition),\n\t\t\tmetadata: isJSONValue,\n\t\t},\n\t\t['description', 'metadata'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open result-side {@link Evidence} object.\n *\n * @remarks\n * Optional `field` is checked as a `FieldPath`, `label` as a string,\n * `comparison` as a `Comparison`, and `met` as a boolean, each when defined.\n * Unknown members, prototypes, and class instances are admitted. Arrays are\n * refused. `expected` and `actual` are `unknown`, so this guard does not read or\n * check them and a borrowed result is never narrowed on them; either member may\n * also be absent because `objectOf` reads declared members rather than\n * requiring or enumerating own keys.\n *\n * @param value - The value to test\n * @returns True if every checked `Evidence` member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isEvidence } from '@orkestrel/rater'\n *\n * isEvidence({ field: 'age', comparison: 'above', expected: 18, actual: 25, met: true }) // true\n * ```\n */\nexport function isEvidence(value: unknown): value is Evidence {\n\treturn objectOf(\n\t\t{\n\t\t\tfield: isFieldPath,\n\t\t\tlabel: isString,\n\t\t\tcomparison: isComparison,\n\t\t\tmet: isBoolean,\n\t\t},\n\t\t['field', 'label', 'comparison', 'met'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link WorksheetFactor} result object.\n *\n * @remarks\n * `id`, the optional authored text, `applied`, an optional plain-number\n * `value`, and each `Evidence` entry are checked. Unknown members, prototypes,\n * and class instances are admitted and left unchecked, because a borrowed\n * result implementation may add them. Arrays are refused. Optional members may\n * be absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet-factor member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isWorksheetFactor } from '@orkestrel/rater'\n *\n * isWorksheetFactor({ id: 'base', applied: true, value: 100, evidence: [] }) // true\n * ```\n */\nexport function isWorksheetFactor(value: unknown): value is WorksheetFactor {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tapplied: isBoolean,\n\t\t\tvalue: isNumber,\n\t\t\tevidence: arrayOf(isEvidence),\n\t\t},\n\t\t['name', 'description', 'value'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link WorksheetGroup} result object.\n *\n * @remarks\n * `id`, the optional authored text, `applied`, a plain-number `value`, and each\n * `WorksheetFactor` entry are checked. Unknown members, prototypes, and class\n * instances are admitted and left unchecked, because a borrowed result\n * implementation may add them. Arrays are refused. Optional members may be\n * absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet-group member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isWorksheetGroup } from '@orkestrel/rater'\n *\n * isWorksheetGroup({ id: 'charges', applied: true, value: 100, factors: [] }) // true\n * ```\n */\nexport function isWorksheetGroup(value: unknown): value is WorksheetGroup {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tapplied: isBoolean,\n\t\t\tvalue: isNumber,\n\t\t\tfactors: arrayOf(isWorksheetFactor),\n\t\t},\n\t\t['name', 'description'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link Step} result object.\n *\n * @remarks\n * `stage` is checked through `isStage`, `id`, `name`, and `expression` when\n * defined, and `value` as a plain number. Unknown members, prototypes, and\n * class instances are admitted and left unchecked, because a borrowed result\n * implementation may add them. Arrays are refused. Optional members may be\n * absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet-step member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isStep } from '@orkestrel/rater'\n *\n * isStep({ stage: 'total', value: 100 }) // true\n * ```\n */\nexport function isStep(value: unknown): value is Step {\n\treturn objectOf(\n\t\t{\n\t\t\tstage: isStage,\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tvalue: isNumber,\n\t\t\texpression: isString,\n\t\t},\n\t\t['id', 'name', 'expression'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link Worksheet} result object.\n *\n * @remarks\n * Identity, `aggregation` through reason's `isAggregation`, an optional\n * plain-number `precision`, a plain-number `value`, the nested groups and steps,\n * `trace`, `errors`, and `success` are checked. Unknown members, prototypes, and\n * class instances are admitted and left unchecked, because a borrowed result\n * implementation may add them. Arrays are refused. Optional members may be\n * absent or read as `undefined`.\n *\n * @param value - The value to test\n * @returns True if every published worksheet member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isWorksheet } from '@orkestrel/rater'\n *\n * isWorksheet({ id: 'quote', name: 'Quote', aggregation: 'sum', value: 0, groups: [], steps: [], trace: [], errors: [], success: true }) // true\n * ```\n */\nexport function isWorksheet(value: unknown): value is Worksheet {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\taggregation: isAggregation,\n\t\t\tprecision: isNumber,\n\t\t\tvalue: isNumber,\n\t\t\tgroups: arrayOf(isWorksheetGroup),\n\t\t\tsteps: arrayOf(isStep),\n\t\t\ttrace: arrayOf(isString),\n\t\t\terrors: arrayOf(isString),\n\t\t\tsuccess: isBoolean,\n\t\t},\n\t\t['precision'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link LineResult} object.\n *\n * @remarks\n * Identity, an optional plain-number `amount`, and the nested `Worksheet` that\n * carries the line's outcome are checked. Unknown members, prototypes, and\n * class instances are admitted and left unchecked, because a borrowed result\n * implementation may add them, and so is the relationship between `amount` and\n * `worksheet.success`, which the published interface types independently.\n * Arrays are refused. `amount` may be absent or read as `undefined`; when\n * present it stays a plain JavaScript `number` without a finite or range\n * refinement.\n *\n * @param value - The value to test\n * @returns True if every published line-result member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isLineResult } from '@orkestrel/rater'\n *\n * isLineResult({ id: 'base', name: 'Base', worksheet: { id: 'base', name: 'Base', aggregation: 'sum', value: 0, groups: [], steps: [], trace: [], errors: [], success: false } }) // true\n * ```\n */\nexport function isLineResult(value: unknown): value is LineResult {\n\treturn objectOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tamount: isNumber,\n\t\t\tworksheet: isWorksheet,\n\t\t},\n\t\t['amount'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link RatingResult} object.\n *\n * @remarks\n * Use this guard for a result returned by a borrowed `RaterInterface`. Every\n * nested `LineResult`, an optional plain-number `total`, and a boolean `success`\n * are checked. Unknown members, prototypes, and class instances are admitted and\n * left unchecked, and so are the relationships among totals, lines, and success,\n * because the borrowed interface publishes only their member types. Arrays are\n * refused. `total` may be absent or read as `undefined`; when present it stays a\n * plain JavaScript `number` without a finite or range refinement.\n *\n * @param value - The value to test\n * @returns True if every published rating-result member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isRatingResult } from '@orkestrel/rater'\n *\n * isRatingResult({ lines: [], success: true }) // true\n * ```\n */\nexport function isRatingResult(value: unknown): value is RatingResult {\n\treturn objectOf(\n\t\t{\n\t\t\tlines: arrayOf(isLineResult),\n\t\t\ttotal: isNumber,\n\t\t\tsuccess: isBoolean,\n\t\t},\n\t\t['total'],\n\t)(value)\n}\n","import type {\n\tCheck,\n\tCheckResult,\n\tFactor,\n\tFactorResult,\n\tGroupResult,\n\tQuantitativeDefinition,\n\tQuantitativeResult,\n} from '@orkestrel/reason'\nimport type {\n\tEvidence,\n\tLineDefinition,\n\tLineResult,\n\tRatingDefinition,\n\tStage,\n\tStep,\n\tWorksheet,\n\tWorksheetFactor,\n\tWorksheetGroup,\n} from './types.js'\nimport { formatField } from '@orkestrel/reason'\n\n/**\n * Builds a fresh {@link LineDefinition} from a line id, a display name, and the\n * line's quantitative rating definition, with `overrides` merged over those\n * defaults.\n *\n * @param id - The line id\n * @param name - The display name\n * @param rate - The line's quantitative rating definition\n * @param overrides - Optional {@link LineDefinition} fields merged over the defaults\n * @returns A fresh line definition\n *\n * @example\n * ```ts\n * import { createQuantitativeDefinition } from '@orkestrel/reason'\n * import { buildLineDefinition } from '@orkestrel/rater'\n *\n * buildLineDefinition('base', 'Base Amount', createQuantitativeDefinition('base', 'Base', []))\n * ```\n */\nexport function buildLineDefinition(\n\tid: string,\n\tname: string,\n\trate: QuantitativeDefinition,\n\toverrides?: Partial<Omit<LineDefinition, 'id' | 'name' | 'rate'>>,\n): LineDefinition {\n\treturn { id, name, rate, ...overrides }\n}\n\n/**\n * Builds a fresh {@link RatingDefinition} from a rating id, a display name, and\n * the rating's ordered lines, with `overrides` merged over those defaults.\n *\n * @param id - The rating id\n * @param name - The display name\n * @param lines - The rating's ordered lines\n * @param overrides - Optional {@link RatingDefinition} fields merged over the defaults\n * @returns A fresh rating definition\n *\n * @example\n * ```ts\n * import { buildLineDefinition, buildRatingDefinition } from '@orkestrel/rater'\n * import { createQuantitativeDefinition } from '@orkestrel/reason'\n *\n * buildRatingDefinition('r1', 'Rating', [\n * \tbuildLineDefinition('base', 'Base Amount', createQuantitativeDefinition('base', 'Base', [])),\n * ])\n * ```\n */\nexport function buildRatingDefinition(\n\tid: string,\n\tname: string,\n\tlines: readonly LineDefinition[],\n\toverrides?: Partial<Omit<RatingDefinition, 'id' | 'name' | 'lines'>>,\n): RatingDefinition {\n\treturn { id, name, lines, ...overrides }\n}\n\n/**\n * Builds an {@link Evidence} row from an evaluated {@link Check}.\n *\n * @param check - The authored check\n * @param actual - The resolved subject value\n * @param met - If `true`, the check was met; if `false`, it was not; absent when the check\n * was not yet evaluated\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh evidence row\n *\n * @example\n * ```ts\n * import { createCheck } from '@orkestrel/reason'\n * import { buildEvidence } from '@orkestrel/rater'\n *\n * const entry = createCheck('age', 'above', 18)\n * buildEvidence(entry, 25, true) // { field: 'age', comparison: 'above', expected: 18, actual: 25, met: true }\n * ```\n */\nexport function buildEvidence(\n\tcheck: Check,\n\tactual: unknown,\n\tmet: boolean | undefined,\n\tlabels?: Readonly<Record<string, string>>,\n): Evidence {\n\tconst field = formatField(check.field)\n\treturn {\n\t\tfield: check.field,\n\t\t...(labels?.[field] === undefined ? {} : { label: labels[field] }),\n\t\tcomparison: check.operator,\n\t\texpected: check.value,\n\t\tactual,\n\t\t...(met === undefined ? {} : { met }),\n\t}\n}\n\n/**\n * Builds one evidence row per authored check of a quantitative factor, joined\n * to that check's evaluated result.\n *\n * @param checks - The factor's authored checks\n * @param results - The corresponding {@link CheckResult}s, in the same order\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh list of evidence rows, one per authored check\n *\n * @example\n * ```ts\n * import { createCheck } from '@orkestrel/reason'\n * import { buildEvidenceRows } from '@orkestrel/rater'\n *\n * const checks = [createCheck('age', 'above', 18)]\n * buildEvidenceRows(checks, [{ field: 'age', met: true, actual: 25 }])\n * ```\n */\nexport function buildEvidenceRows(\n\tchecks: readonly Check[] | undefined,\n\tresults: readonly CheckResult[] | undefined,\n\tlabels?: Readonly<Record<string, string>>,\n): readonly Evidence[] {\n\treturn (checks ?? []).map((check, index) => {\n\t\tconst result = results?.[index]\n\t\treturn buildEvidence(check, result?.actual, result?.met, labels)\n\t})\n}\n\n/**\n * Joins one authored quantitative factor to its evaluated {@link FactorResult}.\n *\n * @param definition - The authored factor\n * @param results - The group's factor results\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh worksheet factor\n *\n * @example\n * ```ts\n * import { createFieldFactor } from '@orkestrel/reason'\n * import { buildWorksheetFactor } from '@orkestrel/rater'\n *\n * const factor = createFieldFactor('seats', 'seats')\n * buildWorksheetFactor(factor, [{ id: 'seats', applied: true, value: 10 }])\n * ```\n */\nexport function buildWorksheetFactor(\n\tdefinition: Factor,\n\tresults: readonly FactorResult[],\n\tlabels?: Readonly<Record<string, string>>,\n): WorksheetFactor {\n\tconst result = results.find((entry) => entry.id === definition.id)\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\t...(definition.description === undefined ? {} : { description: definition.description }),\n\t\tapplied: result?.applied ?? false,\n\t\t...(result?.value === undefined ? {} : { value: result.value }),\n\t\tevidence: buildEvidenceRows(definition.checks, result?.checks, labels),\n\t}\n}\n\n/**\n * Joins one authored quantitative group to its evaluated {@link GroupResult}.\n *\n * @param definition - The authored group\n * @param results - The definition's group results\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh worksheet group\n *\n * @example\n * ```ts\n * import { createFactorGroup, createStaticFactor } from '@orkestrel/reason'\n * import { buildWorksheetGroup } from '@orkestrel/rater'\n *\n * const group = createFactorGroup('charge', 'sum', [createStaticFactor('base', 100)])\n * buildWorksheetGroup(group, [{ id: 'charge', applied: true, value: 100, factors: [] }])\n * ```\n */\nexport function buildWorksheetGroup(\n\tdefinition: QuantitativeDefinition['groups'][number],\n\tresults: readonly GroupResult[],\n\tlabels?: Readonly<Record<string, string>>,\n): WorksheetGroup {\n\tconst result = results.find((entry) => entry.id === definition.id)\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\t...(definition.description === undefined ? {} : { description: definition.description }),\n\t\tapplied: result?.applied ?? false,\n\t\tvalue: result?.value ?? 0,\n\t\tfactors: definition.factors.map((factor) =>\n\t\t\tbuildWorksheetFactor(factor, result?.factors ?? [], labels),\n\t\t),\n\t}\n}\n\n/**\n * Builds one display-neutral {@link Step} row.\n *\n * @param stage - The step's stage\n * @param id - The stage's authored id, when it has one\n * @param name - The stage's authored name, when it has one\n * @param value - The stage's resolved value\n * @param expression - A display-neutral expression string\n * @returns A fresh step\n *\n * @example\n * ```ts\n * import { buildWorksheetStep } from '@orkestrel/rater'\n *\n * buildWorksheetStep('total', 'quote', 'Quote', 110, 'sum = 110')\n * // { stage: 'total', id: 'quote', name: 'Quote', value: 110, expression: 'sum = 110' }\n * ```\n */\nexport function buildWorksheetStep(\n\tstage: Stage,\n\tid: string | undefined,\n\tname: string | undefined,\n\tvalue: number,\n\texpression: string,\n): Step {\n\treturn {\n\t\tstage,\n\t\t...(id === undefined ? {} : { id }),\n\t\t...(name === undefined ? {} : { name }),\n\t\tvalue,\n\t\texpression,\n\t}\n}\n\n/**\n * Builds the ordered {@link Step} rows for a resolved {@link Worksheet}.\n *\n * @param definition - The authored quantitative definition\n * @param result - The evaluated quantitative result\n * @param groups - The definition's already-joined worksheet groups\n * @returns A fresh, ordered list of steps: applied factors, then groups, then the total\n *\n * @example\n * ```ts\n * import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'\n * import { buildWorksheetGroup, buildWorksheetSteps } from '@orkestrel/rater'\n *\n * const definition = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, definition)\n * if (result.reasoning === 'quantitative') {\n * \tbuildWorksheetSteps(definition, result, definition.groups.map((group) => buildWorksheetGroup(group, result.groups)))\n * }\n * ```\n */\nexport function buildWorksheetSteps(\n\tdefinition: QuantitativeDefinition,\n\tresult: QuantitativeResult,\n\tgroups: readonly WorksheetGroup[],\n): readonly Step[] {\n\tconst output: Step[] = []\n\tfor (const group of groups) {\n\t\tfor (const factor of group.factors) {\n\t\t\tif (factor.applied && factor.value !== undefined) {\n\t\t\t\toutput.push(\n\t\t\t\t\tbuildWorksheetStep(\n\t\t\t\t\t\t'factor',\n\t\t\t\t\t\tfactor.id,\n\t\t\t\t\t\tfactor.name,\n\t\t\t\t\t\tfactor.value,\n\t\t\t\t\t\t`${factor.id} = ${factor.value}`,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\toutput.push(\n\t\t\tbuildWorksheetStep(\n\t\t\t\t'group',\n\t\t\t\tgroup.id,\n\t\t\t\tgroup.name,\n\t\t\t\tgroup.value,\n\t\t\t\t`${group.id} = ${group.value}`,\n\t\t\t),\n\t\t)\n\t}\n\toutput.push(\n\t\tbuildWorksheetStep(\n\t\t\t'total',\n\t\t\tdefinition.id,\n\t\t\tdefinition.name,\n\t\t\tresult.value,\n\t\t\t`${definition.aggregation} = ${result.value}`,\n\t\t),\n\t)\n\treturn output\n}\n\n/**\n * Joins a {@link QuantitativeDefinition} and its {@link QuantitativeResult} into\n * a {@link Worksheet} — the rating audit trail.\n *\n * @param definition - The authored quantitative definition\n * @param result - The evaluated quantitative result\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh worksheet\n *\n * @example\n * ```ts\n * import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'\n * import { buildWorksheet } from '@orkestrel/rater'\n *\n * const definition = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, definition)\n * if (result.reasoning === 'quantitative') buildWorksheet(definition, result) // the full audit trail\n * ```\n */\nexport function buildWorksheet(\n\tdefinition: QuantitativeDefinition,\n\tresult: QuantitativeResult,\n\tlabels?: Readonly<Record<string, string>>,\n): Worksheet {\n\tconst groups = definition.groups.map((group) => buildWorksheetGroup(group, result.groups, labels))\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\taggregation: definition.aggregation,\n\t\t...(definition.precision === undefined ? {} : { precision: definition.precision }),\n\t\tvalue: result.value,\n\t\tgroups,\n\t\tsteps: buildWorksheetSteps(definition, result, groups),\n\t\ttrace: result.trace,\n\t\terrors: result.errors,\n\t\tsuccess: result.success,\n\t}\n}\n\n/**\n * Builds a rated {@link LineResult} from a line's evaluated\n * {@link QuantitativeResult}.\n *\n * @param definition - The authored line definition\n * @param result - The evaluated quantitative result\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh line result\n *\n * @example\n * ```ts\n * import { createQuantitativeDefinition, createQuantitativeReasoner, createReason } from '@orkestrel/reason'\n * import { buildLineDefinition, buildLineResult } from '@orkestrel/rater'\n *\n * const line = buildLineDefinition('base', 'Base', createQuantitativeDefinition('base', 'Base', []))\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, line.rate)\n * if (result.reasoning === 'quantitative') buildLineResult(line, result) // amount present only on a successful worksheet\n * ```\n */\nexport function buildLineResult(\n\tdefinition: LineDefinition,\n\tresult: QuantitativeResult,\n\tlabels?: Readonly<Record<string, string>>,\n): LineResult {\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\t...(result.success ? { amount: result.value } : {}),\n\t\tworksheet: buildWorksheet(definition.rate, result, labels),\n\t}\n}\n\n/**\n * Sums defined line amounts.\n *\n * @param lines - The rated lines\n * @returns The sum of every line's `amount`, or `undefined` when no line has one\n *\n * @example\n * ```ts\n * import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'\n * import { buildLineDefinition, buildLineResult, sumAmounts } from '@orkestrel/rater'\n *\n * const rate = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])\n * const line = buildLineDefinition('base', 'Base', rate)\n * const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, rate)\n * if (result.reasoning === 'quantitative') sumAmounts([buildLineResult(line, result)]) // 100\n * ```\n */\nexport function sumAmounts(lines: readonly LineResult[]): number | undefined {\n\tlet total = 0\n\tlet count = 0\n\tfor (const rated of lines) {\n\t\tif (rated.amount !== undefined) {\n\t\t\ttotal += rated.amount\n\t\t\tcount += 1\n\t\t}\n\t}\n\treturn count === 0 ? undefined : total\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tQuantitativeDefinition,\n\tQuantitativeResult,\n\tReasonInterface,\n\tSubject,\n} from '@orkestrel/reason'\nimport type {\n\tLineDefinition,\n\tLineResult,\n\tRaterEventMap,\n\tRaterInterface,\n\tRaterOptions,\n\tRatingDefinition,\n\tRatingResult,\n\tTotalHandler,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { arrayOf, isArray, isRecord } from '@orkestrel/contract'\nimport { buildErrorResult, createQuantitativeReasoner, createReason } from '@orkestrel/reason'\nimport { RaterError } from './errors.js'\nimport { buildLineResult, sumAmounts } from './helpers.js'\nimport { isLineDefinition, isRatingDefinition } from './validators.js'\n\n/**\n * Orchestrates rating — owns (or receives) the shared quantitative\n * reasoning engine and projects results into the rating domain vocabulary.\n *\n * @remarks\n * When no `engine` is injected, `Rater` builds and owns its own\n * quantitative-only engine (`bail: false`) — Rater performs no evaluation\n * arithmetic of its own; it only orchestrates and projects. The\n * array-of-lines `rate` overload is declared first so a plain line list\n * resolves to that form. `destroy()` destroys an owned engine, then the\n * emitter last; an injected engine is never destroyed. Afterwards every\n * other method throws {@link RaterError} `'DESTROYED'`.\n *\n * @example\n * ```ts\n * import { Rater } from '@orkestrel/rater'\n *\n * const rater = new Rater()\n * rater.rate([], { id: 'subject-1' }) // { lines: [], success: true }\n * rater.destroy()\n * ```\n */\nexport class Rater implements RaterInterface {\n\treadonly #emitter: Emitter<RaterEventMap>\n\treadonly #engine: ReasonInterface\n\treadonly #owned: boolean\n\treadonly #total: TotalHandler | undefined\n\treadonly #labels: Readonly<Record<string, string>> | undefined\n\t#destroyed = false\n\n\tconstructor(options?: RaterOptions) {\n\t\tthis.#emitter = new Emitter<RaterEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t\tif (options?.engine === undefined) {\n\t\t\tthis.#engine = createReason({ reasoners: [createQuantitativeReasoner()], bail: false })\n\t\t\tthis.#owned = true\n\t\t} else {\n\t\t\tthis.#engine = options.engine\n\t\t\tthis.#owned = false\n\t\t}\n\t\tthis.#total = options?.total\n\t\tthis.#labels = options?.labels\n\t}\n\n\tget emitter(): EmitterInterface<RaterEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t// Array overload first so a plain line list resolves to that form.\n\trate(lines: readonly LineDefinition[], subject: Subject): RatingResult\n\trate(definition: RatingDefinition, subject: Subject): RatingResult\n\trate(input: readonly LineDefinition[] | RatingDefinition, subject: Subject): RatingResult {\n\t\tthis.#ensureAlive()\n\t\tconst lines = this.#normalize(input)\n\t\tif (!isRecord(subject)) throw new RaterError('MISMATCH', 'Subject must be a record')\n\t\tconst results = lines.map((line) => this.#rateLine(line, subject))\n\t\tconst total = (this.#total ?? sumAmounts)(results)\n\t\tconst success = results.every((entry) => entry.worksheet.success)\n\t\tconst result: RatingResult = {\n\t\t\tlines: results,\n\t\t\t...(total === undefined ? {} : { total }),\n\t\t\tsuccess,\n\t\t}\n\t\tthis.#emitter.emit('rate', subject, result)\n\t\treturn result\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tif (this.#owned) this.#engine.destroy()\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#normalize(input: readonly LineDefinition[] | RatingDefinition): readonly LineDefinition[] {\n\t\tif (arrayOf(isLineDefinition)(input)) return input\n\t\tif (isRatingDefinition(input)) return input.lines\n\t\tthrow new RaterError(\n\t\t\t'DEFINITION',\n\t\t\t'Rating input must be an array of line definitions or a rating definition',\n\t\t)\n\t}\n\n\t#rateLine(line: LineDefinition, subject: Subject): LineResult {\n\t\tconst result = this.#reasonQuantitative(subject, line.rate)\n\t\treturn buildLineResult(line, result, this.#labels)\n\t}\n\n\t// Narrows the engine's tagged ReasonResult union down to a QuantitativeResult\n\t// for a definition the engine is guaranteed (by dispatch-by-reasoning, given\n\t// only the quantitative reasoner is ever registered) to resolve as such — a\n\t// defensive, total fallback rather than an assertion. A nonconforming\n\t// injected engine result missing (or with a non-array) `errors` contributes\n\t// no errors from that side rather than throwing.\n\t#reasonQuantitative(subject: Subject, definition: QuantitativeDefinition): QuantitativeResult {\n\t\tconst result = this.#engine.reason(subject, definition)\n\t\tif (result.reasoning === 'quantitative') return result\n\t\tconst failure = buildErrorResult(\n\t\t\tdefinition,\n\t\t\t`Expected quantitative result, got ${result.reasoning}`,\n\t\t)\n\t\tconst errors = [...(isArray<string>(result.errors) ? result.errors : []), ...failure.errors]\n\t\tif (failure.reasoning === 'quantitative') return { ...failure, errors }\n\t\treturn {\n\t\t\treasoning: 'quantitative',\n\t\t\tvalue: 0,\n\t\t\tgroups: [],\n\t\t\tcount: 0,\n\t\t\tsuccess: false,\n\t\t\ttrace: [],\n\t\t\terrors,\n\t\t}\n\t}\n\n\t#ensureAlive(): void {\n\t\tif (this.#destroyed) throw new RaterError('DESTROYED', 'Rater has been destroyed')\n\t}\n}\n","import type { RaterInterface, RaterOptions } from './types.js'\nimport { Rater } from './Rater.js'\n\n/**\n * Creates a rating orchestrator over the shared quantitative engine, seeded\n * from {@link RaterOptions} and returning a {@link RaterInterface}.\n *\n * @param options - Optional total handler, labels, injected engine, and emitter hooks\n * @returns A {@link RaterInterface}\n *\n * @example Create a rater\n * ```ts\n * import { createRater } from '@orkestrel/rater'\n *\n * const rater = createRater()\n * rater.destroy()\n * ```\n */\nexport function createRater(options?: RaterOptions): RaterInterface {\n\treturn new Rater(options)\n}\n"],"mappings":"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"}