@orkestrel/rater 0.0.14 → 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/dist/src/core/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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'\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 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 * @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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"}
|
|
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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"}
|
package/dist/src/core/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { arrayOf, isArray, isBoolean, isJSONValue, isNumber, isRecord, isString, literalOf, objectOf, recordOf } from "@orkestrel/contract";
|
|
1
|
+
import { arrayOf, isArray, isBoolean, isInstance, isJSONValue, isNumber, isRecord, isString, literalOf, objectOf, recordOf } from "@orkestrel/contract";
|
|
2
2
|
import { buildErrorResult, createQuantitativeReasoner, createReason, formatField, isAggregation, isComparison, isFieldPath, isQuantitativeDefinition } from "@orkestrel/reason";
|
|
3
3
|
import { Emitter } from "@orkestrel/emitter";
|
|
4
4
|
//#region src/core/errors.ts
|
|
@@ -46,7 +46,7 @@ var RaterError = class extends Error {
|
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
48
|
function isRaterError(value) {
|
|
49
|
-
return value
|
|
49
|
+
return isInstance(value, RaterError);
|
|
50
50
|
}
|
|
51
51
|
//#endregion
|
|
52
52
|
//#region src/core/validators.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","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'\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 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 * @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":";;;;;;;;;;;;;;;;;;;;AAkBA,IAAa,aAAb,cAAgC,MAAM;CACrC;CACA;CAEA,YAAY,MAAsB,SAAiB,SAA6C;EAC/F,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,IAAI,YAAY,KAAA,GAAW,KAAK,UAAU;CAC3C;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,aAAa,OAAqC;CACjE,OAAO,iBAAiB;AACzB;;;;;;;;;;;;;;;;;;;;;ACDA,IAAa,UAAwB,UAAU,UAAU,SAAS,OAAO;;;;;;;;;;;;;;;;;;;;;;AAuBzE,SAAgB,iBAAiB,OAAyC;CACzE,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;CACX,GACA,CAAC,eAAe,UAAU,CAC3B,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,mBAAmB,OAA2C;CAC7E,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,OAAO,QAAQ,gBAAgB;EAC/B,UAAU;CACX,GACA,CAAC,eAAe,UAAU,CAC3B,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,WAAW,OAAmC;CAC7D,OAAO,SACN;EACC,OAAO;EACP,OAAO;EACP,YAAY;EACZ,KAAK;CACN,GACA;EAAC;EAAS;EAAS;EAAc;CAAK,CACvC,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,kBAAkB,OAA0C;CAC3E,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,SAAS;EACT,OAAO;EACP,UAAU,QAAQ,UAAU;CAC7B,GACA;EAAC;EAAQ;EAAe;CAAO,CAChC,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,iBAAiB,OAAyC;CACzE,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,SAAS;EACT,OAAO;EACP,SAAS,QAAQ,iBAAiB;CACnC,GACA,CAAC,QAAQ,aAAa,CACvB,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,OAAO,OAA+B;CACrD,OAAO,SACN;EACC,OAAO;EACP,IAAI;EACJ,MAAM;EACN,OAAO;EACP,YAAY;CACb,GACA;EAAC;EAAM;EAAQ;CAAY,CAC5B,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,YAAY,OAAoC;CAC/D,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,WAAW;EACX,OAAO;EACP,QAAQ,QAAQ,gBAAgB;EAChC,OAAO,QAAQ,MAAM;EACrB,OAAO,QAAQ,QAAQ;EACvB,QAAQ,QAAQ,QAAQ;EACxB,SAAS;CACV,GACA,CAAC,WAAW,CACb,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,aAAa,OAAqC;CACjE,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,QAAQ;EACR,WAAW;CACZ,GACA,CAAC,QAAQ,CACV,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,eAAe,OAAuC;CACrE,OAAO,SACN;EACC,OAAO,QAAQ,YAAY;EAC3B,OAAO;EACP,SAAS;CACV,GACA,CAAC,OAAO,CACT,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;AC5TA,SAAgB,oBACf,IACA,MACA,MACA,WACiB;CACjB,OAAO;EAAE;EAAI;EAAM;EAAM,GAAG;CAAU;AACvC;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,sBACf,IACA,MACA,OACA,WACmB;CACnB,OAAO;EAAE;EAAI;EAAM;EAAO,GAAG;CAAU;AACxC;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cACf,OACA,QACA,KACA,QACW;CACX,MAAM,QAAQ,YAAY,MAAM,KAAK;CACrC,OAAO;EACN,OAAO,MAAM;EACb,GAAI,SAAS,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,OAAO,OAAO;EAChE,YAAY,MAAM;EAClB,UAAU,MAAM;EAChB;EACA,GAAI,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,IAAI;CACpC;AACD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,kBACf,QACA,SACA,QACsB;CACtB,QAAQ,UAAU,CAAC,EAAA,CAAG,KAAK,OAAO,UAAU;EAC3C,MAAM,SAAS,UAAU;EACzB,OAAO,cAAc,OAAO,QAAQ,QAAQ,QAAQ,KAAK,MAAM;CAChE,CAAC;AACF;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,qBACf,YACA,SACA,QACkB;CAClB,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,OAAO,WAAW,EAAE;CACjE,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,GAAI,WAAW,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,WAAW,YAAY;EACtF,SAAS,QAAQ,WAAW;EAC5B,GAAI,QAAQ,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,OAAO,MAAM;EAC7D,UAAU,kBAAkB,WAAW,QAAQ,QAAQ,QAAQ,MAAM;CACtE;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,oBACf,YACA,SACA,QACiB;CACjB,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,OAAO,WAAW,EAAE;CACjE,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,GAAI,WAAW,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,WAAW,YAAY;EACtF,SAAS,QAAQ,WAAW;EAC5B,OAAO,QAAQ,SAAS;EACxB,SAAS,WAAW,QAAQ,KAAK,WAChC,qBAAqB,QAAQ,QAAQ,WAAW,CAAC,GAAG,MAAM,CAC3D;CACD;AACD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,mBACf,OACA,IACA,MACA,OACA,YACO;CACP,OAAO;EACN;EACA,GAAI,OAAO,KAAA,IAAY,CAAC,IAAI,EAAE,GAAG;EACjC,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC;EACA;CACD;AACD;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,oBACf,YACA,QACA,QACkB;CAClB,MAAM,SAAiB,CAAC;CACxB,KAAK,MAAM,SAAS,QAAQ;EAC3B,KAAK,MAAM,UAAU,MAAM,SAC1B,IAAI,OAAO,WAAW,OAAO,UAAU,KAAA,GACtC,OAAO,KACN,mBACC,UACA,OAAO,IACP,OAAO,MACP,OAAO,OACP,GAAG,OAAO,GAAG,KAAK,OAAO,OAC1B,CACD;EAGF,OAAO,KACN,mBACC,SACA,MAAM,IACN,MAAM,MACN,MAAM,OACN,GAAG,MAAM,GAAG,KAAK,MAAM,OACxB,CACD;CACD;CACA,OAAO,KACN,mBACC,SACA,WAAW,IACX,WAAW,MACX,OAAO,OACP,GAAG,WAAW,YAAY,KAAK,OAAO,OACvC,CACD;CACA,OAAO;AACR;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eACf,YACA,QACA,QACY;CACZ,MAAM,SAAS,WAAW,OAAO,KAAK,UAAU,oBAAoB,OAAO,OAAO,QAAQ,MAAM,CAAC;CACjG,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,aAAa,WAAW;EACxB,GAAI,WAAW,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,WAAW,UAAU;EAChF,OAAO,OAAO;EACd;EACA,OAAO,oBAAoB,YAAY,QAAQ,MAAM;EACrD,OAAO,OAAO;EACd,QAAQ,OAAO;EACf,SAAS,OAAO;CACjB;AACD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,gBACf,YACA,QACA,QACa;CACb,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,GAAI,OAAO,UAAU,EAAE,QAAQ,OAAO,MAAM,IAAI,CAAC;EACjD,WAAW,eAAe,WAAW,MAAM,QAAQ,MAAM;CAC1D;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,WAAW,OAAkD;CAC5E,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,KAAK,MAAM,SAAS,OACnB,IAAI,MAAM,WAAW,KAAA,GAAW;EAC/B,SAAS,MAAM;EACf,SAAS;CACV;CAED,OAAO,UAAU,IAAI,KAAA,IAAY;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;ACxWA,IAAa,QAAb,MAA6C;CAC5C;CACA;CACA;CACA;CACA;CACA,aAAa;CAEb,YAAY,SAAwB;EACnC,KAAK,WAAW,IAAI,QAAuB;GAC1C,GAAI,SAAS,OAAO,KAAA,IAAY,CAAC,IAAI,EAAE,IAAI,QAAQ,GAAG;GACtD,GAAI,SAAS,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,QAAQ,MAAM;EAChE,CAAC;EACD,IAAI,SAAS,WAAW,KAAA,GAAW;GAClC,KAAK,UAAU,aAAa;IAAE,WAAW,CAAC,2BAA2B,CAAC;IAAG,MAAM;GAAM,CAAC;GACtF,KAAK,SAAS;EACf,OAAO;GACN,KAAK,UAAU,QAAQ;GACvB,KAAK,SAAS;EACf;EACA,KAAK,SAAS,SAAS;EACvB,KAAK,UAAU,SAAS;CACzB;CAEA,IAAI,UAA2C;EAC9C,OAAO,KAAK;CACb;CAKA,KAAK,OAAqD,SAAgC;EACzF,KAAK,aAAa;EAClB,MAAM,QAAQ,KAAK,WAAW,KAAK;EACnC,IAAI,CAAC,SAAS,OAAO,GAAG,MAAM,IAAI,WAAW,YAAY,0BAA0B;EACnF,MAAM,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,MAAM,OAAO,CAAC;EACjE,MAAM,SAAS,KAAK,UAAU,WAAA,CAAY,OAAO;EACjD,MAAM,UAAU,QAAQ,OAAO,UAAU,MAAM,UAAU,OAAO;EAChE,MAAM,SAAuB;GAC5B,OAAO;GACP,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;GACvC;EACD;EACA,KAAK,SAAS,KAAK,QAAQ,SAAS,MAAM;EAC1C,OAAO;CACR;CAEA,UAAgB;EACf,IAAI,KAAK,YAAY;EACrB,KAAK,aAAa;EAClB,IAAI,KAAK,QAAQ,KAAK,QAAQ,QAAQ;EACtC,KAAK,SAAS,QAAQ;CACvB;CAEA,WAAW,OAAgF;EAC1F,IAAI,QAAQ,gBAAgB,CAAC,CAAC,KAAK,GAAG,OAAO;EAC7C,IAAI,mBAAmB,KAAK,GAAG,OAAO,MAAM;EAC5C,MAAM,IAAI,WACT,cACA,0EACD;CACD;CAEA,UAAU,MAAsB,SAA8B;EAE7D,OAAO,gBAAgB,MADR,KAAK,oBAAoB,SAAS,KAAK,IACzB,GAAQ,KAAK,OAAO;CAClD;CAQA,oBAAoB,SAAkB,YAAwD;EAC7F,MAAM,SAAS,KAAK,QAAQ,OAAO,SAAS,UAAU;EACtD,IAAI,OAAO,cAAc,gBAAgB,OAAO;EAChD,MAAM,UAAU,iBACf,YACA,qCAAqC,OAAO,WAC7C;EACA,MAAM,SAAS,CAAC,GAAI,QAAgB,OAAO,MAAM,IAAI,OAAO,SAAS,CAAC,GAAI,GAAG,QAAQ,MAAM;EAC3F,IAAI,QAAQ,cAAc,gBAAgB,OAAO;GAAE,GAAG;GAAS;EAAO;EACtE,OAAO;GACN,WAAW;GACX,OAAO;GACP,QAAQ,CAAC;GACT,OAAO;GACP,SAAS;GACT,OAAO,CAAC;GACR;EACD;CACD;CAEA,eAAqB;EACpB,IAAI,KAAK,YAAY,MAAM,IAAI,WAAW,aAAa,0BAA0B;CAClF;AACD;;;;;;;;;;;;;;;;;;AC7HA,SAAgB,YAAY,SAAwC;CACnE,OAAO,IAAI,MAAM,OAAO;AACzB"}
|
|
1
|
+
{"version":3,"file":"index.js","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":";;;;;;;;;;;;;;;;;;;;AAmBA,IAAa,aAAb,cAAgC,MAAM;CACrC;CACA;CAEA,YAAY,MAAsB,SAAiB,SAA6C;EAC/F,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,IAAI,YAAY,KAAA,GAAW,KAAK,UAAU;CAC3C;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,aAAa,OAAqC;CACjE,OAAO,WAAW,OAAO,UAAU;AACpC;;;;;;;;;;;;;;;;;;;;;ACFA,IAAa,UAAwB,UAAU,UAAU,SAAS,OAAO;;;;;;;;;;;;;;;;;;;;;;AAuBzE,SAAgB,iBAAiB,OAAyC;CACzE,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,MAAM;EACN,UAAU;CACX,GACA,CAAC,eAAe,UAAU,CAC3B,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,mBAAmB,OAA2C;CAC7E,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,OAAO,QAAQ,gBAAgB;EAC/B,UAAU;CACX,GACA,CAAC,eAAe,UAAU,CAC3B,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,WAAW,OAAmC;CAC7D,OAAO,SACN;EACC,OAAO;EACP,OAAO;EACP,YAAY;EACZ,KAAK;CACN,GACA;EAAC;EAAS;EAAS;EAAc;CAAK,CACvC,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,kBAAkB,OAA0C;CAC3E,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,SAAS;EACT,OAAO;EACP,UAAU,QAAQ,UAAU;CAC7B,GACA;EAAC;EAAQ;EAAe;CAAO,CAChC,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,iBAAiB,OAAyC;CACzE,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,SAAS;EACT,OAAO;EACP,SAAS,QAAQ,iBAAiB;CACnC,GACA,CAAC,QAAQ,aAAa,CACvB,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,OAAO,OAA+B;CACrD,OAAO,SACN;EACC,OAAO;EACP,IAAI;EACJ,MAAM;EACN,OAAO;EACP,YAAY;CACb,GACA;EAAC;EAAM;EAAQ;CAAY,CAC5B,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,YAAY,OAAoC;CAC/D,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,aAAa;EACb,WAAW;EACX,OAAO;EACP,QAAQ,QAAQ,gBAAgB;EAChC,OAAO,QAAQ,MAAM;EACrB,OAAO,QAAQ,QAAQ;EACvB,QAAQ,QAAQ,QAAQ;EACxB,SAAS;CACV,GACA,CAAC,WAAW,CACb,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,aAAa,OAAqC;CACjE,OAAO,SACN;EACC,IAAI;EACJ,MAAM;EACN,QAAQ;EACR,WAAW;CACZ,GACA,CAAC,QAAQ,CACV,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,eAAe,OAAuC;CACrE,OAAO,SACN;EACC,OAAO,QAAQ,YAAY;EAC3B,OAAO;EACP,SAAS;CACV,GACA,CAAC,OAAO,CACT,CAAC,CAAC,KAAK;AACR;;;;;;;;;;;;;;;;;;;;;;AC5TA,SAAgB,oBACf,IACA,MACA,MACA,WACiB;CACjB,OAAO;EAAE;EAAI;EAAM;EAAM,GAAG;CAAU;AACvC;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,sBACf,IACA,MACA,OACA,WACmB;CACnB,OAAO;EAAE;EAAI;EAAM;EAAO,GAAG;CAAU;AACxC;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cACf,OACA,QACA,KACA,QACW;CACX,MAAM,QAAQ,YAAY,MAAM,KAAK;CACrC,OAAO;EACN,OAAO,MAAM;EACb,GAAI,SAAS,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,OAAO,OAAO;EAChE,YAAY,MAAM;EAClB,UAAU,MAAM;EAChB;EACA,GAAI,QAAQ,KAAA,IAAY,CAAC,IAAI,EAAE,IAAI;CACpC;AACD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,kBACf,QACA,SACA,QACsB;CACtB,QAAQ,UAAU,CAAC,EAAA,CAAG,KAAK,OAAO,UAAU;EAC3C,MAAM,SAAS,UAAU;EACzB,OAAO,cAAc,OAAO,QAAQ,QAAQ,QAAQ,KAAK,MAAM;CAChE,CAAC;AACF;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,qBACf,YACA,SACA,QACkB;CAClB,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,OAAO,WAAW,EAAE;CACjE,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,GAAI,WAAW,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,WAAW,YAAY;EACtF,SAAS,QAAQ,WAAW;EAC5B,GAAI,QAAQ,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,OAAO,MAAM;EAC7D,UAAU,kBAAkB,WAAW,QAAQ,QAAQ,QAAQ,MAAM;CACtE;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,oBACf,YACA,SACA,QACiB;CACjB,MAAM,SAAS,QAAQ,MAAM,UAAU,MAAM,OAAO,WAAW,EAAE;CACjE,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,GAAI,WAAW,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,WAAW,YAAY;EACtF,SAAS,QAAQ,WAAW;EAC5B,OAAO,QAAQ,SAAS;EACxB,SAAS,WAAW,QAAQ,KAAK,WAChC,qBAAqB,QAAQ,QAAQ,WAAW,CAAC,GAAG,MAAM,CAC3D;CACD;AACD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,mBACf,OACA,IACA,MACA,OACA,YACO;CACP,OAAO;EACN;EACA,GAAI,OAAO,KAAA,IAAY,CAAC,IAAI,EAAE,GAAG;EACjC,GAAI,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,KAAK;EACrC;EACA;CACD;AACD;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,oBACf,YACA,QACA,QACkB;CAClB,MAAM,SAAiB,CAAC;CACxB,KAAK,MAAM,SAAS,QAAQ;EAC3B,KAAK,MAAM,UAAU,MAAM,SAC1B,IAAI,OAAO,WAAW,OAAO,UAAU,KAAA,GACtC,OAAO,KACN,mBACC,UACA,OAAO,IACP,OAAO,MACP,OAAO,OACP,GAAG,OAAO,GAAG,KAAK,OAAO,OAC1B,CACD;EAGF,OAAO,KACN,mBACC,SACA,MAAM,IACN,MAAM,MACN,MAAM,OACN,GAAG,MAAM,GAAG,KAAK,MAAM,OACxB,CACD;CACD;CACA,OAAO,KACN,mBACC,SACA,WAAW,IACX,WAAW,MACX,OAAO,OACP,GAAG,WAAW,YAAY,KAAK,OAAO,OACvC,CACD;CACA,OAAO;AACR;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,eACf,YACA,QACA,QACY;CACZ,MAAM,SAAS,WAAW,OAAO,KAAK,UAAU,oBAAoB,OAAO,OAAO,QAAQ,MAAM,CAAC;CACjG,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,aAAa,WAAW;EACxB,GAAI,WAAW,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,WAAW,UAAU;EAChF,OAAO,OAAO;EACd;EACA,OAAO,oBAAoB,YAAY,QAAQ,MAAM;EACrD,OAAO,OAAO;EACd,QAAQ,OAAO;EACf,SAAS,OAAO;CACjB;AACD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,gBACf,YACA,QACA,QACa;CACb,OAAO;EACN,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,GAAI,OAAO,UAAU,EAAE,QAAQ,OAAO,MAAM,IAAI,CAAC;EACjD,WAAW,eAAe,WAAW,MAAM,QAAQ,MAAM;CAC1D;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,WAAW,OAAkD;CAC5E,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,KAAK,MAAM,SAAS,OACnB,IAAI,MAAM,WAAW,KAAA,GAAW;EAC/B,SAAS,MAAM;EACf,SAAS;CACV;CAED,OAAO,UAAU,IAAI,KAAA,IAAY;AAClC;;;;;;;;;;;;;;;;;;;;;;;;;ACxWA,IAAa,QAAb,MAA6C;CAC5C;CACA;CACA;CACA;CACA;CACA,aAAa;CAEb,YAAY,SAAwB;EACnC,KAAK,WAAW,IAAI,QAAuB;GAC1C,GAAI,SAAS,OAAO,KAAA,IAAY,CAAC,IAAI,EAAE,IAAI,QAAQ,GAAG;GACtD,GAAI,SAAS,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO,QAAQ,MAAM;EAChE,CAAC;EACD,IAAI,SAAS,WAAW,KAAA,GAAW;GAClC,KAAK,UAAU,aAAa;IAAE,WAAW,CAAC,2BAA2B,CAAC;IAAG,MAAM;GAAM,CAAC;GACtF,KAAK,SAAS;EACf,OAAO;GACN,KAAK,UAAU,QAAQ;GACvB,KAAK,SAAS;EACf;EACA,KAAK,SAAS,SAAS;EACvB,KAAK,UAAU,SAAS;CACzB;CAEA,IAAI,UAA2C;EAC9C,OAAO,KAAK;CACb;CAKA,KAAK,OAAqD,SAAgC;EACzF,KAAK,aAAa;EAClB,MAAM,QAAQ,KAAK,WAAW,KAAK;EACnC,IAAI,CAAC,SAAS,OAAO,GAAG,MAAM,IAAI,WAAW,YAAY,0BAA0B;EACnF,MAAM,UAAU,MAAM,KAAK,SAAS,KAAK,UAAU,MAAM,OAAO,CAAC;EACjE,MAAM,SAAS,KAAK,UAAU,WAAA,CAAY,OAAO;EACjD,MAAM,UAAU,QAAQ,OAAO,UAAU,MAAM,UAAU,OAAO;EAChE,MAAM,SAAuB;GAC5B,OAAO;GACP,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;GACvC;EACD;EACA,KAAK,SAAS,KAAK,QAAQ,SAAS,MAAM;EAC1C,OAAO;CACR;CAEA,UAAgB;EACf,IAAI,KAAK,YAAY;EACrB,KAAK,aAAa;EAClB,IAAI,KAAK,QAAQ,KAAK,QAAQ,QAAQ;EACtC,KAAK,SAAS,QAAQ;CACvB;CAEA,WAAW,OAAgF;EAC1F,IAAI,QAAQ,gBAAgB,CAAC,CAAC,KAAK,GAAG,OAAO;EAC7C,IAAI,mBAAmB,KAAK,GAAG,OAAO,MAAM;EAC5C,MAAM,IAAI,WACT,cACA,0EACD;CACD;CAEA,UAAU,MAAsB,SAA8B;EAE7D,OAAO,gBAAgB,MADR,KAAK,oBAAoB,SAAS,KAAK,IACzB,GAAQ,KAAK,OAAO;CAClD;CAQA,oBAAoB,SAAkB,YAAwD;EAC7F,MAAM,SAAS,KAAK,QAAQ,OAAO,SAAS,UAAU;EACtD,IAAI,OAAO,cAAc,gBAAgB,OAAO;EAChD,MAAM,UAAU,iBACf,YACA,qCAAqC,OAAO,WAC7C;EACA,MAAM,SAAS,CAAC,GAAI,QAAgB,OAAO,MAAM,IAAI,OAAO,SAAS,CAAC,GAAI,GAAG,QAAQ,MAAM;EAC3F,IAAI,QAAQ,cAAc,gBAAgB,OAAO;GAAE,GAAG;GAAS;EAAO;EACtE,OAAO;GACN,WAAW;GACX,OAAO;GACP,QAAQ,CAAC;GACT,OAAO;GACP,SAAS;GACT,OAAO,CAAC;GACR;EACD;CACD;CAEA,eAAqB;EACpB,IAAI,KAAK,YAAY,MAAM,IAAI,WAAW,aAAa,0BAA0B;CAClF;AACD;;;;;;;;;;;;;;;;;;AC7HA,SAAgB,YAAY,SAAwC;CACnE,OAAO,IAAI,MAAM,OAAO;AACzB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkestrel/rater",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "A typed quantitative rating layer: authored lines are rated against a subject to produce per-line amounts, worksheets, and a derived total. Part of the @orkestrel line.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"quantitative",
|
|
@@ -72,17 +72,17 @@
|
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@orkestrel/contract": "^0.0.17",
|
|
74
74
|
"@orkestrel/emitter": "^0.0.10",
|
|
75
|
-
"@orkestrel/reason": "^0.0.
|
|
75
|
+
"@orkestrel/reason": "^0.0.11"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@microsoft/api-extractor": "^7.59.1",
|
|
79
|
-
"@orkestrel/guide": "^0.0.
|
|
80
|
-
"@orkestrel/probe": "^0.0.
|
|
81
|
-
"@orkestrel/scaffold": "^0.0.
|
|
82
|
-
"@orkestrel/test": "^0.0.
|
|
79
|
+
"@orkestrel/guide": "^0.0.19",
|
|
80
|
+
"@orkestrel/probe": "^0.0.15",
|
|
81
|
+
"@orkestrel/scaffold": "^0.0.70",
|
|
82
|
+
"@orkestrel/test": "^0.0.15",
|
|
83
83
|
"@types/node": "^26.5.1",
|
|
84
|
-
"oxfmt": "^0.
|
|
85
|
-
"oxlint": "^1.
|
|
84
|
+
"oxfmt": "^0.68.0",
|
|
85
|
+
"oxlint": "^1.83.0",
|
|
86
86
|
"typescript": "^6.0.3",
|
|
87
87
|
"vite": "^8.3.0",
|
|
88
88
|
"vitest": "^4.1.11"
|