@orkestrel/program 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -33
- package/dist/src/core/index.cjs +452 -225
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1846 -1201
- package/dist/src/core/index.d.ts +1846 -1201
- package/dist/src/core/index.js +445 -217
- package/dist/src/core/index.js.map +1 -1
- package/package.json +17 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#emitter","#qualifier","#rater","#engine","#evaluator","#qualifierOwned","#raterOwned","#engineOwned","#validate","#labels","#seal","#alive","#aggregate","#subject","#destroyed","#finish","#aggregateLimits","#emitter","#programs","#qualifier","#rater","#engine","#qualifierOwned","#raterOwned","#engineOwned","#validate","#labels","#alive","#drain","#removeOne","#destroyed"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/programs/Program.ts","../../../src/core/programs/ProgramManager.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { Decision, Status } from './types.js'\nimport type { Eligibility } from '@orkestrel/qualifier'\n\n/** Default definition validation policy for `createProgram` / `ProgramManager.add`. */\nexport const DEFAULT_PROGRAM_VALIDATE = true\n\n/** Status tally precedence order — least to most resolved. */\nexport const STATUS_PRECEDENCE: readonly Status[] = Object.freeze([\n\t'ineligible',\n\t'referral',\n\t'conditional',\n\t'unrated',\n\t'eligible',\n])\n\n/** The deterministic authority decision for each global eligibility. */\nexport const ELIGIBILITY_DECISIONS: Readonly<Record<Eligibility, Decision>> = Object.freeze({\n\teligible: 'approved',\n\tineligible: 'denied',\n\treferral: 'submitted',\n})\n\n/** The reserved working-subject key a batch's aggregate projection is written under. */\nexport const AGGREGATE_KEY = 'aggregate'\n\n/** The reserved working-subject key the authority's outcome projection is written under. */\nexport const OUTCOME_KEY = 'outcome'\n","import type { ProgramErrorCode } from './types.js'\n\n/**\n * A coded programmer error thrown by the program layer.\n *\n * @remarks\n * `DUPLICATE` — a program id collision on `ProgramManager.add`, or a duplicate\n * authored rating-line or notice id. `MISSING` — an\n * authored notice or qualification ruling scope names no rating line.\n * `DEFINITION` — a program, qualification, rating, authority, or aggregate\n * policy failed validation. `MISMATCH` — an injected entity or a returned\n * reason result has the wrong contract. `RESERVED` — a subject already\n * carries `aggregate` or `outcome`. `DESTROYED` — use of a destroyed entity.\n */\nexport class ProgramError extends Error {\n\treadonly code: ProgramErrorCode\n\treadonly context?: unknown\n\n\tconstructor(code: ProgramErrorCode, message: string, context?: unknown) {\n\t\tsuper(message)\n\t\tthis.name = 'ProgramError'\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/** Narrow a caught value to a {@link ProgramError}. */\nexport function isProgramError(value: unknown): value is ProgramError {\n\treturn value instanceof ProgramError\n}\n","import type { Guard } from '@orkestrel/contract'\nimport type {\n\tAggregateGroup,\n\tAggregateDefinition,\n\tAggregateResult,\n\tDecision,\n\tDetermination,\n\tNotice,\n\tProgramDefinition,\n\tProgramEffect,\n\tProgramResult,\n\tProgramValidationResult,\n\tStatus,\n\tTally,\n} from './types.js'\nimport {\n\tarrayOf,\n\tisBoolean,\n\tisJSONValue,\n\tisNumber,\n\tisString,\n\tliteralOf,\n\tobjectOf,\n\trecordOf,\n\twhereOf,\n} from '@orkestrel/contract'\nimport {\n\tisEligibility,\n\tisPremise,\n\tisQualificationDefinition,\n\tisQualificationResult,\n} from '@orkestrel/qualifier'\nimport { isRatingDefinition, isRatingResult } from '@orkestrel/rater'\nimport { isFieldPath, isLogicalDefinition } from '@orkestrel/reason'\nimport { STATUS_PRECEDENCE } from './constants.js'\n\n/**\n * Determine whether a value is a {@link Decision} literal.\n *\n * @param value - The candidate value\n * @returns `true` when `value` is a {@link Decision}\n *\n * @example\n * ```ts\n * import { isDecision } from '@orkestrel/program'\n *\n * isDecision('approved') // true\n * ```\n */\nexport const isDecision: Guard<Decision> = literalOf('approved', 'denied', 'submitted')\n\n/**\n * Determine whether a value is a {@link Status} literal.\n *\n * @param value - The candidate value\n * @returns `true` when `value` is a {@link Status}\n *\n * @example\n * ```ts\n * import { isStatus } from '@orkestrel/program'\n *\n * isStatus('eligible') // true\n * ```\n */\nexport const isStatus: Guard<Status> = literalOf(\n\t'ineligible',\n\t'referral',\n\t'conditional',\n\t'unrated',\n\t'eligible',\n)\n\n/**\n * Determine whether a value is a {@link ProgramEffect} literal.\n *\n * @param value - The candidate value\n * @returns `true` when `value` is a {@link ProgramEffect}\n *\n * @example\n * ```ts\n * import { isProgramEffect } from '@orkestrel/program'\n *\n * isProgramEffect('notice') // true\n * ```\n */\nexport const isProgramEffect: Guard<ProgramEffect> = literalOf('notice', 'limit')\n\n/**\n * Determine whether a value is an exact {@link Notice} record.\n *\n * @param value - The candidate value\n * @returns `true` when `value` is a {@link Notice}\n *\n * @example\n * ```ts\n * import { isNotice } from '@orkestrel/program'\n *\n * isNotice({ id: 'minimum', message: 'Minimum applies' }) // true\n * ```\n */\nexport function isNotice(value: unknown): value is Notice {\n\treturn recordOf({ id: isString, message: isString, scope: isString }, ['scope'])(value)\n}\n\n/**\n * Determine whether a value is an exact {@link AggregateDefinition} record.\n *\n * @param value - The candidate value\n * @returns `true` when `value` is an {@link AggregateDefinition}\n *\n * @example\n * ```ts\n * import { isAggregateDefinition } from '@orkestrel/program'\n *\n * isAggregateDefinition({ fields: ['amount'] }) // true\n * ```\n */\nexport function isAggregateDefinition(value: unknown): value is AggregateDefinition {\n\treturn recordOf({ fields: arrayOf(isFieldPath), by: isFieldPath, gates: isLogicalDefinition }, [\n\t\t'by',\n\t\t'gates',\n\t])(value)\n}\n\n/**\n * Determine whether a value is an exact {@link ProgramDefinition} record.\n *\n * @remarks\n * `rating` is optional — an omitted `rating` authors an eligibility-only\n * program (see {@link ProgramDefinition}).\n *\n * @param value - The candidate value\n * @returns `true` when `value` is a {@link ProgramDefinition}\n *\n * @example\n * ```ts\n * import { isProgramDefinition } from '@orkestrel/program'\n *\n * isProgramDefinition({ id: 'p', name: 'P', qualification }) // true\n * ```\n */\nexport function isProgramDefinition(value: unknown): value is ProgramDefinition {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tqualification: isQualificationDefinition,\n\t\t\trating: isRatingDefinition,\n\t\t\tnotices: arrayOf(isNotice),\n\t\t\tauthority: isLogicalDefinition,\n\t\t\taggregate: isAggregateDefinition,\n\t\t\tmetadata: isJSONValue,\n\t\t},\n\t\t['description', 'rating', 'notices', 'authority', 'aggregate', 'metadata'],\n\t)(value)\n}\n\n/**\n * Determine whether a value is an open program sums record.\n *\n * @remarks\n * Every own string-named property is checked, including non-enumerable\n * properties. Inherited and symbol-named members are outside the record this\n * guard certifies. Values remain plain JavaScript numbers, including `NaN` and\n * infinities, because the published contract does not refine them.\n *\n * @param value - The candidate value\n * @returns `true` when every own string-named value is a number\n *\n * @example\n * ```ts\n * import { isProgramSums } from '@orkestrel/program'\n *\n * isProgramSums({ premium: 100 }) // true\n * ```\n */\nexport function isProgramSums(value: unknown): value is Readonly<Record<string, number>> {\n\treturn whereOf(objectOf({}), (record) =>\n\t\tObject.getOwnPropertyNames(record).every((key) => isNumber(Reflect.get(record, key))),\n\t)(value)\n}\n\n/**\n * Determine whether a value is an open result-side {@link Determination}.\n *\n * @remarks\n * Unknown members and class instances are admitted. Arrays are refused.\n * Optional `scope` and `message` members may be absent or `undefined`.\n *\n * @param value - The candidate value\n * @returns `true` when every published determination member conforms\n *\n * @example\n * ```ts\n * import { isDetermination } from '@orkestrel/program'\n *\n * isDetermination({ id: 'audit', effect: 'notice', applied: true, premises: [] }) // true\n * ```\n */\nexport const isDetermination: Guard<Determination> = objectOf(\n\t{\n\t\tid: isString,\n\t\teffect: isProgramEffect,\n\t\tapplied: isBoolean,\n\t\tscope: isString,\n\t\tmessage: isString,\n\t\tpremises: arrayOf(isPremise),\n\t},\n\t['scope', 'message'],\n)\n\n/**\n * Determine whether a value is an open result-side {@link AggregateGroup}.\n *\n * @remarks\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns `true` when every published aggregate-group member conforms\n *\n * @example\n * ```ts\n * import { isAggregateGroup } from '@orkestrel/program'\n *\n * isAggregateGroup({ key: 'east', count: 1, sums: { premium: 100 } }) // true\n * ```\n */\nexport const isAggregateGroup: Guard<AggregateGroup> = objectOf({\n\tkey: isString,\n\tcount: isNumber,\n\tsums: isProgramSums,\n})\n\n/**\n * Determine whether a value is an open result-side {@link Tally}.\n *\n * @remarks\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns `true` when every published tally member conforms\n *\n * @example\n * ```ts\n * import { isTally } from '@orkestrel/program'\n *\n * isTally({ count: 1, sums: { premium: 100 } }) // true\n * ```\n */\nexport const isTally: Guard<Tally> = objectOf({ count: isNumber, sums: isProgramSums })\n\n/**\n * Determine whether a value is a total open status-tally record.\n *\n * @remarks\n * Every {@link Status} in {@link STATUS_PRECEDENCE} is required and checked.\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns `true` when every required status member is a {@link Tally}\n *\n * @example\n * ```ts\n * import { emptyTallies, isTallies } from '@orkestrel/program'\n *\n * isTallies(emptyTallies([])) // true\n * ```\n */\nexport function isTallies(value: unknown): value is Readonly<Record<Status, Tally>> {\n\treturn whereOf(objectOf({}), (record) =>\n\t\tSTATUS_PRECEDENCE.every((status) => isTally(Reflect.get(record, status))),\n\t)(value)\n}\n\n/**\n * Determine whether a value is an open {@link ProgramResult}.\n *\n * @remarks\n * This guard is result-postured for values returned through a borrowed\n * {@link ProgramInterface}. It admits unknown members and class instances while\n * composing qualifier's `isQualificationResult` and rater's `isRatingResult`\n * over their complete nested result closures. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns `true` when every published program-result member conforms\n *\n * @example\n * ```ts\n * import { isProgramResult } from '@orkestrel/program'\n *\n * isProgramResult(program.execute(subject)) // true\n * ```\n */\nexport const isProgramResult: Guard<ProgramResult> = objectOf(\n\t{\n\t\tid: isString,\n\t\tname: isString,\n\t\teligibility: isEligibility,\n\t\tstatus: isStatus,\n\t\tdecision: isDecision,\n\t\tqualification: isQualificationResult,\n\t\trating: isRatingResult,\n\t\tdeterminations: arrayOf(isDetermination),\n\t\tsuccess: isBoolean,\n\t\ttrace: arrayOf(isString),\n\t\terrors: arrayOf(isString),\n\t},\n\t['decision', 'rating'],\n)\n\n/**\n * Determine whether a value is an open {@link AggregateResult}.\n *\n * @remarks\n * This guard is result-postured for values returned through a borrowed\n * {@link ProgramInterface}. It admits unknown members and class instances while\n * checking every nested program result, determination, group, total tally\n * record, and sums record. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns `true` when every published aggregate-result member conforms\n *\n * @example\n * ```ts\n * import { isAggregateResult } from '@orkestrel/program'\n *\n * isAggregateResult(program.execute(subjects)) // true\n * ```\n */\nexport const isAggregateResult: Guard<AggregateResult> = objectOf({\n\tid: isString,\n\tname: isString,\n\tsubjects: arrayOf(isProgramResult),\n\tdeterminations: arrayOf(isDetermination),\n\tgroups: arrayOf(isAggregateGroup),\n\ttallies: isTallies,\n\tcount: isNumber,\n\tsums: isProgramSums,\n\tsuccess: isBoolean,\n\ttrace: arrayOf(isString),\n\terrors: arrayOf(isString),\n})\n\n/**\n * Determine whether a value is an open {@link ProgramValidationResult}.\n *\n * @remarks\n * `ProgramValidationResult` is this package's own declared interface, not an\n * alias of reason's validation result. This guard therefore checks the three\n * program-owned members directly so the contracts may evolve independently.\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns `true` when every published program-validation member conforms\n *\n * @example\n * ```ts\n * import { isProgramValidationResult } from '@orkestrel/program'\n *\n * isProgramValidationResult({ valid: true, errors: [], warnings: [] }) // true\n * ```\n */\nexport const isProgramValidationResult: Guard<ProgramValidationResult> = objectOf({\n\tvalid: isBoolean,\n\terrors: arrayOf(isString),\n\twarnings: arrayOf(isString),\n})\n","import type { FieldPath, JSONValue } from '@orkestrel/contract'\nimport type {\n\tEligibility,\n\tQualificationDefinition,\n\tQualificationResult,\n\tQualifierInterface,\n} from '@orkestrel/qualifier'\nimport type { LineDefinition, RatingDefinition, RatingResult } from '@orkestrel/rater'\nimport type {\n\tEvaluatorInterface,\n\tLogicalDefinition,\n\tLogicalResult,\n\tReasonInterface,\n\tSubject,\n} from '@orkestrel/reason'\nimport type {\n\tAggregateDefinition,\n\tAggregateGroup,\n\tAggregateInput,\n\tAggregateProjection,\n\tAggregateResult,\n\tDecision,\n\tDetermination,\n\tNotice,\n\tNoticeInput,\n\tProgramDefinition,\n\tProgramInput,\n\tProgramResult,\n\tProgramValidationResult,\n\tStatus,\n\tTally,\n} from './types.js'\nimport { isFiniteNumber, isRecord, resolveField } from '@orkestrel/contract'\nimport {\n\tfindRule,\n\tinterpolateMessage,\n\tisQualificationValidationResult,\n\tlogicalPremises,\n} from '@orkestrel/qualifier'\nimport { findDuplicates, formatField, isReasonValidationResult } from '@orkestrel/reason'\nimport {\n\tAGGREGATE_KEY,\n\tELIGIBILITY_DECISIONS,\n\tOUTCOME_KEY,\n\tSTATUS_PRECEDENCE,\n} from './constants.js'\nimport { ProgramError } from './errors.js'\nimport { isProgramDefinition } from './validators.js'\n\n/**\n * Return a fresh JSON value tree that does not alias the input.\n *\n * @remarks\n * The input must be an acyclic JSON tree of bounded depth — a pathologically\n * deep tree throws the engine's `RangeError` (stack exhaustion) rather than\n * hanging. Each copied record uses `Object.defineProperty` for own-property\n * definition, which defends against prototype-pollution keys (`__proto__`).\n *\n * @param value - The JSON value to copy\n * @returns A fresh JSON value\n *\n * @example\n * ```ts\n * import { copyJSONValue } from '@orkestrel/program'\n *\n * copyJSONValue({ a: [1, 2] }) // { a: [1, 2] }, a fresh copy\n * ```\n */\nexport function copyJSONValue(value: JSONValue): JSONValue {\n\tif (value === null || typeof value !== 'object') return value\n\tif (Array.isArray(value)) return value.map(copyJSONValue)\n\tconst copy: Record<string, JSONValue> = {}\n\tfor (const [key, entry] of Object.entries(value)) {\n\t\tObject.defineProperty(copy, key, {\n\t\t\tvalue: copyJSONValue(entry),\n\t\t\tenumerable: true,\n\t\t\twritable: true,\n\t\t\tconfigurable: true,\n\t\t})\n\t}\n\treturn copy\n}\n\n/**\n * Determine whether a caller subject already carries a reserved program key.\n *\n * @remarks\n * `aggregate` and `outcome` are program-private working-subject namespaces — the\n * batch aggregate projection and the authority outcome projection are written\n * under them. A caller subject that already owns either key would silently\n * collide with a projection, so it is rejected before qualification.\n *\n * @param subject - The caller subject to check\n * @returns `true` when the subject owns `aggregate` or `outcome`\n *\n * @example\n * ```ts\n * import { hasReservedKey } from '@orkestrel/program'\n *\n * hasReservedKey({ id: 'r1' }) // false\n * hasReservedKey({ id: 'r1', aggregate: {} }) // true\n * ```\n */\nexport function hasReservedKey(subject: Readonly<Record<string, unknown>>): boolean {\n\treturn Object.hasOwn(subject, AGGREGATE_KEY) || Object.hasOwn(subject, OUTCOME_KEY)\n}\n\n/**\n * Assert a value is a valid program {@link Subject}, narrowing it in place.\n *\n * @param subject - The candidate subject to validate\n * @throws {@link ProgramError} `'MISMATCH'` when the value is not a record, or\n * `'RESERVED'` when it already carries the `aggregate` or `outcome` key\n *\n * @example\n * ```ts\n * import { assertProgramSubject } from '@orkestrel/program'\n *\n * assertProgramSubject({ id: 'r1' }) // does not throw\n * ```\n */\nexport function assertProgramSubject(subject: unknown): asserts subject is Subject {\n\tif (!isRecord(subject)) {\n\t\tthrow new ProgramError('MISMATCH', 'Program subject must be a record')\n\t}\n\tif (hasReservedKey(subject)) {\n\t\tconst key = Object.hasOwn(subject, AGGREGATE_KEY) ? AGGREGATE_KEY : OUTCOME_KEY\n\t\tthrow new ProgramError('RESERVED', `Subject contains a reserved program key '${key}'`, key)\n\t}\n}\n\n/**\n * Select the rating lines a subject may be rated on from scoped eligibility.\n *\n * @remarks\n * A scope names a rating-line id. A line survives when its scope is absent\n * (eligible by default), `eligible`, or a `condition` (which is not an\n * eligibility value and never appears here). A scoped `ineligible` or `referral`\n * removes the line BEFORE the rater is invoked — the excluded line is never\n * evaluated merely to discard its amount.\n *\n * @param lines - The program's authored rating lines\n * @param scopes - The qualification's per-scope eligibility\n * @returns The surviving line definitions, in authored order\n *\n * @example\n * ```ts\n * import { selectProgramLines } from '@orkestrel/program'\n *\n * selectProgramLines(lines, { wind: 'ineligible' }) // every line except 'wind'\n * ```\n */\nexport function selectProgramLines(\n\tlines: readonly LineDefinition[],\n\tscopes: Readonly<Record<string, Eligibility>>,\n): readonly LineDefinition[] {\n\treturn lines.filter((line) => {\n\t\tconst eligibility = scopes[line.id]\n\t\treturn eligibility !== 'ineligible' && eligibility !== 'referral'\n\t})\n}\n\n/**\n * Derive the final program {@link Status} from a definition's rating policy and\n * qualification/rating evidence.\n *\n * @remarks\n * Explicit policy, not an opaque precedence reduce (AGENTS §10): global\n * ineligibility or referral is terminal; a scoped referral yields `referral`;\n * an applied `condition` or an applied scoped `restriction` (a line was\n * removed but others rated) is `conditional`. When the definition OMITS\n * `rating` the program is eligibility-only — status resolves to `conditional`\n * or `eligible` and is NEVER `unrated`. Otherwise a subject with no successful\n * rating is `unrated`.\n *\n * @param definition - The authored program definition\n * @param qualification - The subject's qualification result\n * @param rating - The subject's rating result, when rating occurred\n * @returns The derived status\n *\n * @example\n * ```ts\n * import { deriveStatus } from '@orkestrel/program'\n *\n * deriveStatus(definition, qualification, rating) // 'eligible'\n * ```\n */\nexport function deriveStatus(\n\tdefinition: ProgramDefinition,\n\tqualification: QualificationResult,\n\trating?: RatingResult,\n): Status {\n\tif (qualification.eligibility === 'ineligible') return 'ineligible'\n\tif (qualification.eligibility === 'referral') return 'referral'\n\tif (Object.values(qualification.scopes).includes('referral')) return 'referral'\n\tconst conditional = qualification.findings.some(\n\t\t(finding) =>\n\t\t\tfinding.applied &&\n\t\t\t(finding.effect === 'condition' ||\n\t\t\t\t(finding.scope !== undefined && finding.effect === 'restriction')),\n\t)\n\tif (definition.rating === undefined) return conditional ? 'conditional' : 'eligible'\n\tif (rating === undefined || rating.lines.length === 0 || !rating.success) return 'unrated'\n\treturn conditional ? 'conditional' : 'eligible'\n}\n\n/**\n * Map a global {@link Eligibility} to its deterministic authority {@link Decision}.\n *\n * @param eligibility - The global eligibility\n * @returns The matching decision\n *\n * @example\n * ```ts\n * import { decideEligibility } from '@orkestrel/program'\n *\n * decideEligibility('eligible') // 'approved'\n * decideEligibility('referral') // 'submitted'\n * ```\n */\nexport function decideEligibility(eligibility: Eligibility): Decision {\n\treturn ELIGIBILITY_DECISIONS[eligibility]\n}\n\n/**\n * Resolve authored {@link Notice}s into unconditionally-applied `notice`\n * {@link Determination}s.\n *\n * @remarks\n * Notices are program output only — they never affect eligibility, status, line\n * selection, or the decision. Each message interpolates against the original\n * subject.\n *\n * @param notices - The authored notices\n * @param subject - The original subject notices interpolate against\n * @returns A fresh list of notice determinations\n *\n * @example\n * ```ts\n * import { buildNotices } from '@orkestrel/program'\n *\n * buildNotices([{ id: 'min', message: 'Minimum applies' }], { id: 'r1' })\n * ```\n */\nexport function buildNotices(\n\tnotices: readonly Notice[],\n\tsubject: Readonly<Record<string, unknown>>,\n): readonly Determination[] {\n\treturn notices.map((notice) => ({\n\t\tid: notice.id,\n\t\teffect: 'notice',\n\t\tapplied: true,\n\t\t...(notice.scope === undefined ? {} : { scope: notice.scope }),\n\t\tmessage: interpolateMessage(notice.message, subject),\n\t\tpremises: [],\n\t}))\n}\n\n/**\n * Convert a logical result's applied rules into `limit` {@link Determination}s.\n *\n * @remarks\n * Fires for both the per-subject authority and the batch aggregate gates — both\n * are plain {@link LogicalDefinition}s with no program-authored ruling map, so a\n * fired rule's own `description` (from `@orkestrel/reason`) is the message\n * template, interpolated against the working record the definition ran against.\n * Rich premises reuse the qualifier's {@link logicalPremises}. A rule that never\n * fires produces no determination — program has no authored ruling map to keep\n * evidence for.\n *\n * @param definition - The authority or aggregate-gate logical definition\n * @param result - The evaluated logical result\n * @param working - The working record the definition ran against\n * @param evaluator - The shared reason check evaluator\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh list of `limit` determinations\n *\n * @example\n * ```ts\n * import { buildLimits } from '@orkestrel/program'\n *\n * buildLimits(authority, resolved, outcome, evaluator)\n * ```\n */\nexport function buildLimits(\n\tdefinition: LogicalDefinition,\n\tresult: LogicalResult,\n\tworking: Readonly<Record<string, unknown>>,\n\tevaluator: EvaluatorInterface,\n\tlabels?: Readonly<Record<string, string>>,\n): readonly Determination[] {\n\tconst output: Determination[] = []\n\tfor (const entry of result.rules) {\n\t\tif (!entry.applied) continue\n\t\tconst rule = findRule(definition, entry.id)\n\t\tif (rule === undefined) continue\n\t\toutput.push({\n\t\t\tid: entry.id,\n\t\t\teffect: 'limit',\n\t\t\tapplied: true,\n\t\t\t...(rule.description === undefined\n\t\t\t\t? {}\n\t\t\t\t: { message: interpolateMessage(rule.description, working) }),\n\t\t\tpremises: logicalPremises(rule, working, evaluator, labels),\n\t\t})\n\t}\n\treturn output\n}\n\n/**\n * Build the private authority outcome projection from an assembled program result.\n *\n * @remarks\n * The authority reads this record under {@link OUTCOME_KEY}; it never receives\n * the mutable internal state of either sibling engine. `total` is carried from\n * the nested rating result when rating occurred.\n *\n * @param result - The preliminary program result computed before authority runs\n * @returns A record shaped for the authority's `outcome` projection\n *\n * @example\n * ```ts\n * import { buildOutcomeProjection } from '@orkestrel/program'\n *\n * buildOutcomeProjection(result) // { id, eligibility, status, rated, scopes }\n * ```\n */\nexport function buildOutcomeProjection(result: ProgramResult): Readonly<Record<string, unknown>> {\n\tconst total = result.rating?.total\n\treturn {\n\t\tid: result.id,\n\t\teligibility: result.eligibility,\n\t\tstatus: result.status,\n\t\trated: result.rating !== undefined,\n\t\t...(total === undefined ? {} : { total }),\n\t\tscopes: { ...result.qualification.scopes },\n\t}\n}\n\n/**\n * Assemble a {@link ProgramResult} from its qualification, rating, and\n * determination parts — before or after authority.\n *\n * @remarks\n * `eligibility` mirrors the qualification. `success` is execution integrity: the\n * qualification succeeded, rating (when it ran) succeeded, and authority (when it\n * ran) produced no errors — a valid ineligible or referral outcome still\n * succeeds. `trace` and `errors` accumulate the qualification's, every rated\n * line's worksheet trail, and the authority's. A `decision` is present ONLY when\n * an authority ran (`options.authority`), the execution SUCCEEDED (`success`),\n * no `limit` determination applied, and status is not `unrated`.\n *\n * @param definition - The authored program definition\n * @param qualification - The subject's qualification result\n * @param rating - The subject's rating result, when rating occurred\n * @param determinations - The program-scoped determinations (notices, then limits)\n * @param status - The already-derived status\n * @param options - Optional authority result driving the decision projection\n * @returns A fresh program result\n *\n * @example\n * ```ts\n * import { buildProgramResult } from '@orkestrel/program'\n *\n * buildProgramResult(definition, qualification, rating, [], 'eligible')\n * ```\n */\nexport function buildProgramResult(\n\tdefinition: ProgramDefinition,\n\tqualification: QualificationResult,\n\trating: RatingResult | undefined,\n\tdeterminations: readonly Determination[],\n\tstatus: Status,\n\toptions?: { readonly authority?: LogicalResult },\n): ProgramResult {\n\tconst authority = options?.authority\n\tconst ratingTrace =\n\t\trating === undefined ? [] : rating.lines.flatMap((line) => line.worksheet.trace)\n\tconst ratingErrors =\n\t\trating === undefined ? [] : rating.lines.flatMap((line) => line.worksheet.errors)\n\tconst authorityTrace = authority === undefined ? [] : [...authority.trace]\n\tconst authorityErrors = authority === undefined ? [] : [...authority.errors]\n\tconst trace = [...qualification.trace, ...ratingTrace, ...authorityTrace]\n\tconst errors = [...qualification.errors, ...ratingErrors, ...authorityErrors]\n\tconst success =\n\t\tqualification.success &&\n\t\t(rating === undefined || rating.success) &&\n\t\tauthorityErrors.length === 0\n\tconst limited = determinations.some((entry) => entry.effect === 'limit' && entry.applied)\n\tconst decision =\n\t\tauthority !== undefined && success && !limited && status !== 'unrated'\n\t\t\t? decideEligibility(qualification.eligibility)\n\t\t\t: undefined\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\teligibility: qualification.eligibility,\n\t\tstatus,\n\t\t...(decision === undefined ? {} : { decision }),\n\t\tqualification,\n\t\t...(rating === undefined ? {} : { rating }),\n\t\tdeterminations,\n\t\tsuccess,\n\t\ttrace,\n\t\terrors,\n\t}\n}\n\n/**\n * Add optional aggregate context to a private subject copy for qualification.\n *\n * @remarks\n * The original subject is returned unchanged when no aggregate context exists.\n * When context exists the helper creates a private copy under {@link AGGREGATE_KEY}\n * and defensively copies every nested record — the rater still receives the\n * original subject, never this copy.\n *\n * @param subject - The original caller subject\n * @param aggregate - The subject's aggregate projection, when a batch supplies one\n * @returns The subject, or a private copy carrying the aggregate projection\n *\n * @example\n * ```ts\n * import { buildQualificationSubject } from '@orkestrel/program'\n *\n * buildQualificationSubject({ id: 'r1' }) // { id: 'r1' }\n * ```\n */\nexport function buildQualificationSubject(\n\tsubject: Subject,\n\taggregate?: AggregateProjection,\n): Subject {\n\tif (aggregate === undefined) return subject\n\treturn {\n\t\t...subject,\n\t\t[AGGREGATE_KEY]: {\n\t\t\tcount: aggregate.count,\n\t\t\tsums: { ...aggregate.sums },\n\t\t\t...(aggregate.group === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tgroup: {\n\t\t\t\t\t\t\tkey: aggregate.group.key,\n\t\t\t\t\t\t\tcount: aggregate.group.count,\n\t\t\t\t\t\t\tsums: { ...aggregate.group.sums },\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t},\n\t}\n}\n\n/**\n * Return authored scopes (qualification ruling scopes or notice scopes) that\n * name no rating line on the program.\n *\n * @remarks\n * A scope is an opaque string to the qualifier — program alone matches it to a\n * rating-line id. A scope naming no line is a hard authoring error surfaced as\n * {@link ProgramError} `'MISSING'` at construction, regardless of the validate\n * option.\n *\n * @param definition - The program definition to check\n * @returns A fresh, deduped list of missing scope references\n *\n * @example\n * ```ts\n * import { findMissingScopes } from '@orkestrel/program'\n *\n * findMissingScopes(definition) // []\n * ```\n */\nexport function findMissingScopes(definition: ProgramDefinition): readonly string[] {\n\tconst ids = new Set((definition.rating?.lines ?? []).map((line) => line.id))\n\tconst missing = new Set<string>()\n\tfor (const ruling of definition.qualification.rulings ?? []) {\n\t\tif (ruling.scope !== undefined && !ids.has(ruling.scope)) missing.add(ruling.scope)\n\t}\n\tfor (const notice of definition.notices ?? []) {\n\t\tif (notice.scope !== undefined && !ids.has(notice.scope)) missing.add(notice.scope)\n\t}\n\treturn [...missing]\n}\n\n/**\n * Assert a program definition's always-on construction invariants — missing\n * scope references and duplicate rating-line or notice ids.\n *\n * @remarks\n * These checks run at construction regardless of `options.validate` (unlike\n * {@link validateProgramDefinition}, the standalone report-shaped validator) —\n * an authoring mistake this severe cannot silently compile.\n *\n * @param definition - The program definition to assert\n * @throws {@link ProgramError} `'MISSING'` when a ruling or notice scope names\n * no rating line\n * @throws {@link ProgramError} `'DUPLICATE'` when two rating lines or two\n * notices share an id\n *\n * @example\n * ```ts\n * import { assertProgramDefinition } from '@orkestrel/program'\n *\n * assertProgramDefinition(definition) // does not throw\n * ```\n */\nexport function assertProgramDefinition(definition: ProgramDefinition): void {\n\tconst missing = findMissingScopes(definition)\n\tif (missing.length > 0) {\n\t\tthrow new ProgramError(\n\t\t\t'MISSING',\n\t\t\t`Unknown rating line reference: ${missing.join(', ')}`,\n\t\t\tdefinition.id,\n\t\t)\n\t}\n\tconst duplicateLines = findDuplicates(definition.rating?.lines ?? [])\n\tif (duplicateLines.length > 0) {\n\t\tthrow new ProgramError(\n\t\t\t'DUPLICATE',\n\t\t\t`Duplicate rating line id: ${duplicateLines.join(', ')}`,\n\t\t\tdefinition.id,\n\t\t)\n\t}\n\tconst duplicateNotices = findDuplicates(definition.notices ?? [])\n\tif (duplicateNotices.length > 0) {\n\t\tthrow new ProgramError(\n\t\t\t'DUPLICATE',\n\t\t\t`Duplicate notice id: ${duplicateNotices.join(', ')}`,\n\t\t\tdefinition.id,\n\t\t)\n\t}\n}\n\n/**\n * Validate a program definition's shape, references, and nested definitions.\n *\n * @remarks\n * The single semantic-validation implementation used by `Program.validate`. It\n * establishes exact shape through {@link isProgramDefinition}, validates the\n * rating structurally through the rater's {@link isRatingDefinition} guard (the\n * rater exposes no `validate`), delegates qualification validation to the\n * injected qualifier and authority / aggregate-gate validation to the shared\n * reason engine, and checks scope, notice, and aggregate-field references here.\n *\n * @param definition - The program definition to validate\n * @param qualifier - The qualifier that validates the nested qualification\n * @param engine - The reason engine that validates authority and aggregate gates\n * @returns A structured validation result\n *\n * @example\n * ```ts\n * import { validateProgramDefinition } from '@orkestrel/program'\n *\n * validateProgramDefinition(definition, qualifier, engine) // { valid: true, ... }\n * ```\n */\nexport function validateProgramDefinition(\n\tdefinition: ProgramDefinition,\n\tqualifier: QualifierInterface,\n\tengine: ReasonInterface,\n): ProgramValidationResult {\n\tif (!isProgramDefinition(definition)) {\n\t\treturn { valid: false, errors: ['Program definition has an invalid shape'], warnings: [] }\n\t}\n\n\tconst errors: string[] = []\n\tconst warnings: string[] = []\n\n\tif (definition.id.length === 0) errors.push('Program id must not be empty')\n\tif (definition.name.length === 0) errors.push('Program name must not be empty')\n\n\tconst qualification = qualifier.validate(definition.qualification)\n\tif (isQualificationValidationResult(qualification)) {\n\t\terrors.push(...qualification.errors.map((error) => `qualification: ${error}`))\n\t\twarnings.push(...qualification.warnings.map((warning) => `qualification: ${warning}`))\n\t} else {\n\t\terrors.push('qualification: Qualifier returned invalid validation result')\n\t}\n\n\tconst lines = new Set((definition.rating?.lines ?? []).map((line) => line.id))\n\tif (definition.rating !== undefined && lines.size !== definition.rating.lines.length) {\n\t\terrors.push('rating: duplicate line id')\n\t}\n\tfor (const ruling of definition.qualification.rulings ?? []) {\n\t\tif (ruling.scope !== undefined && !lines.has(ruling.scope)) {\n\t\t\terrors.push(`Qualification ruling \"${ruling.id}\" references missing line \"${ruling.scope}\"`)\n\t\t}\n\t}\n\n\tconst notices = new Set<string>()\n\tfor (const notice of definition.notices ?? []) {\n\t\tif (notices.has(notice.id)) errors.push(`Duplicate notice id \"${notice.id}\"`)\n\t\tnotices.add(notice.id)\n\t\tif (notice.scope !== undefined && !lines.has(notice.scope)) {\n\t\t\terrors.push(`Notice \"${notice.id}\" references missing line \"${notice.scope}\"`)\n\t\t}\n\t}\n\n\tconst authority = definition.authority\n\tif (authority !== undefined) {\n\t\tconst validation = engine.validate(authority)\n\t\tif (isReasonValidationResult(validation)) {\n\t\t\terrors.push(...validation.errors.map((error) => `authority: ${error}`))\n\t\t\twarnings.push(...validation.warnings.map((warning) => `authority: ${warning}`))\n\t\t} else {\n\t\t\terrors.push('authority: Reason engine returned invalid validation result')\n\t\t}\n\t}\n\n\tconst aggregate = definition.aggregate\n\tif (aggregate !== undefined) {\n\t\tconst fields = new Set<string>()\n\t\tfor (const field of aggregate.fields) {\n\t\t\tconst key = formatField(field)\n\t\t\tif (key.length === 0) errors.push('Aggregate fields must be non-empty')\n\t\t\tif (fields.has(key)) errors.push(`Duplicate aggregate field \"${key}\"`)\n\t\t\tfields.add(key)\n\t\t}\n\t\tif (aggregate.by !== undefined && formatField(aggregate.by).length === 0) {\n\t\t\terrors.push('Aggregate partition field must be non-empty')\n\t\t}\n\t\tif (aggregate.gates !== undefined) {\n\t\t\tconst validation = engine.validate(aggregate.gates)\n\t\t\tif (isReasonValidationResult(validation)) {\n\t\t\t\terrors.push(...validation.errors.map((error) => `aggregate: ${error}`))\n\t\t\t\twarnings.push(...validation.warnings.map((warning) => `aggregate: ${warning}`))\n\t\t\t} else {\n\t\t\t\terrors.push('aggregate: Reason engine returned invalid validation result')\n\t\t\t}\n\t\t\tif (aggregate.fields.length === 0) {\n\t\t\t\twarnings.push('Aggregate gates are defined without aggregate fields')\n\t\t\t}\n\t\t}\n\t}\n\n\tif (definition.rating !== undefined && definition.rating.lines.length === 0) {\n\t\twarnings.push('Program rating has no lines')\n\t}\n\n\treturn { valid: errors.length === 0, errors, warnings }\n}\n\n/**\n * Coerce a subject's partition-key field to its group-key string.\n *\n * @remarks\n * The key is the resolved field coerced with `String` — `undefined` collapses\n * to the empty string, so a subject missing the field and a subject whose\n * field is literally `''` land in the SAME partition, and a numeric `1`\n * collides with the string `'1'`.\n *\n * @param subject - The subject to key\n * @param by - The partition key field\n * @returns The subject's group key\n *\n * @example\n * ```ts\n * import { formatGroupKey } from '@orkestrel/program'\n *\n * formatGroupKey({ location: 'east' }, 'location') // 'east'\n * ```\n */\nexport function formatGroupKey(subject: Subject, by: FieldPath): string {\n\treturn String(resolveField(subject, by) ?? '')\n}\n\n/**\n * Fold one subject's finite aggregate field values into a sums record.\n *\n * @remarks\n * Returns a FRESH record — `sums` is never mutated. Only finite numbers\n * contribute; a non-numeric or absent value contributes zero (never a\n * coercion). A {@link FieldPath} may be nested — `formatField` renders the\n * dot-joined key the returned record is keyed by.\n *\n * @param sums - The sums record to fold into\n * @param subject - The subject to fold in\n * @param fields - The fields to sum\n * @returns A fresh sums record with `subject`'s contribution added\n *\n * @example\n * ```ts\n * import { sumFields } from '@orkestrel/program'\n *\n * sumFields({ amount: 0 }, { amount: 5 }, ['amount']) // { amount: 5 }\n * ```\n */\nexport function sumFields(\n\tsums: Readonly<Record<string, number>>,\n\tsubject: Subject,\n\tfields: readonly FieldPath[],\n): Readonly<Record<string, number>> {\n\tconst next: Record<string, number> = { ...sums }\n\tfor (const field of fields) {\n\t\tconst key = formatField(field)\n\t\tconst value = resolveField(subject, field)\n\t\tif (isFiniteNumber(value)) next[key] = (next[key] ?? 0) + value\n\t}\n\treturn next\n}\n\n/**\n * Sum aggregate fields across a batch of subjects.\n *\n * @remarks\n * A {@link FieldPath} may be nested — a nested path sums a nested subject field\n * exactly like a top-level one, and `formatField` renders the dot-joined key the\n * returned record is keyed by. Only finite numbers contribute; a non-numeric or\n * absent value contributes zero (never a coercion).\n *\n * @param subjects - The batch of subjects\n * @param fields - The fields to sum\n * @returns A fresh record of dot-joined field to summed finite value\n *\n * @example\n * ```ts\n * import { aggregateSums } from '@orkestrel/program'\n *\n * aggregateSums([{ amount: 5 }, { amount: 3 }], ['amount']) // { amount: 8 }\n * ```\n */\nexport function aggregateSums(\n\tsubjects: readonly Subject[],\n\tfields: readonly FieldPath[],\n): Readonly<Record<string, number>> {\n\tlet sums = emptySums(fields)\n\tfor (const subject of subjects) sums = sumFields(sums, subject, fields)\n\treturn sums\n}\n\n/**\n * Partition a batch of subjects by a field, summing aggregate fields per key.\n *\n * @remarks\n * The partition key is derived by {@link formatGroupKey}. Group order follows\n * first appearance in the subject array.\n *\n * @param subjects - The batch of subjects\n * @param fields - The fields to sum within each partition\n * @param by - The partition key field; no partition is built when absent\n * @returns A fresh list of aggregate groups, or an empty list when `by` is absent\n *\n * @example\n * ```ts\n * import { aggregateGroups } from '@orkestrel/program'\n *\n * aggregateGroups([{ location: 'east', amount: 5 }], ['amount'], 'location')\n * ```\n */\nexport function aggregateGroups(\n\tsubjects: readonly Subject[],\n\tfields: readonly FieldPath[],\n\tby?: FieldPath,\n): readonly AggregateGroup[] {\n\tif (by === undefined) return []\n\tconst records = new Map<string, Subject[]>()\n\tfor (const subject of subjects) {\n\t\tconst key = formatGroupKey(subject, by)\n\t\tconst group = records.get(key)\n\t\tif (group === undefined) records.set(key, [subject])\n\t\telse group.push(subject)\n\t}\n\treturn [...records.entries()].map(([key, entries]) => ({\n\t\tkey,\n\t\tcount: entries.length,\n\t\tsums: aggregateSums(entries, fields),\n\t}))\n}\n\n/**\n * Build one subject's overall and optional group aggregate projection.\n *\n * @remarks\n * The projection carries the whole-batch `count` and `sums` plus the subject's\n * OWN partition, located by the same {@link formatGroupKey} key\n * {@link aggregateGroups} partitions under.\n *\n * @param subject - The subject to project for\n * @param count - The whole-batch subject count\n * @param sums - The whole-batch summed aggregate fields\n * @param groups - The batch partitions\n * @param by - The partition key field; no group is attached when absent\n * @returns A fresh aggregate projection\n *\n * @example\n * ```ts\n * import { buildAggregateProjection } from '@orkestrel/program'\n *\n * buildAggregateProjection(subject, 2, { amount: 8 }, groups, 'location')\n * ```\n */\nexport function buildAggregateProjection(\n\tsubject: Subject,\n\tcount: number,\n\tsums: Readonly<Record<string, number>>,\n\tgroups: readonly AggregateGroup[],\n\tby?: FieldPath,\n): AggregateProjection {\n\tconst group =\n\t\tby === undefined ? undefined : groups.find((entry) => entry.key === formatGroupKey(subject, by))\n\treturn { count, sums: { ...sums }, ...(group === undefined ? {} : { group }) }\n}\n\n/**\n * Build the reserved-key record a batch aggregate-gate definition runs against.\n *\n * @remarks\n * Unlike a per-subject {@link buildAggregateProjection}, the batch record carries\n * every `group` (a `groups` array) under {@link AGGREGATE_KEY} so a gate rule can\n * read `aggregate.sums.<field>` (overall) or a partition inside `aggregate.groups`.\n *\n * @param count - The whole-batch subject count\n * @param sums - The whole-batch summed aggregate fields\n * @param groups - The batch partitions\n * @returns A fresh record carrying the batch aggregate under {@link AGGREGATE_KEY}\n *\n * @example\n * ```ts\n * import { buildAggregateRecord } from '@orkestrel/program'\n *\n * buildAggregateRecord(2, { amount: 8 }, [])\n * ```\n */\nexport function buildAggregateRecord(\n\tcount: number,\n\tsums: Readonly<Record<string, number>>,\n\tgroups: readonly AggregateGroup[],\n): Readonly<Record<string, unknown>> {\n\treturn { [AGGREGATE_KEY]: { count, sums, groups } }\n}\n\n/**\n * Build a zero-sum record for a set of aggregate fields.\n *\n * @param fields - The fields to zero\n * @returns A fresh record of dot-joined field to `0`\n *\n * @example\n * ```ts\n * import { emptySums } from '@orkestrel/program'\n *\n * emptySums(['amount']) // { amount: 0 }\n * ```\n */\nexport function emptySums(fields: readonly FieldPath[]): Readonly<Record<string, number>> {\n\tconst sums: Record<string, number> = {}\n\tfor (const field of fields) sums[formatField(field)] = 0\n\treturn sums\n}\n\n/**\n * Complete a partial status tally record with zero entries for every missing\n * {@link Status}.\n *\n * @param entries - The partial tally entries to complete\n * @returns A record with all five statuses present\n *\n * @example\n * ```ts\n * import { completeTallies } from '@orkestrel/program'\n *\n * completeTallies({ eligible: { count: 1, sums: {} } })\n * ```\n */\nexport function completeTallies(\n\tentries: Partial<Record<Status, Tally>>,\n): Readonly<Record<Status, Tally>> {\n\treturn {\n\t\tineligible: entries.ineligible ?? { count: 0, sums: {} },\n\t\treferral: entries.referral ?? { count: 0, sums: {} },\n\t\tconditional: entries.conditional ?? { count: 0, sums: {} },\n\t\tunrated: entries.unrated ?? { count: 0, sums: {} },\n\t\teligible: entries.eligible ?? { count: 0, sums: {} },\n\t}\n}\n\n/**\n * Build complete zero status tallies in {@link STATUS_PRECEDENCE} order.\n *\n * @param fields - The fields each tally's sums are zeroed for\n * @returns A fresh, complete tally record\n *\n * @example\n * ```ts\n * import { emptyTallies } from '@orkestrel/program'\n *\n * emptyTallies(['amount'])\n * ```\n */\nexport function emptyTallies(fields: readonly FieldPath[]): Readonly<Record<Status, Tally>> {\n\tconst entries: Partial<Record<Status, Tally>> = {}\n\tfor (const status of STATUS_PRECEDENCE) entries[status] = { count: 0, sums: emptySums(fields) }\n\treturn completeTallies(entries)\n}\n\n/**\n * Add one subject's aggregate contribution to a status tally record.\n *\n * @param tallies - The tallies to update\n * @param result - The subject's program result (its `status` selects the tally)\n * @param subject - The subject to fold in\n * @param fields - The fields to sum\n * @returns A fresh, complete tally record with the subject folded in\n *\n * @example\n * ```ts\n * import { tallyProgram } from '@orkestrel/program'\n *\n * tallyProgram(tallies, result, { id: 'r1', amount: 5 }, ['amount'])\n * ```\n */\nexport function tallyProgram(\n\ttallies: Readonly<Record<Status, Tally>>,\n\tresult: ProgramResult,\n\tsubject: Subject,\n\tfields: readonly FieldPath[],\n): Readonly<Record<Status, Tally>> {\n\tconst status = result.status\n\tconst current = tallies[status]\n\tconst sums = sumFields(current.sums, subject, fields)\n\treturn completeTallies({ ...tallies, [status]: { count: current.count + 1, sums } })\n}\n\n/**\n * Assemble one batch {@link AggregateResult} from its per-subject and aggregate\n * parts.\n *\n * @remarks\n * `count` is the subject count, `trace` / `errors` accumulate every subject's\n * plus the batch aggregate-gate evaluation's (`options.gates`), and `success`\n * requires every subject execution to succeed AND the gate evaluation to have\n * produced no errors. A fired aggregate gate contributes a `limit`\n * determination, never a technical failure (a non-logical gate result is a\n * caller-facing `MISMATCH` thrown by `Program` before this assembles).\n *\n * @param definition - The authored program definition\n * @param subjects - The per-subject program results, in input order\n * @param determinations - The batch aggregate-gate `limit` determinations\n * @param groups - The batch partitions\n * @param tallies - The completed status tallies\n * @param sums - The whole-batch summed aggregate fields\n * @param options - Optional resolved aggregate-gate result\n * @returns A fresh aggregate result\n *\n * @example\n * ```ts\n * import { buildAggregateResult } from '@orkestrel/program'\n *\n * buildAggregateResult(definition, subjects, [], [], tallies, { amount: 8 })\n * ```\n */\nexport function buildAggregateResult(\n\tdefinition: ProgramDefinition,\n\tsubjects: readonly ProgramResult[],\n\tdeterminations: readonly Determination[],\n\tgroups: readonly AggregateGroup[],\n\ttallies: Readonly<Record<Status, Tally>>,\n\tsums: Readonly<Record<string, number>>,\n\toptions?: { readonly gates?: LogicalResult },\n): AggregateResult {\n\tconst gates = options?.gates\n\tconst gateTrace = gates === undefined ? [] : [...gates.trace]\n\tconst gateErrors = gates === undefined ? [] : [...gates.errors]\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tsubjects,\n\t\tdeterminations,\n\t\tgroups,\n\t\ttallies,\n\t\tcount: subjects.length,\n\t\tsums,\n\t\tsuccess: subjects.every((entry) => entry.success) && gateErrors.length === 0,\n\t\ttrace: [...subjects.flatMap((entry) => entry.trace), ...gateTrace],\n\t\terrors: [...subjects.flatMap((entry) => entry.errors), ...gateErrors],\n\t}\n}\n\n/**\n * Build a {@link ProgramDefinition}.\n *\n * @remarks\n * Copies every collection and omits absent optional keys, so the returned\n * definition is a fresh, JSON-serializable value that never aliases its inputs.\n *\n * @param id - The program id\n * @param name - The display name\n * @param qualification - The nested qualification definition\n * @param rating - The nested rating definition; omit for an eligibility-only program\n * @param input - Optional description, notices, authority, aggregate, and metadata\n * @returns A fresh program definition\n *\n * @example\n * ```ts\n * import { programDefinition } from '@orkestrel/program'\n *\n * programDefinition('standard', 'Standard', qualification, rating, { notices: [notice] })\n * ```\n */\nexport function programDefinition(\n\tid: string,\n\tname: string,\n\tqualification: QualificationDefinition,\n\trating?: RatingDefinition,\n\tinput?: ProgramInput,\n): ProgramDefinition {\n\treturn {\n\t\tid,\n\t\tname,\n\t\tqualification,\n\t\t...(rating === undefined ? {} : { rating }),\n\t\t...(input?.description === undefined ? {} : { description: input.description }),\n\t\t...(input?.notices === undefined ? {} : { notices: [...input.notices] }),\n\t\t...(input?.authority === undefined ? {} : { authority: input.authority }),\n\t\t...(input?.aggregate === undefined ? {} : { aggregate: input.aggregate }),\n\t\t...(input?.metadata === undefined ? {} : { metadata: copyJSONValue(input.metadata) }),\n\t}\n}\n\n/**\n * Build a {@link Notice}.\n *\n * @param id - The notice id\n * @param message - The message template, carrying optional `{{token}}`s\n * @param input - Optional presentation scope\n * @returns A fresh notice\n *\n * @example\n * ```ts\n * import { noticeDefinition } from '@orkestrel/program'\n *\n * noticeDefinition('minimum', 'Minimum earned premium applies')\n * ```\n */\nexport function noticeDefinition(id: string, message: string, input?: NoticeInput): Notice {\n\treturn {\n\t\tid,\n\t\tmessage,\n\t\t...(input?.scope === undefined ? {} : { scope: input.scope }),\n\t}\n}\n\n/**\n * Build an {@link AggregateDefinition}.\n *\n * @param fields - The aggregate fields to sum across a batch\n * @param input - Optional partition field and aggregate gates\n * @returns A fresh aggregate definition\n *\n * @example\n * ```ts\n * import { aggregateDefinition } from '@orkestrel/program'\n *\n * aggregateDefinition(['amount'], { by: 'location' })\n * ```\n */\nexport function aggregateDefinition(\n\tfields: readonly FieldPath[],\n\tinput?: AggregateInput,\n): AggregateDefinition {\n\treturn {\n\t\tfields: [...fields],\n\t\t...(input?.by === undefined ? {} : { by: input.by }),\n\t\t...(input?.gates === undefined ? {} : { gates: input.gates }),\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { QualificationResult, QualifierInterface } from '@orkestrel/qualifier'\nimport type { RaterInterface, RatingResult } from '@orkestrel/rater'\nimport type { EvaluatorInterface, LogicalResult, ReasonInterface, Subject } from '@orkestrel/reason'\nimport type {\n\tAggregateGroup,\n\tAggregateProjection,\n\tAggregateResult,\n\tDetermination,\n\tProgramDefinition,\n\tProgramEventMap,\n\tProgramInterface,\n\tProgramOptions,\n\tProgramResult,\n\tProgramValidationResult,\n} from '../types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isArray } from '@orkestrel/contract'\nimport { createQualifier, isQualificationResult } from '@orkestrel/qualifier'\nimport { createRater, isRatingResult } from '@orkestrel/rater'\nimport {\n\tcreateEvaluator,\n\tcreateLogicalReasoner,\n\tcreateQuantitativeReasoner,\n\tcreateReason,\n\tisLogicalResult,\n} from '@orkestrel/reason'\nimport { DEFAULT_PROGRAM_VALIDATE, OUTCOME_KEY } from '../constants.js'\nimport { ProgramError } from '../errors.js'\nimport {\n\taggregateGroups,\n\taggregateSums,\n\tassertProgramDefinition,\n\tassertProgramSubject,\n\tbuildAggregateProjection,\n\tbuildAggregateRecord,\n\tbuildAggregateResult,\n\tbuildLimits,\n\tbuildNotices,\n\tbuildOutcomeProjection,\n\tbuildProgramResult,\n\tbuildQualificationSubject,\n\tderiveStatus,\n\temptyTallies,\n\tselectProgramLines,\n\ttallyProgram,\n\tvalidateProgramDefinition,\n} from '../helpers.js'\n\n/**\n * One compiled program — composes one qualifier and one rater over a shared\n * reason engine and executes single subjects or aggregate-aware batches.\n *\n * @remarks\n * Qualification decides whether rating happens: a globally ineligible, referred,\n * or failed subject never reaches the rater, and a scoped ineligibility removes\n * only its line before the first rating call. The rater always receives the\n * ORIGINAL subject; the qualifier's aggregate projection stays private. When no\n * qualifier, rater, or engine is injected the program creates ONE shared\n * quantitative-plus-logical engine, injects it into the qualifier and rater it\n * creates, and destroys only what it owns. A definition failure during\n * construction (an invalid definition under `options.validate`) tears down\n * whatever the constructor had already allocated before throwing. Construction\n * snapshots the caller's definition once, runs the always-on assertions against\n * that snapshot, and seals its plain-object graph before exposure. A `Map`, `Set`,\n * or `Date` reached through a reason `Check.value` is cloned but remains mutable\n * because its contents live in internal slots. Uncloneable values and non-empty\n * typed arrays are refused with `ProgramError('DEFINITION')` and the host error\n * as its cause. `destroy()` is idempotent and REENTRANCY-SAFE — the destroyed\n * flag is set BEFORE any teardown or the `destroy` event fires, so a listener\n * that re-enters `destroy()` is a no-op — and tears the emitter down last.\n */\nexport class Program implements ProgramInterface {\n\treadonly #emitter: Emitter<ProgramEventMap>\n\treadonly #qualifier: QualifierInterface\n\treadonly #rater: RaterInterface\n\treadonly #engine: ReasonInterface\n\treadonly #evaluator: EvaluatorInterface\n\treadonly #qualifierOwned: boolean\n\treadonly #raterOwned: boolean\n\treadonly #engineOwned: boolean\n\treadonly #validate: boolean\n\treadonly #labels: Readonly<Record<string, string>> | undefined\n\t#destroyed = false\n\n\treadonly id: string\n\treadonly name: string\n\treadonly definition: ProgramDefinition\n\n\tconstructor(definition: ProgramDefinition, options?: ProgramOptions) {\n\t\tlet snapshot: ProgramDefinition\n\t\ttry {\n\t\t\tsnapshot = structuredClone(definition)\n\t\t} catch (cause) {\n\t\t\tconst error = new ProgramError('DEFINITION', 'Program definition could not be cloned')\n\t\t\tObject.defineProperty(error, 'cause', { configurable: true, value: cause, writable: true })\n\t\t\tthrow error\n\t\t}\n\t\tassertProgramDefinition(snapshot)\n\t\tthis.id = snapshot.id\n\t\tthis.name = snapshot.name\n\t\tthis.definition = snapshot\n\t\ttry {\n\t\t\tthis.#seal()\n\t\t} catch (cause) {\n\t\t\tconst error = new ProgramError(\n\t\t\t\t'DEFINITION',\n\t\t\t\t'Program definition could not be sealed',\n\t\t\t\tsnapshot.id,\n\t\t\t)\n\t\t\tObject.defineProperty(error, 'cause', { configurable: true, value: cause, writable: true })\n\t\t\tthrow error\n\t\t}\n\t\tthis.#emitter = new Emitter({\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\tthis.#evaluator = createEvaluator()\n\t\tthis.#engineOwned = options?.engine === undefined\n\t\tthis.#qualifierOwned = options?.qualifier === undefined\n\t\tthis.#raterOwned = options?.rater === undefined\n\t\tthis.#engine =\n\t\t\toptions?.engine ??\n\t\t\tcreateReason({\n\t\t\t\treasoners: [createQuantitativeReasoner(), createLogicalReasoner()],\n\t\t\t\tbail: false,\n\t\t\t})\n\t\tthis.#qualifier = options?.qualifier ?? createQualifier({ engine: this.#engine })\n\t\tthis.#rater = options?.rater ?? createRater({ engine: this.#engine })\n\t\tthis.#validate = options?.validate ?? DEFAULT_PROGRAM_VALIDATE\n\t\tthis.#labels = options?.labels\n\n\t\tif (this.#validate) {\n\t\t\tconst validation = this.validate()\n\t\t\tif (!validation.valid) {\n\t\t\t\tthis.destroy()\n\t\t\t\tthrow new ProgramError('DEFINITION', validation.errors.join('; '), snapshot.id)\n\t\t\t}\n\t\t}\n\t}\n\n\tget emitter(): EmitterInterface<ProgramEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t// Array overload first (AGENTS §9.2) so a subject list resolves to the batch form.\n\texecute(subjects: readonly Subject[]): AggregateResult\n\texecute(subject: Subject): ProgramResult\n\texecute(input: Subject | readonly Subject[]): ProgramResult | AggregateResult {\n\t\tthis.#alive()\n\t\tif (isArray<Subject>(input)) return this.#aggregate(input)\n\t\treturn this.#subject(input)\n\t}\n\n\tvalidate(): ProgramValidationResult {\n\t\tthis.#alive()\n\t\treturn validateProgramDefinition(this.definition, this.#qualifier, this.#engine)\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tif (this.#qualifierOwned) this.#qualifier.destroy()\n\t\tif (this.#raterOwned) this.#rater.destroy()\n\t\tif (this.#engineOwned) this.#engine.destroy()\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#subject(subject: Subject, aggregate?: AggregateProjection): ProgramResult {\n\t\tassertProgramSubject(subject)\n\t\tconst qualified = buildQualificationSubject(subject, aggregate)\n\t\tconst qualification = this.#qualifier.qualify(qualified, this.definition.qualification)\n\t\tif (!isQualificationResult(qualification)) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'MISMATCH',\n\t\t\t\t'Qualifier returned invalid qualification result',\n\t\t\t\tthis.definition.qualification.id,\n\t\t\t)\n\t\t}\n\t\tthis.#emitter.emit('qualify', qualification)\n\n\t\tif (!qualification.success || qualification.eligibility !== 'eligible') {\n\t\t\treturn this.#finish(subject, qualification, undefined)\n\t\t}\n\n\t\tconst lines = selectProgramLines(this.definition.rating?.lines ?? [], qualification.scopes)\n\t\tconst rating = lines.length === 0 ? undefined : this.#rater.rate(lines, subject)\n\t\tif (rating !== undefined) {\n\t\t\tif (!isRatingResult(rating)) {\n\t\t\t\tthrow new ProgramError(\n\t\t\t\t\t'MISMATCH',\n\t\t\t\t\t'Rater returned invalid rating result',\n\t\t\t\t\tthis.definition.rating?.id,\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.#emitter.emit('rate', rating)\n\t\t}\n\n\t\treturn this.#finish(subject, qualification, rating)\n\t}\n\n\t#finish(\n\t\tsubject: Subject,\n\t\tqualification: QualificationResult,\n\t\trating?: RatingResult,\n\t): ProgramResult {\n\t\tconst notices = buildNotices(this.definition.notices ?? [], subject)\n\t\tfor (const notice of notices) this.#emitter.emit('determine', notice)\n\n\t\tconst status = deriveStatus(this.definition, qualification, rating)\n\t\tlet result = buildProgramResult(this.definition, qualification, rating, notices, status)\n\n\t\tconst authority = this.definition.authority\n\t\tif (authority === undefined) {\n\t\t\tthis.#emitter.emit('execute', result)\n\t\t\treturn result\n\t\t}\n\n\t\tconst outcome = { [OUTCOME_KEY]: buildOutcomeProjection(result) }\n\t\tconst resolved = this.#engine.reason(outcome, authority)\n\t\tif (!isLogicalResult(resolved)) {\n\t\t\tthrow new ProgramError('MISMATCH', 'Authority returned invalid logical result', authority.id)\n\t\t}\n\n\t\tconst limits = buildLimits(authority, resolved, outcome, this.#evaluator, this.#labels)\n\t\tfor (const limit of limits) this.#emitter.emit('determine', limit)\n\n\t\tresult = buildProgramResult(\n\t\t\tthis.definition,\n\t\t\tqualification,\n\t\t\trating,\n\t\t\t[...notices, ...limits],\n\t\t\tstatus,\n\t\t\t{ authority: resolved },\n\t\t)\n\n\t\tif (result.decision !== undefined) this.#emitter.emit('decide', result.decision, result)\n\t\tthis.#emitter.emit('execute', result)\n\t\treturn result\n\t}\n\n\t#aggregate(subjects: readonly Subject[]): AggregateResult {\n\t\tfor (const subject of subjects) assertProgramSubject(subject)\n\n\t\tconst definition = this.definition.aggregate\n\t\tconst fields = [...(definition?.fields ?? [])]\n\t\tconst sums = aggregateSums(subjects, fields)\n\t\tconst groups = aggregateGroups(subjects, fields, definition?.by)\n\t\tlet tallies = emptyTallies(fields)\n\t\tconst results = subjects.map((subject) => {\n\t\t\tconst projection =\n\t\t\t\tdefinition === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: buildAggregateProjection(subject, subjects.length, sums, groups, definition.by)\n\t\t\tconst result = this.#subject(subject, projection)\n\t\t\ttallies = tallyProgram(tallies, result, subject, fields)\n\t\t\treturn result\n\t\t})\n\n\t\tconst gates = this.#aggregateLimits(subjects.length, sums, groups)\n\t\tconst result = buildAggregateResult(\n\t\t\tthis.definition,\n\t\t\tresults,\n\t\t\tgates.determinations,\n\t\t\tgroups,\n\t\t\ttallies,\n\t\t\tsums,\n\t\t\tgates.resolved === undefined ? undefined : { gates: gates.resolved },\n\t\t)\n\t\tthis.#emitter.emit('aggregate', result)\n\t\treturn result\n\t}\n\n\t#aggregateLimits(\n\t\tcount: number,\n\t\tsums: Readonly<Record<string, number>>,\n\t\tgroups: readonly AggregateGroup[],\n\t): { readonly determinations: readonly Determination[]; readonly resolved?: LogicalResult } {\n\t\tconst gates = this.definition.aggregate?.gates\n\t\tif (gates === undefined) return { determinations: [] }\n\n\t\tconst record = buildAggregateRecord(count, sums, groups)\n\t\tconst resolved = this.#engine.reason(record, gates)\n\t\tif (!isLogicalResult(resolved)) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'MISMATCH',\n\t\t\t\t'Aggregate gates returned invalid logical result',\n\t\t\t\tgates.id,\n\t\t\t)\n\t\t}\n\n\t\tconst determinations = buildLimits(gates, resolved, record, this.#evaluator, this.#labels)\n\t\tfor (const determination of determinations) this.#emitter.emit('determine', determination)\n\t\treturn { determinations, resolved }\n\t}\n\n\t#alive(): void {\n\t\tif (this.#destroyed) {\n\t\t\tthrow new ProgramError('DESTROYED', 'Program has been destroyed', this.id)\n\t\t}\n\t}\n\n\t#seal(): void {\n\t\tconst pending: object[] = [this.definition]\n\t\twhile (pending.length > 0) {\n\t\t\tconst value = pending.pop()\n\t\t\tif (value === undefined || Object.isFrozen(value)) continue\n\t\t\tObject.freeze(value)\n\t\t\tfor (const child of Object.values(value)) {\n\t\t\t\tif (child !== null && typeof child === 'object') pending.push(child)\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { QualifierInterface } from '@orkestrel/qualifier'\nimport type { RaterInterface } from '@orkestrel/rater'\nimport type { ReasonInterface } from '@orkestrel/reason'\nimport type {\n\tProgramDefinition,\n\tProgramInterface,\n\tProgramManagerEventMap,\n\tProgramManagerInterface,\n\tProgramManagerOptions,\n} from '../types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { createQualifier } from '@orkestrel/qualifier'\nimport { createRater } from '@orkestrel/rater'\nimport { createLogicalReasoner, createQuantitativeReasoner, createReason } from '@orkestrel/reason'\nimport { DEFAULT_PROGRAM_VALIDATE } from '../constants.js'\nimport { ProgramError } from '../errors.js'\nimport { createProgram } from '../factories.js'\n\n/**\n * An ordered manager over compiled {@link ProgramInterface}s (AGENTS §9), sharing\n * one qualifier, rater, and reason engine across every program it compiles.\n *\n * @remarks\n * OWNS its ordered `#programs` collection and its own {@link Emitter} over\n * {@link ProgramManagerEventMap}. Creates or borrows one shared engine, qualifier,\n * and rater and injects the same instances into every compiled program. `remove`\n * destroys the programs it removes; `destroy()` removes all programs, then\n * destroys only the owned shared dependencies, and tears the emitter down LAST.\n * A seed-program failure during construction tears the manager down (destroying\n * whatever had already been compiled) before rethrowing the original error.\n * `destroy()` is REENTRANCY-SAFE — the destroyed flag is set BEFORE any teardown\n * or the `remove` / `destroy` events fire, so a `remove` listener that re-enters\n * `destroy()` is a no-op. Every call after `destroy()` throws {@link ProgramError}\n * `'DESTROYED'`.\n */\nexport class ProgramManager implements ProgramManagerInterface {\n\treadonly #emitter: Emitter<ProgramManagerEventMap>\n\treadonly #programs: ProgramInterface[] = []\n\treadonly #qualifier: QualifierInterface\n\treadonly #rater: RaterInterface\n\treadonly #engine: ReasonInterface\n\treadonly #qualifierOwned: boolean\n\treadonly #raterOwned: boolean\n\treadonly #engineOwned: boolean\n\treadonly #validate: boolean\n\treadonly #labels: Readonly<Record<string, string>> | undefined\n\t#destroyed = false\n\n\tconstructor(options?: ProgramManagerOptions) {\n\t\tthis.#emitter = new Emitter({\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\tthis.#labels = options?.labels\n\t\tthis.#engineOwned = options?.engine === undefined\n\t\tthis.#qualifierOwned = options?.qualifier === undefined\n\t\tthis.#raterOwned = options?.rater === undefined\n\t\tthis.#engine =\n\t\t\toptions?.engine ??\n\t\t\tcreateReason({\n\t\t\t\treasoners: [createQuantitativeReasoner(), createLogicalReasoner()],\n\t\t\t\tbail: false,\n\t\t\t})\n\t\tthis.#qualifier = options?.qualifier ?? createQualifier({ engine: this.#engine })\n\t\tthis.#rater = options?.rater ?? createRater({ engine: this.#engine })\n\t\tthis.#validate = options?.validate ?? DEFAULT_PROGRAM_VALIDATE\n\n\t\ttry {\n\t\t\tfor (const definition of options?.programs ?? []) this.add(definition)\n\t\t} catch (error) {\n\t\t\tthis.destroy()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\tget emitter(): EmitterInterface<ProgramManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget size(): number {\n\t\tthis.#alive()\n\t\treturn this.#programs.length\n\t}\n\n\thas(id: string): boolean {\n\t\tthis.#alive()\n\t\treturn this.#programs.some((program) => program.id === id)\n\t}\n\n\tprogram(id: string): ProgramInterface | undefined {\n\t\tthis.#alive()\n\t\treturn this.#programs.find((program) => program.id === id)\n\t}\n\n\tprograms(): readonly ProgramInterface[] {\n\t\tthis.#alive()\n\t\treturn [...this.#programs]\n\t}\n\n\tadd(definition: ProgramDefinition): ProgramInterface {\n\t\tthis.#alive()\n\t\tif (this.has(definition.id)) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'DUPLICATE',\n\t\t\t\t`Program \"${definition.id}\" already exists`,\n\t\t\t\tdefinition.id,\n\t\t\t)\n\t\t}\n\t\tconst program = createProgram(definition, {\n\t\t\tqualifier: this.#qualifier,\n\t\t\trater: this.#rater,\n\t\t\tengine: this.#engine,\n\t\t\tvalidate: this.#validate,\n\t\t\t...(this.#labels === undefined ? {} : { labels: this.#labels }),\n\t\t})\n\t\tthis.#programs.push(program)\n\t\tthis.#emitter.emit('add', program.id)\n\t\treturn program\n\t}\n\n\t// Array overload first (AGENTS §9.2) so an id list resolves to the batch form.\n\tremove(ids: readonly string[]): boolean\n\tremove(id: string): boolean\n\tremove(): void\n\tremove(input?: string | readonly string[]): boolean | void {\n\t\tthis.#alive()\n\t\tif (input === undefined) {\n\t\t\tthis.#drain()\n\t\t\treturn\n\t\t}\n\t\tif (Array.isArray(input)) {\n\t\t\tlet removed = true\n\t\t\tfor (const id of input) removed = this.#removeOne(id) && removed\n\t\t\treturn removed\n\t\t}\n\t\tif (typeof input === 'string') return this.#removeOne(input)\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tthis.#drain()\n\t\tif (this.#qualifierOwned) this.#qualifier.destroy()\n\t\tif (this.#raterOwned) this.#rater.destroy()\n\t\tif (this.#engineOwned) this.#engine.destroy()\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#drain(): void {\n\t\tfor (const program of this.#programs.splice(0)) {\n\t\t\tprogram.destroy()\n\t\t\tthis.#emitter.emit('remove', program.id)\n\t\t}\n\t}\n\n\t#removeOne(id: string): boolean {\n\t\tconst index = this.#programs.findIndex((program) => program.id === id)\n\t\tif (index < 0) return false\n\t\tconst removed = this.#programs.splice(index, 1)[0]\n\t\tif (removed === undefined) return false\n\t\tremoved.destroy()\n\t\tthis.#emitter.emit('remove', removed.id)\n\t\treturn true\n\t}\n\n\t#alive(): void {\n\t\tif (this.#destroyed) {\n\t\t\tthrow new ProgramError('DESTROYED', 'Program manager has been destroyed')\n\t\t}\n\t}\n}\n","import type {\n\tProgramDefinition,\n\tProgramInterface,\n\tProgramManagerInterface,\n\tProgramManagerOptions,\n\tProgramOptions,\n} from './types.js'\nimport { Program } from './programs/Program.js'\nimport { ProgramManager } from './programs/ProgramManager.js'\n\n/**\n * Create one compiled program over a qualifier and rater.\n *\n * @remarks\n * Validates the definition at construction when `options.validate` is left at\n * its {@link DEFAULT_PROGRAM_VALIDATE} default. A standalone program creates and\n * OWNS one shared quantitative-plus-logical reason engine and injects it into the\n * qualifier and rater it creates; injected dependencies remain caller-owned.\n *\n * @param definition - The authored program definition\n * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks\n * @returns A {@link ProgramInterface}\n *\n * @example\n * ```ts\n * import { createProgram, programDefinition } from '@orkestrel/program'\n *\n * const program = createProgram(programDefinition('standard', 'Standard', qualification, rating))\n * program.execute({ id: 'risk-1' })\n * program.destroy()\n * ```\n */\nexport function createProgram(\n\tdefinition: ProgramDefinition,\n\toptions?: ProgramOptions,\n): ProgramInterface {\n\treturn new Program(definition, options)\n}\n\n/**\n * Create one ordered manager over compiled programs.\n *\n * @remarks\n * Creates or borrows one shared reason engine, qualifier, and rater and injects\n * them into every compiled program, so a batch of definitions shares one engine.\n * Seed definitions are compiled in order.\n *\n * @param options - Optional injected qualifier, rater, engine, seed programs, validation, labels, and emitter hooks\n * @returns A {@link ProgramManagerInterface}\n *\n * @example\n * ```ts\n * import { createProgramManager } from '@orkestrel/program'\n *\n * const manager = createProgramManager({ programs: [definition] })\n * manager.program('standard')?.execute(subject)\n * manager.destroy()\n * ```\n */\nexport function createProgramManager(options?: ProgramManagerOptions): ProgramManagerInterface {\n\treturn new ProgramManager(options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/programs/Program.ts","../../../src/core/programs/ProgramManager.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { Decision } from './types.js'\nimport type { Eligibility } from '@orkestrel/qualifier'\n\n/**\n * Names the default definition validation policy, `true`, for `createProgram` /\n * `ProgramManager.add`.\n */\nexport const DEFAULT_PROGRAM_VALIDATE = true\n\n/**\n * Lists every {@link Status} literal in tally order — the source the union and its\n * guard derive from.\n */\nexport const STATUSES = Object.freeze([\n\t'ineligible',\n\t'referral',\n\t'conditional',\n\t'unrated',\n\t'eligible',\n] as const)\n\n/** Maps each global eligibility to its deterministic authority decision. */\nexport const ELIGIBILITY_DECISIONS: Readonly<Record<Eligibility, Decision>> = Object.freeze({\n\teligible: 'approved',\n\tineligible: 'denied',\n\treferral: 'submitted',\n})\n\n/**\n * Names the reserved working-subject key a batch's aggregate projection is written\n * under, `'aggregate'`.\n */\nexport const AGGREGATE_KEY = 'aggregate'\n\n/**\n * Names the reserved working-subject key the authority's outcome projection is\n * written under, `'outcome'`.\n */\nexport const OUTCOME_KEY = 'outcome'\n","import type { ProgramErrorCode } from './types.js'\n\n/**\n * Reports a coded programmer error thrown by the program layer, carrying a\n * machine-readable code and an optional context and cause.\n *\n * @remarks\n * `DUPLICATE` — a program id collision on `ProgramManager.add`, or a duplicate\n * authored rating-line or notice id. `MISSING` — an authored notice or\n * qualification ruling scope names no rating line.\n * `DEFINITION` — a program, qualification, rating, authority, or aggregate\n * policy failed validation. `MISMATCH` — an injected entity or a returned\n * reason result has the wrong contract. `RESERVED` — a subject already\n * carries `aggregate` or `outcome`. `DESTROYED` — use of a destroyed entity.\n *\n * @example\n * ```ts\n * import { ProgramError } from '@orkestrel/program'\n *\n * const error = new ProgramError('RESERVED', 'Subject carries a reserved key', 'aggregate')\n * error.code // 'RESERVED'\n * ```\n */\nexport class ProgramError extends Error {\n\treadonly code: ProgramErrorCode\n\treadonly context?: unknown\n\n\t/**\n\t * Creates a coded program error.\n\t *\n\t * @param code - The machine-readable failure category\n\t * @param message - The human-readable failure description\n\t * @param context - Optional structured context for the failure\n\t * @param cause - Optional underlying value the failure wraps\n\t */\n\tconstructor(code: ProgramErrorCode, message: string, context?: unknown, cause?: unknown) {\n\t\tsuper(message, cause === undefined ? undefined : { cause })\n\t\tthis.name = 'ProgramError'\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/**\n * Determines whether a caught value is a {@link ProgramError}.\n *\n * @param value - The candidate value\n * @returns True if the value is a {@link ProgramError}; false otherwise\n *\n * @example\n * ```ts\n * import { isProgramError, ProgramError } from '@orkestrel/program'\n *\n * isProgramError(new ProgramError('RESERVED', 'Subject carries a reserved key')) // true\n * isProgramError(new Error('Subject carries a reserved key')) // false\n * ```\n */\nexport function isProgramError(value: unknown): value is ProgramError {\n\treturn value instanceof ProgramError\n}\n","import type { Guard } from '@orkestrel/contract'\nimport type {\n\tAggregateGroup,\n\tAggregateDefinition,\n\tAggregateResult,\n\tDecision,\n\tDetermination,\n\tNotice,\n\tProgramDefinition,\n\tProgramEffect,\n\tProgramResult,\n\tProgramValidationResult,\n\tStatus,\n\tTally,\n} from './types.js'\nimport {\n\tarrayOf,\n\tisBoolean,\n\tisJSONValue,\n\tisNumber,\n\tisString,\n\tliteralOf,\n\tobjectOf,\n\trecordOf,\n\twhereOf,\n} from '@orkestrel/contract'\nimport {\n\tisEligibility,\n\tisPremise,\n\tisQualificationDefinition,\n\tisQualificationResult,\n} from '@orkestrel/qualifier'\nimport { isRatingDefinition, isRatingResult } from '@orkestrel/rater'\nimport { isFieldPath, isLogicalDefinition } from '@orkestrel/reason'\nimport { STATUSES } from './constants.js'\n\n/**\n * Determines whether a value is a {@link Decision} literal.\n *\n * @param value - The candidate value\n * @returns True if `value` is a {@link Decision}; false otherwise\n *\n * @example\n * ```ts\n * import { isDecision } from '@orkestrel/program'\n *\n * isDecision('approved') // true\n * ```\n */\nexport const isDecision: Guard<Decision> = literalOf('approved', 'denied', 'submitted')\n\n/**\n * Determines whether a value is a {@link Status} literal.\n *\n * @param value - The candidate value\n * @returns True if `value` is a {@link Status}; false otherwise\n *\n * @example\n * ```ts\n * import { isStatus } from '@orkestrel/program'\n *\n * isStatus('eligible') // true\n * ```\n */\nexport const isStatus: Guard<Status> = literalOf(STATUSES)\n\n/**\n * Determines whether a value is a {@link ProgramEffect} literal.\n *\n * @param value - The candidate value\n * @returns True if `value` is a {@link ProgramEffect}; false otherwise\n *\n * @example\n * ```ts\n * import { isProgramEffect } from '@orkestrel/program'\n *\n * isProgramEffect('notice') // true\n * ```\n */\nexport const isProgramEffect: Guard<ProgramEffect> = literalOf('notice', 'limit')\n\n/**\n * Determines whether a value is an exact {@link Notice} record.\n *\n * @param value - The candidate value\n * @returns True if `value` is a {@link Notice}; false otherwise\n *\n * @example\n * ```ts\n * import { isNotice } from '@orkestrel/program'\n *\n * isNotice({ id: 'minimum', message: 'Minimum applies' }) // true\n * ```\n */\nexport function isNotice(value: unknown): value is Notice {\n\treturn recordOf({ id: isString, message: isString, scope: isString }, ['scope'])(value)\n}\n\n/**\n * Determines whether a value is an exact {@link AggregateDefinition} record.\n *\n * @param value - The candidate value\n * @returns True if `value` is an {@link AggregateDefinition}; false otherwise\n *\n * @example\n * ```ts\n * import { isAggregateDefinition } from '@orkestrel/program'\n *\n * isAggregateDefinition({ fields: ['amount'] }) // true\n * ```\n */\nexport function isAggregateDefinition(value: unknown): value is AggregateDefinition {\n\treturn recordOf(\n\t\t{ fields: arrayOf(isFieldPath), partition: isFieldPath, gates: isLogicalDefinition },\n\t\t['partition', 'gates'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an exact {@link ProgramDefinition} record.\n *\n * @remarks\n * `rating` is optional — an omitted `rating` authors an eligibility-only\n * program (see {@link ProgramDefinition}).\n *\n * @param value - The candidate value\n * @returns True if `value` is a {@link ProgramDefinition}; false otherwise\n *\n * @example\n * ```ts\n * import { isProgramDefinition } from '@orkestrel/program'\n *\n * isProgramDefinition({ id: 'p', name: 'P', qualification }) // true\n * ```\n */\nexport function isProgramDefinition(value: unknown): value is ProgramDefinition {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isString,\n\t\t\tname: isString,\n\t\t\tdescription: isString,\n\t\t\tqualification: isQualificationDefinition,\n\t\t\trating: isRatingDefinition,\n\t\t\tnotices: arrayOf(isNotice),\n\t\t\tauthority: isLogicalDefinition,\n\t\t\taggregate: isAggregateDefinition,\n\t\t\tmetadata: isJSONValue,\n\t\t},\n\t\t['description', 'rating', 'notices', 'authority', 'aggregate', 'metadata'],\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open program sums record.\n *\n * @remarks\n * Every own string-named property is checked, including non-enumerable\n * properties. Inherited and symbol-named members are outside the record this\n * guard certifies. Values remain plain JavaScript numbers, including `NaN` and\n * infinities, because the published contract does not refine them.\n *\n * @param value - The candidate value\n * @returns True if every own string-named value is a number; false otherwise\n *\n * @example\n * ```ts\n * import { isProgramSums } from '@orkestrel/program'\n *\n * isProgramSums({ premium: 100 }) // true\n * ```\n */\nexport function isProgramSums(value: unknown): value is Readonly<Record<string, number>> {\n\treturn whereOf(objectOf({}), (record) =>\n\t\tObject.getOwnPropertyNames(record).every((key) => isNumber(Reflect.get(record, key))),\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open result-side {@link Determination}.\n *\n * @remarks\n * Unknown members and class instances are admitted. Arrays are refused.\n * Optional `scope` and `message` members may be absent or `undefined`.\n *\n * @param value - The candidate value\n * @returns True if every published determination member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isDetermination } from '@orkestrel/program'\n *\n * isDetermination({ id: 'audit', effect: 'notice', applied: true, premises: [] }) // true\n * ```\n */\nexport const isDetermination: Guard<Determination> = objectOf(\n\t{\n\t\tid: isString,\n\t\teffect: isProgramEffect,\n\t\tapplied: isBoolean,\n\t\tscope: isString,\n\t\tmessage: isString,\n\t\tpremises: arrayOf(isPremise),\n\t},\n\t['scope', 'message'],\n)\n\n/**\n * Determines whether a value is an open result-side {@link AggregateGroup}.\n *\n * @remarks\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns True if every published aggregate-group member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isAggregateGroup } from '@orkestrel/program'\n *\n * isAggregateGroup({ key: 'east', count: 1, sums: { premium: 100 } }) // true\n * ```\n */\nexport const isAggregateGroup: Guard<AggregateGroup> = objectOf({\n\tkey: isString,\n\tcount: isNumber,\n\tsums: isProgramSums,\n})\n\n/**\n * Determines whether a value is an open result-side {@link Tally}.\n *\n * @remarks\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns True if every published tally member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isTally } from '@orkestrel/program'\n *\n * isTally({ count: 1, sums: { premium: 100 } }) // true\n * ```\n */\nexport const isTally: Guard<Tally> = objectOf({ count: isNumber, sums: isProgramSums })\n\n/**\n * Determines whether a value is a total open status-tally record.\n *\n * @remarks\n * Every {@link Status} in {@link STATUSES} is required and checked.\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns True if every required status member is a {@link Tally}; false otherwise\n *\n * @example\n * ```ts\n * import { buildEmptyTallies, isTallies } from '@orkestrel/program'\n *\n * isTallies(buildEmptyTallies([])) // true\n * ```\n */\nexport function isTallies(value: unknown): value is Readonly<Record<Status, Tally>> {\n\treturn whereOf(objectOf({}), (record) =>\n\t\tSTATUSES.every((status) => isTally(Reflect.get(record, status))),\n\t)(value)\n}\n\n/**\n * Determines whether a value is an open {@link ProgramResult}.\n *\n * @remarks\n * This guard is result-postured for values returned through a borrowed\n * {@link ProgramInterface}. It admits unknown members and class instances while\n * composing qualifier's `isQualificationResult` and rater's `isRatingResult`\n * over their complete nested result closures. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns True if every published program-result member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isProgramResult } from '@orkestrel/program'\n *\n * isProgramResult(program.execute(subject)) // true\n * ```\n */\nexport const isProgramResult: Guard<ProgramResult> = objectOf(\n\t{\n\t\tid: isString,\n\t\tname: isString,\n\t\teligibility: isEligibility,\n\t\tstatus: isStatus,\n\t\tdecision: isDecision,\n\t\tqualification: isQualificationResult,\n\t\trating: isRatingResult,\n\t\tdeterminations: arrayOf(isDetermination),\n\t\tsuccess: isBoolean,\n\t\ttrace: arrayOf(isString),\n\t\terrors: arrayOf(isString),\n\t},\n\t['decision', 'rating'],\n)\n\n/**\n * Determines whether a value is an open {@link AggregateResult}.\n *\n * @remarks\n * This guard is result-postured for values returned through a borrowed\n * {@link ProgramInterface}. It admits unknown members and class instances while\n * checking every nested program result, determination, group, total tally\n * record, and sums record. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns True if every published aggregate-result member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isAggregateResult } from '@orkestrel/program'\n *\n * isAggregateResult(program.execute(subjects)) // true\n * ```\n */\nexport const isAggregateResult: Guard<AggregateResult> = objectOf({\n\tid: isString,\n\tname: isString,\n\tsubjects: arrayOf(isProgramResult),\n\tdeterminations: arrayOf(isDetermination),\n\tgroups: arrayOf(isAggregateGroup),\n\ttallies: isTallies,\n\tcount: isNumber,\n\tsums: isProgramSums,\n\tsuccess: isBoolean,\n\ttrace: arrayOf(isString),\n\terrors: arrayOf(isString),\n})\n\n/**\n * Determines whether a value is an open {@link ProgramValidationResult}.\n *\n * @remarks\n * `ProgramValidationResult` is this package's own declared interface, not an\n * alias of reason's validation result. This guard therefore checks the\n * program-owned members directly so the contracts may evolve independently.\n * Unknown members and class instances are admitted. Arrays are refused.\n *\n * @param value - The candidate value\n * @returns True if every published program-validation member conforms; false otherwise\n *\n * @example\n * ```ts\n * import { isProgramValidationResult } from '@orkestrel/program'\n *\n * isProgramValidationResult({ valid: true, errors: [], warnings: [] }) // true\n * ```\n */\nexport const isProgramValidationResult: Guard<ProgramValidationResult> = objectOf({\n\tvalid: isBoolean,\n\terrors: arrayOf(isString),\n\twarnings: arrayOf(isString),\n})\n","import type { FieldPath } from '@orkestrel/contract'\nimport type {\n\tEligibility,\n\tQualificationDefinition,\n\tQualificationResult,\n\tQualifierInterface,\n} from '@orkestrel/qualifier'\nimport type { LineDefinition, RatingDefinition, RatingResult } from '@orkestrel/rater'\nimport type {\n\tEvaluatorInterface,\n\tLogicalDefinition,\n\tLogicalResult,\n\tReasonInterface,\n\tSubject,\n} from '@orkestrel/reason'\nimport type {\n\tAggregateDefinition,\n\tAggregateGroup,\n\tAggregateInput,\n\tAggregateProjection,\n\tAggregateResult,\n\tDecision,\n\tDetermination,\n\tNotice,\n\tNoticeInput,\n\tProgramDefinition,\n\tProgramInput,\n\tProgramResult,\n\tProgramValidationResult,\n\tStatus,\n\tTally,\n} from './types.js'\nimport { isFiniteNumber, isRecord, resolveField } from '@orkestrel/contract'\nimport { findRule, interpolateMessage, ruleToPremises } from '@orkestrel/qualifier'\nimport { findDuplicates, formatField, isReasonValidationResult } from '@orkestrel/reason'\nimport { AGGREGATE_KEY, ELIGIBILITY_DECISIONS, OUTCOME_KEY, STATUSES } from './constants.js'\nimport { ProgramError } from './errors.js'\nimport { isProgramDefinition } from './validators.js'\n\n/**\n * Determines whether a caller subject already carries a reserved program key.\n *\n * @remarks\n * `aggregate` and `outcome` are program-private working-subject namespaces — the\n * batch aggregate projection and the authority outcome projection are written\n * under them. A caller subject that already owns either key would silently\n * collide with a projection, so it is rejected before qualification.\n *\n * @param subject - The caller subject to check\n * @returns True if the subject owns `aggregate` or `outcome`; false otherwise\n *\n * @example\n * ```ts\n * import { hasReservedKey } from '@orkestrel/program'\n *\n * hasReservedKey({ id: 'r1' }) // false\n * hasReservedKey({ id: 'r1', aggregate: {} }) // true\n * ```\n */\nexport function hasReservedKey(subject: Readonly<Record<string, unknown>>): boolean {\n\treturn Object.hasOwn(subject, AGGREGATE_KEY) || Object.hasOwn(subject, OUTCOME_KEY)\n}\n\n/**\n * Asserts a value is a valid program {@link Subject}, narrowing it in place.\n *\n * @param subject - The candidate subject to validate\n * @throws {@link ProgramError} Thrown when the value is not a record (`'MISMATCH'`).\n * @throws {@link ProgramError} Thrown when the value already carries the `aggregate`\n * or `outcome` key (`'RESERVED'`).\n *\n * @example\n * ```ts\n * import { assertProgramSubject } from '@orkestrel/program'\n *\n * assertProgramSubject({ id: 'r1' }) // does not throw\n * ```\n */\nexport function assertProgramSubject(subject: unknown): asserts subject is Subject {\n\tif (!isRecord(subject)) {\n\t\tthrow new ProgramError('MISMATCH', 'Program subject must be a record')\n\t}\n\tif (hasReservedKey(subject)) {\n\t\tconst key = Object.hasOwn(subject, AGGREGATE_KEY) ? AGGREGATE_KEY : OUTCOME_KEY\n\t\tthrow new ProgramError('RESERVED', `Subject contains a reserved program key '${key}'`, key)\n\t}\n}\n\n/**\n * Selects the rating lines a subject may be rated on from scoped eligibility.\n *\n * @remarks\n * A scope names a rating-line id. A line survives when its scope is absent\n * (eligible by default), `eligible`, or a `condition` (which is not an\n * eligibility value and never appears here). A scoped `ineligible` or `referral`\n * removes the line before the rater is invoked — the excluded line is never\n * evaluated merely to discard its amount.\n *\n * @param lines - The program's authored rating lines\n * @param scopes - The qualification's per-scope eligibility\n * @returns The surviving line definitions, in authored order\n *\n * @example\n * ```ts\n * import { selectProgramLines } from '@orkestrel/program'\n *\n * selectProgramLines(lines, { wind: 'ineligible' }) // every line except 'wind'\n * ```\n */\nexport function selectProgramLines(\n\tlines: readonly LineDefinition[],\n\tscopes: Readonly<Record<string, Eligibility>>,\n): readonly LineDefinition[] {\n\treturn lines.filter((line) => {\n\t\tconst eligibility = scopes[line.id]\n\t\treturn eligibility !== 'ineligible' && eligibility !== 'referral'\n\t})\n}\n\n/**\n * Derives the final program {@link Status} from a definition's rating policy and\n * qualification/rating evidence.\n *\n * @remarks\n * Explicit policy, not an opaque precedence reduce: global\n * ineligibility or referral is terminal; a scoped referral yields `referral`;\n * an applied `condition` or an applied scoped `restriction` (a line was\n * removed but others rated) is `conditional`. When the definition omits\n * `rating` the program is eligibility-only — status resolves to `conditional`\n * or `eligible` and is never `unrated`. Otherwise a subject with no successful\n * rating is `unrated`.\n *\n * @param definition - The authored program definition\n * @param qualification - The subject's qualification result\n * @param rating - The subject's rating result, when rating occurred\n * @returns The derived status\n *\n * @example\n * ```ts\n * import { deriveStatus } from '@orkestrel/program'\n *\n * deriveStatus(definition, qualification, rating) // 'eligible'\n * ```\n */\nexport function deriveStatus(\n\tdefinition: ProgramDefinition,\n\tqualification: QualificationResult,\n\trating?: RatingResult,\n): Status {\n\tif (qualification.eligibility === 'ineligible') return 'ineligible'\n\tif (qualification.eligibility === 'referral') return 'referral'\n\tif (Object.values(qualification.scopes).includes('referral')) return 'referral'\n\tconst conditional = qualification.findings.some(\n\t\t(finding) =>\n\t\t\tfinding.applied &&\n\t\t\t(finding.effect === 'condition' ||\n\t\t\t\t(finding.scope !== undefined && finding.effect === 'restriction')),\n\t)\n\tif (definition.rating === undefined) return conditional ? 'conditional' : 'eligible'\n\tif (rating === undefined || rating.lines.length === 0 || !rating.success) return 'unrated'\n\treturn conditional ? 'conditional' : 'eligible'\n}\n\n/**\n * Maps a global {@link Eligibility} to its deterministic authority {@link Decision}.\n *\n * @param eligibility - The global eligibility\n * @returns The matching decision\n *\n * @example\n * ```ts\n * import { decideEligibility } from '@orkestrel/program'\n *\n * decideEligibility('eligible') // 'approved'\n * decideEligibility('referral') // 'submitted'\n * ```\n */\nexport function decideEligibility(eligibility: Eligibility): Decision {\n\treturn ELIGIBILITY_DECISIONS[eligibility]\n}\n\n/**\n * Resolves authored {@link Notice} values into unconditionally-applied `notice`\n * {@link Determination} values.\n *\n * @remarks\n * Notices are program output only — they never affect eligibility, status, line\n * selection, or the decision. Each message interpolates against the original\n * subject.\n *\n * @param notices - The authored notices\n * @param subject - The original subject notices interpolate against\n * @returns A fresh list of notice determinations\n *\n * @example\n * ```ts\n * import { buildNoticeDeterminations } from '@orkestrel/program'\n *\n * buildNoticeDeterminations([{ id: 'min', message: 'Minimum applies' }], { id: 'r1' })\n * ```\n */\nexport function buildNoticeDeterminations(\n\tnotices: readonly Notice[],\n\tsubject: Readonly<Record<string, unknown>>,\n): readonly Determination[] {\n\treturn notices.map((notice) => ({\n\t\tid: notice.id,\n\t\teffect: 'notice',\n\t\tapplied: true,\n\t\t...(notice.scope === undefined ? {} : { scope: notice.scope }),\n\t\tmessage: interpolateMessage(notice.message, subject),\n\t\tpremises: [],\n\t}))\n}\n\n/**\n * Converts a logical result's applied rules into `limit` {@link Determination} values.\n *\n * @remarks\n * Fires for both the per-subject authority and the batch aggregate gates — both\n * are plain {@link LogicalDefinition} definitions with no program-authored ruling map, so a\n * fired rule's own `description` (from `@orkestrel/reason`) is the message\n * template, interpolated against the working record the definition ran against.\n * Rich premises reuse the qualifier's {@link ruleToPremises}. A rule that never\n * fires produces no determination — program has no authored ruling map to keep\n * evidence for.\n *\n * @param definition - The authority or aggregate-gate logical definition\n * @param result - The evaluated logical result\n * @param working - The working record the definition ran against\n * @param evaluator - The shared reason check evaluator\n * @param labels - Optional field-to-label overrides, keyed by dot-joined field\n * @returns A fresh list of `limit` determinations\n *\n * @example\n * ```ts\n * import { buildLimitDeterminations } from '@orkestrel/program'\n *\n * buildLimitDeterminations(authority, resolved, outcome, evaluator)\n * ```\n */\nexport function buildLimitDeterminations(\n\tdefinition: LogicalDefinition,\n\tresult: LogicalResult,\n\tworking: Readonly<Record<string, unknown>>,\n\tevaluator: EvaluatorInterface,\n\tlabels?: Readonly<Record<string, string>>,\n): readonly Determination[] {\n\tconst output: Determination[] = []\n\tfor (const entry of result.rules) {\n\t\tif (!entry.applied) continue\n\t\tconst rule = findRule(definition, entry.id)\n\t\tif (rule === undefined) continue\n\t\toutput.push({\n\t\t\tid: entry.id,\n\t\t\teffect: 'limit',\n\t\t\tapplied: true,\n\t\t\t...(rule.description === undefined\n\t\t\t\t? {}\n\t\t\t\t: { message: interpolateMessage(rule.description, working) }),\n\t\t\tpremises: ruleToPremises(rule, working, evaluator, labels),\n\t\t})\n\t}\n\treturn output\n}\n\n/**\n * Builds the private authority outcome projection from an assembled program result.\n *\n * @remarks\n * The authority reads this record under {@link OUTCOME_KEY}; it never receives\n * the mutable internal state of either sibling engine. `total` is carried from\n * the nested rating result when rating occurred.\n *\n * @param result - The preliminary program result computed before authority runs\n * @returns A record shaped for the authority's `outcome` projection\n *\n * @example\n * ```ts\n * import { buildOutcomeProjection } from '@orkestrel/program'\n *\n * buildOutcomeProjection(result) // { id, eligibility, status, rated, scopes }\n * ```\n */\nexport function buildOutcomeProjection(result: ProgramResult): Readonly<Record<string, unknown>> {\n\tconst total = result.rating?.total\n\treturn {\n\t\tid: result.id,\n\t\teligibility: result.eligibility,\n\t\tstatus: result.status,\n\t\trated: result.rating !== undefined,\n\t\t...(total === undefined ? {} : { total }),\n\t\tscopes: { ...result.qualification.scopes },\n\t}\n}\n\n/**\n * Assembles a {@link ProgramResult} from its qualification, rating, and\n * determination parts — before or after authority.\n *\n * @remarks\n * `eligibility` mirrors the qualification. `success` is execution integrity: the\n * qualification succeeded, rating (when it ran) succeeded, and authority (when it\n * ran) produced no errors — a valid ineligible or referral outcome still\n * succeeds. `trace` and `errors` accumulate the qualification's, every rated\n * line's worksheet trail, and the authority's. A `decision` is present only when\n * an authority ran (`options.authority`), the execution succeeded (`success`),\n * no `limit` determination applied, and status is not `unrated`.\n *\n * @param definition - The authored program definition\n * @param qualification - The subject's qualification result\n * @param rating - The subject's rating result, when rating occurred\n * @param determinations - The program-scoped determinations (notices, then limits)\n * @param status - The already-derived status\n * @param options - Optional authority result driving the decision projection\n * @returns A fresh program result\n *\n * @example\n * ```ts\n * import { buildProgramResult } from '@orkestrel/program'\n *\n * buildProgramResult(definition, qualification, rating, [], 'eligible')\n * ```\n */\nexport function buildProgramResult(\n\tdefinition: ProgramDefinition,\n\tqualification: QualificationResult,\n\trating: RatingResult | undefined,\n\tdeterminations: readonly Determination[],\n\tstatus: Status,\n\toptions?: { readonly authority?: LogicalResult },\n): ProgramResult {\n\tconst authority = options?.authority\n\tconst ratingTrace =\n\t\trating === undefined ? [] : rating.lines.flatMap((line) => line.worksheet.trace)\n\tconst ratingErrors =\n\t\trating === undefined ? [] : rating.lines.flatMap((line) => line.worksheet.errors)\n\tconst authorityTrace = authority === undefined ? [] : [...authority.trace]\n\tconst authorityErrors = authority === undefined ? [] : [...authority.errors]\n\tconst trace = [...qualification.trace, ...ratingTrace, ...authorityTrace]\n\tconst errors = [...qualification.errors, ...ratingErrors, ...authorityErrors]\n\tconst success =\n\t\tqualification.success &&\n\t\t(rating === undefined || rating.success) &&\n\t\tauthorityErrors.length === 0\n\tconst limited = determinations.some((entry) => entry.effect === 'limit' && entry.applied)\n\tconst decision =\n\t\tauthority !== undefined && success && !limited && status !== 'unrated'\n\t\t\t? decideEligibility(qualification.eligibility)\n\t\t\t: undefined\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\teligibility: qualification.eligibility,\n\t\tstatus,\n\t\t...(decision === undefined ? {} : { decision }),\n\t\tqualification,\n\t\t...(rating === undefined ? {} : { rating }),\n\t\tdeterminations,\n\t\tsuccess,\n\t\ttrace,\n\t\terrors,\n\t}\n}\n\n/**\n * Adds optional aggregate context to a private subject copy for qualification.\n *\n * @remarks\n * The original subject is returned unchanged when no aggregate context exists.\n * When context exists the helper creates a private copy under {@link AGGREGATE_KEY}\n * and defensively copies every nested record — the rater still receives the\n * original subject, never this copy.\n *\n * @param subject - The original caller subject\n * @param aggregate - The subject's aggregate projection, when a batch supplies one\n * @returns The subject, or a private copy carrying the aggregate projection\n *\n * @example\n * ```ts\n * import { buildQualificationSubject } from '@orkestrel/program'\n *\n * buildQualificationSubject({ id: 'r1' }) // { id: 'r1' }\n * ```\n */\nexport function buildQualificationSubject(\n\tsubject: Subject,\n\taggregate?: AggregateProjection,\n): Subject {\n\tif (aggregate === undefined) return subject\n\treturn {\n\t\t...subject,\n\t\t[AGGREGATE_KEY]: {\n\t\t\tcount: aggregate.count,\n\t\t\tsums: { ...aggregate.sums },\n\t\t\t...(aggregate.group === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tgroup: {\n\t\t\t\t\t\t\tkey: aggregate.group.key,\n\t\t\t\t\t\t\tcount: aggregate.group.count,\n\t\t\t\t\t\t\tsums: { ...aggregate.group.sums },\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t},\n\t}\n}\n\n/**\n * Returns authored scopes (qualification ruling scopes or notice scopes) that\n * name no rating line on the program.\n *\n * @remarks\n * A scope is an opaque string to the qualifier — program alone matches it to a\n * rating-line id. A scope naming no line is a hard authoring error surfaced as\n * {@link ProgramError} `'MISSING'` at construction, regardless of the validate\n * option.\n *\n * @param definition - The program definition to check\n * @returns A fresh, deduped list of missing scope references\n *\n * @example\n * ```ts\n * import { findMissingScopes } from '@orkestrel/program'\n *\n * findMissingScopes(definition) // []\n * ```\n */\nexport function findMissingScopes(definition: ProgramDefinition): readonly string[] {\n\tconst ids = new Set((definition.rating?.lines ?? []).map((line) => line.id))\n\tconst missing = new Set<string>()\n\tfor (const ruling of definition.qualification.rulings ?? []) {\n\t\tif (ruling.scope !== undefined && !ids.has(ruling.scope)) missing.add(ruling.scope)\n\t}\n\tfor (const notice of definition.notices ?? []) {\n\t\tif (notice.scope !== undefined && !ids.has(notice.scope)) missing.add(notice.scope)\n\t}\n\treturn [...missing]\n}\n\n/**\n * Asserts a program definition's always-on construction invariants — missing\n * scope references and duplicate rating-line or notice ids.\n *\n * @remarks\n * These checks run at construction regardless of `options.validate` (unlike\n * {@link validateProgramDefinition}, the standalone report-shaped validator) —\n * an authoring mistake this severe cannot silently compile.\n *\n * @param definition - The program definition to assert\n * @throws {@link ProgramError} Thrown when a ruling or notice scope names no\n * rating line (`'MISSING'`).\n * @throws {@link ProgramError} Thrown when two rating lines or two notices share\n * an id (`'DUPLICATE'`).\n *\n * @example\n * ```ts\n * import { assertProgramDefinition } from '@orkestrel/program'\n *\n * assertProgramDefinition(definition) // does not throw\n * ```\n */\nexport function assertProgramDefinition(definition: ProgramDefinition): void {\n\tconst missing = findMissingScopes(definition)\n\tif (missing.length > 0) {\n\t\tthrow new ProgramError(\n\t\t\t'MISSING',\n\t\t\t`Unknown rating line reference: ${missing.join(', ')}`,\n\t\t\tdefinition.id,\n\t\t)\n\t}\n\tconst duplicateLines = findDuplicates(definition.rating?.lines ?? [])\n\tif (duplicateLines.length > 0) {\n\t\tthrow new ProgramError(\n\t\t\t'DUPLICATE',\n\t\t\t`Duplicate rating line id: ${duplicateLines.join(', ')}`,\n\t\t\tdefinition.id,\n\t\t)\n\t}\n\tconst duplicateNotices = findDuplicates(definition.notices ?? [])\n\tif (duplicateNotices.length > 0) {\n\t\tthrow new ProgramError(\n\t\t\t'DUPLICATE',\n\t\t\t`Duplicate notice id: ${duplicateNotices.join(', ')}`,\n\t\t\tdefinition.id,\n\t\t)\n\t}\n}\n\n/**\n * Validates a program definition's shape, references, and nested definitions.\n *\n * @remarks\n * The single semantic-validation implementation used by `Program.validate`. It\n * establishes exact shape through {@link isProgramDefinition}, validates the\n * rating structurally through the rater's {@link isRatingDefinition} guard (the\n * rater exposes no `validate`), delegates qualification validation to the\n * injected qualifier and authority / aggregate-gate validation to the shared\n * reason engine, and checks scope, notice, and aggregate-field references here.\n *\n * @param definition - The program definition to validate\n * @param qualifier - The qualifier that validates the nested qualification\n * @param engine - The reason engine that validates authority and aggregate gates\n * @returns A structured validation result\n *\n * @example\n * ```ts\n * import { validateProgramDefinition } from '@orkestrel/program'\n *\n * validateProgramDefinition(definition, qualifier, engine) // { valid: true, ... }\n * ```\n */\nexport function validateProgramDefinition(\n\tdefinition: ProgramDefinition,\n\tqualifier: QualifierInterface,\n\tengine: ReasonInterface,\n): ProgramValidationResult {\n\tif (!isProgramDefinition(definition)) {\n\t\treturn { valid: false, errors: ['Program definition has an invalid shape'], warnings: [] }\n\t}\n\n\tconst errors: string[] = []\n\tconst warnings: string[] = []\n\n\tif (definition.id.length === 0) errors.push('Program id must not be empty')\n\tif (definition.name.length === 0) errors.push('Program name must not be empty')\n\n\tconst qualification = qualifier.validate(definition.qualification)\n\tif (isReasonValidationResult(qualification)) {\n\t\terrors.push(...qualification.errors.map((error) => `qualification: ${error}`))\n\t\twarnings.push(...qualification.warnings.map((warning) => `qualification: ${warning}`))\n\t} else {\n\t\terrors.push('qualification: Qualifier returned invalid validation result')\n\t}\n\n\tconst lines = new Set((definition.rating?.lines ?? []).map((line) => line.id))\n\tif (definition.rating !== undefined && lines.size !== definition.rating.lines.length) {\n\t\terrors.push('rating: duplicate line id')\n\t}\n\tfor (const ruling of definition.qualification.rulings ?? []) {\n\t\tif (ruling.scope !== undefined && !lines.has(ruling.scope)) {\n\t\t\terrors.push(`Qualification ruling \"${ruling.id}\" references missing line \"${ruling.scope}\"`)\n\t\t}\n\t}\n\n\tconst notices = new Set<string>()\n\tfor (const notice of definition.notices ?? []) {\n\t\tif (notices.has(notice.id)) errors.push(`Duplicate notice id \"${notice.id}\"`)\n\t\tnotices.add(notice.id)\n\t\tif (notice.scope !== undefined && !lines.has(notice.scope)) {\n\t\t\terrors.push(`Notice \"${notice.id}\" references missing line \"${notice.scope}\"`)\n\t\t}\n\t}\n\n\tconst authority = definition.authority\n\tif (authority !== undefined) {\n\t\tconst validation = engine.validate(authority)\n\t\tif (isReasonValidationResult(validation)) {\n\t\t\terrors.push(...validation.errors.map((error) => `authority: ${error}`))\n\t\t\twarnings.push(...validation.warnings.map((warning) => `authority: ${warning}`))\n\t\t} else {\n\t\t\terrors.push('authority: Reason engine returned invalid validation result')\n\t\t}\n\t}\n\n\tconst aggregate = definition.aggregate\n\tif (aggregate !== undefined) {\n\t\tconst fields = new Set<string>()\n\t\tfor (const field of aggregate.fields) {\n\t\t\tconst key = formatField(field)\n\t\t\tif (key.length === 0) errors.push('Aggregate fields must be non-empty')\n\t\t\tif (fields.has(key)) errors.push(`Duplicate aggregate field \"${key}\"`)\n\t\t\tfields.add(key)\n\t\t}\n\t\tif (aggregate.partition !== undefined && formatField(aggregate.partition).length === 0) {\n\t\t\terrors.push('Aggregate partition field must be non-empty')\n\t\t}\n\t\tif (aggregate.gates !== undefined) {\n\t\t\tconst validation = engine.validate(aggregate.gates)\n\t\t\tif (isReasonValidationResult(validation)) {\n\t\t\t\terrors.push(...validation.errors.map((error) => `aggregate: ${error}`))\n\t\t\t\twarnings.push(...validation.warnings.map((warning) => `aggregate: ${warning}`))\n\t\t\t} else {\n\t\t\t\terrors.push('aggregate: Reason engine returned invalid validation result')\n\t\t\t}\n\t\t\tif (aggregate.fields.length === 0) {\n\t\t\t\twarnings.push('Aggregate gates are defined without aggregate fields')\n\t\t\t}\n\t\t}\n\t}\n\n\tif (definition.rating !== undefined && definition.rating.lines.length === 0) {\n\t\twarnings.push('Program rating has no lines')\n\t}\n\n\treturn { valid: errors.length === 0, errors, warnings }\n}\n\n/**\n * Coerces a subject's partition-key field to its group-key string.\n *\n * @remarks\n * The key is the resolved field coerced with `String` — `undefined` collapses\n * to the empty string, so a subject missing the field and a subject whose\n * field is literally `''` land in the same partition, and a numeric `1`\n * collides with the string `'1'`.\n *\n * @param subject - The subject to key\n * @param partition - The field the batch partitions on\n * @returns The subject's group key\n *\n * @example\n * ```ts\n * import { formatGroupKey } from '@orkestrel/program'\n *\n * formatGroupKey({ location: 'east' }, 'location') // 'east'\n * ```\n */\nexport function formatGroupKey(subject: Subject, partition: FieldPath): string {\n\treturn String(resolveField(subject, partition) ?? '')\n}\n\n/**\n * Folds one subject's finite aggregate field values into a sums record.\n *\n * @remarks\n * Returns a fresh record — `sums` is never mutated. Only finite numbers\n * contribute; a non-numeric or absent value contributes zero (never a\n * coercion). A {@link FieldPath} may be nested — `formatField` renders the\n * dot-joined key the returned record is keyed by.\n *\n * @param sums - The sums record to fold into\n * @param subject - The subject to fold in\n * @param fields - The fields to sum\n * @returns A fresh sums record with `subject`'s contribution added\n *\n * @example\n * ```ts\n * import { sumFields } from '@orkestrel/program'\n *\n * sumFields({ amount: 0 }, { amount: 5 }, ['amount']) // { amount: 5 }\n * ```\n */\nexport function sumFields(\n\tsums: Readonly<Record<string, number>>,\n\tsubject: Subject,\n\tfields: readonly FieldPath[],\n): Readonly<Record<string, number>> {\n\tconst next: Record<string, number> = { ...sums }\n\tfor (const field of fields) {\n\t\tconst key = formatField(field)\n\t\tconst value = resolveField(subject, field)\n\t\tif (isFiniteNumber(value)) next[key] = (next[key] ?? 0) + value\n\t}\n\treturn next\n}\n\n/**\n * Sums aggregate fields across a batch of subjects.\n *\n * @remarks\n * A {@link FieldPath} may be nested — a nested path sums a nested subject field\n * exactly like a top-level one, and `formatField` renders the dot-joined key the\n * returned record is keyed by. Only finite numbers contribute; a non-numeric or\n * absent value contributes zero (never a coercion).\n *\n * @param subjects - The batch of subjects\n * @param fields - The fields to sum\n * @returns A fresh record of dot-joined field to summed finite value\n *\n * @example\n * ```ts\n * import { aggregateSums } from '@orkestrel/program'\n *\n * aggregateSums([{ amount: 5 }, { amount: 3 }], ['amount']) // { amount: 8 }\n * ```\n */\nexport function aggregateSums(\n\tsubjects: readonly Subject[],\n\tfields: readonly FieldPath[],\n): Readonly<Record<string, number>> {\n\tlet sums = buildEmptySums(fields)\n\tfor (const subject of subjects) sums = sumFields(sums, subject, fields)\n\treturn sums\n}\n\n/**\n * Partitions a batch of subjects by a field, summing aggregate fields per key.\n *\n * @remarks\n * The partition key is derived by {@link formatGroupKey}. Group order follows\n * first appearance in the subject array.\n *\n * @param subjects - The batch of subjects\n * @param fields - The fields to sum within each partition\n * @param partition - The field the batch partitions on; no partition is built when absent\n * @returns A fresh list of aggregate groups, or an empty list when `partition` is absent\n *\n * @example\n * ```ts\n * import { aggregateGroups } from '@orkestrel/program'\n *\n * aggregateGroups([{ location: 'east', amount: 5 }], ['amount'], 'location')\n * ```\n */\nexport function aggregateGroups(\n\tsubjects: readonly Subject[],\n\tfields: readonly FieldPath[],\n\tpartition?: FieldPath,\n): readonly AggregateGroup[] {\n\tif (partition === undefined) return []\n\tconst records = new Map<string, Subject[]>()\n\tfor (const subject of subjects) {\n\t\tconst key = formatGroupKey(subject, partition)\n\t\tconst group = records.get(key)\n\t\tif (group === undefined) records.set(key, [subject])\n\t\telse group.push(subject)\n\t}\n\treturn [...records.entries()].map(([key, entries]) => ({\n\t\tkey,\n\t\tcount: entries.length,\n\t\tsums: aggregateSums(entries, fields),\n\t}))\n}\n\n/**\n * Builds one subject's overall and optional group aggregate projection.\n *\n * @remarks\n * The projection carries the whole-batch `count` and `sums` plus the subject's\n * own partition, located by the same {@link formatGroupKey} key\n * {@link aggregateGroups} partitions under.\n *\n * @param subject - The subject to project for\n * @param count - The whole-batch subject count\n * @param sums - The whole-batch summed aggregate fields\n * @param groups - The batch partitions\n * @param partition - The field the batch partitions on; no group is attached when absent\n * @returns A fresh aggregate projection\n *\n * @example\n * ```ts\n * import { buildAggregateProjection } from '@orkestrel/program'\n *\n * buildAggregateProjection(subject, 2, { amount: 8 }, groups, 'location')\n * ```\n */\nexport function buildAggregateProjection(\n\tsubject: Subject,\n\tcount: number,\n\tsums: Readonly<Record<string, number>>,\n\tgroups: readonly AggregateGroup[],\n\tpartition?: FieldPath,\n): AggregateProjection {\n\tconst group =\n\t\tpartition === undefined\n\t\t\t? undefined\n\t\t\t: groups.find((entry) => entry.key === formatGroupKey(subject, partition))\n\treturn { count, sums: { ...sums }, ...(group === undefined ? {} : { group }) }\n}\n\n/**\n * Builds the reserved-key record a batch aggregate-gate definition runs against.\n *\n * @remarks\n * Unlike a per-subject {@link buildAggregateProjection}, the batch record carries\n * every `group` (a `groups` array) under {@link AGGREGATE_KEY} so a gate rule can\n * read `aggregate.sums.<field>` (overall) or a partition inside `aggregate.groups`.\n *\n * @param count - The whole-batch subject count\n * @param sums - The whole-batch summed aggregate fields\n * @param groups - The batch partitions\n * @returns A fresh record carrying the batch aggregate under {@link AGGREGATE_KEY}\n *\n * @example\n * ```ts\n * import { buildAggregateRecord } from '@orkestrel/program'\n *\n * buildAggregateRecord(2, { amount: 8 }, [])\n * ```\n */\nexport function buildAggregateRecord(\n\tcount: number,\n\tsums: Readonly<Record<string, number>>,\n\tgroups: readonly AggregateGroup[],\n): Readonly<Record<string, unknown>> {\n\treturn { [AGGREGATE_KEY]: { count, sums, groups } }\n}\n\n/**\n * Builds a zero-sum record for a set of aggregate fields.\n *\n * @param fields - The fields to zero\n * @returns A fresh record of dot-joined field to `0`\n *\n * @example\n * ```ts\n * import { buildEmptySums } from '@orkestrel/program'\n *\n * buildEmptySums(['amount']) // { amount: 0 }\n * ```\n */\nexport function buildEmptySums(fields: readonly FieldPath[]): Readonly<Record<string, number>> {\n\tconst sums: Record<string, number> = {}\n\tfor (const field of fields) sums[formatField(field)] = 0\n\treturn sums\n}\n\n/**\n * Completes a partial status tally record with zero entries for every missing\n * {@link Status}.\n *\n * @param entries - The partial tally entries to complete\n * @returns A record carrying every {@link Status}\n *\n * @example\n * ```ts\n * import { completeTallies } from '@orkestrel/program'\n *\n * completeTallies({ eligible: { count: 1, sums: {} } })\n * ```\n */\nexport function completeTallies(\n\tentries: Partial<Record<Status, Tally>>,\n): Readonly<Record<Status, Tally>> {\n\treturn {\n\t\tineligible: entries.ineligible ?? { count: 0, sums: {} },\n\t\treferral: entries.referral ?? { count: 0, sums: {} },\n\t\tconditional: entries.conditional ?? { count: 0, sums: {} },\n\t\tunrated: entries.unrated ?? { count: 0, sums: {} },\n\t\teligible: entries.eligible ?? { count: 0, sums: {} },\n\t}\n}\n\n/**\n * Builds complete zero status tallies in {@link STATUSES} order.\n *\n * @param fields - The fields each tally's sums are zeroed for\n * @returns A fresh, complete tally record\n *\n * @example\n * ```ts\n * import { buildEmptyTallies } from '@orkestrel/program'\n *\n * buildEmptyTallies(['amount'])\n * ```\n */\nexport function buildEmptyTallies(fields: readonly FieldPath[]): Readonly<Record<Status, Tally>> {\n\tconst entries: Partial<Record<Status, Tally>> = {}\n\tfor (const status of STATUSES) entries[status] = { count: 0, sums: buildEmptySums(fields) }\n\treturn completeTallies(entries)\n}\n\n/**\n * Adds one subject's aggregate contribution to a status tally record.\n *\n * @param tallies - The tallies to update\n * @param result - The subject's program result (its `status` selects the tally)\n * @param subject - The subject to fold in\n * @param fields - The fields to sum\n * @returns A fresh, complete tally record with the subject folded in\n *\n * @example\n * ```ts\n * import { tallySubject } from '@orkestrel/program'\n *\n * tallySubject(tallies, result, { id: 'r1', amount: 5 }, ['amount'])\n * ```\n */\nexport function tallySubject(\n\ttallies: Readonly<Record<Status, Tally>>,\n\tresult: ProgramResult,\n\tsubject: Subject,\n\tfields: readonly FieldPath[],\n): Readonly<Record<Status, Tally>> {\n\tconst status = result.status\n\tconst current = tallies[status]\n\tconst sums = sumFields(current.sums, subject, fields)\n\treturn completeTallies({ ...tallies, [status]: { count: current.count + 1, sums } })\n}\n\n/**\n * Assembles one batch {@link AggregateResult} from its per-subject and aggregate\n * parts.\n *\n * @remarks\n * `count` is the subject count, `trace` / `errors` accumulate every subject's\n * plus the batch aggregate-gate evaluation's (`options.gates`), and `success`\n * requires every subject execution to succeed and the gate evaluation to have\n * produced no errors. A fired aggregate gate contributes a `limit`\n * determination, never a technical failure (a non-logical gate result is a\n * caller-facing `MISMATCH` thrown by `Program` before this assembles).\n *\n * @param definition - The authored program definition\n * @param subjects - The per-subject program results, in input order\n * @param determinations - The batch aggregate-gate `limit` determinations\n * @param groups - The batch partitions\n * @param tallies - The completed status tallies\n * @param sums - The whole-batch summed aggregate fields\n * @param options - Optional resolved aggregate-gate result\n * @returns A fresh aggregate result\n *\n * @example\n * ```ts\n * import { buildAggregateResult } from '@orkestrel/program'\n *\n * buildAggregateResult(definition, subjects, [], [], tallies, { amount: 8 })\n * ```\n */\nexport function buildAggregateResult(\n\tdefinition: ProgramDefinition,\n\tsubjects: readonly ProgramResult[],\n\tdeterminations: readonly Determination[],\n\tgroups: readonly AggregateGroup[],\n\ttallies: Readonly<Record<Status, Tally>>,\n\tsums: Readonly<Record<string, number>>,\n\toptions?: { readonly gates?: LogicalResult },\n): AggregateResult {\n\tconst gates = options?.gates\n\tconst gateTrace = gates === undefined ? [] : [...gates.trace]\n\tconst gateErrors = gates === undefined ? [] : [...gates.errors]\n\treturn {\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tsubjects,\n\t\tdeterminations,\n\t\tgroups,\n\t\ttallies,\n\t\tcount: subjects.length,\n\t\tsums,\n\t\tsuccess: subjects.every((entry) => entry.success) && gateErrors.length === 0,\n\t\ttrace: [...subjects.flatMap((entry) => entry.trace), ...gateTrace],\n\t\terrors: [...subjects.flatMap((entry) => entry.errors), ...gateErrors],\n\t}\n}\n\n/**\n * Builds a fresh {@link ProgramDefinition}.\n *\n * @remarks\n * Omits absent optional keys. `metadata` is deep-copied with `structuredClone`.\n * `notices` is copied as a fresh array whose elements are shared with the\n * input. `qualification`, `rating`, `authority`, and `aggregate` are stored\n * by reference. The {@link Program} constructor later snapshots and seals\n * the whole graph.\n *\n * @param id - The program id\n * @param name - The display name\n * @param qualification - The nested qualification definition\n * @param rating - The nested rating definition; omit for an eligibility-only program\n * @param input - Optional description, notices, authority, aggregate, and metadata\n * @returns A fresh program definition\n *\n * @example\n * ```ts\n * import { buildProgramDefinition } from '@orkestrel/program'\n *\n * buildProgramDefinition('standard', 'Standard', qualification, rating, { notices: [notice] })\n * ```\n */\nexport function buildProgramDefinition(\n\tid: string,\n\tname: string,\n\tqualification: QualificationDefinition,\n\trating?: RatingDefinition,\n\tinput?: ProgramInput,\n): ProgramDefinition {\n\treturn {\n\t\tid,\n\t\tname,\n\t\tqualification,\n\t\t...(rating === undefined ? {} : { rating }),\n\t\t...(input?.description === undefined ? {} : { description: input.description }),\n\t\t...(input?.notices === undefined ? {} : { notices: [...input.notices] }),\n\t\t...(input?.authority === undefined ? {} : { authority: input.authority }),\n\t\t...(input?.aggregate === undefined ? {} : { aggregate: input.aggregate }),\n\t\t...(input?.metadata === undefined ? {} : { metadata: structuredClone(input.metadata) }),\n\t}\n}\n\n/**\n * Builds a fresh {@link Notice}.\n *\n * @remarks\n * An absent `scope` is omitted entirely rather than stored as `undefined`.\n *\n * @param id - The notice id\n * @param message - The message template, carrying optional `{{token}}` placeholders\n * @param input - Optional presentation scope\n * @returns A fresh notice\n *\n * @example\n * ```ts\n * import { buildNotice } from '@orkestrel/program'\n *\n * buildNotice('minimum', 'Minimum earned premium applies')\n * ```\n */\nexport function buildNotice(id: string, message: string, input?: NoticeInput): Notice {\n\treturn {\n\t\tid,\n\t\tmessage,\n\t\t...(input?.scope === undefined ? {} : { scope: input.scope }),\n\t}\n}\n\n/**\n * Builds a fresh {@link AggregateDefinition}.\n *\n * @remarks\n * `fields` is copied into a fresh array; an absent `partition` or `gates` is\n * omitted entirely rather than stored as `undefined`.\n *\n * @param fields - The aggregate fields to sum across a batch\n * @param input - Optional partition field and aggregate gates\n * @returns A fresh aggregate definition\n *\n * @example\n * ```ts\n * import { buildAggregateDefinition } from '@orkestrel/program'\n *\n * buildAggregateDefinition(['amount'], { partition: 'location' })\n * ```\n */\nexport function buildAggregateDefinition(\n\tfields: readonly FieldPath[],\n\tinput?: AggregateInput,\n): AggregateDefinition {\n\treturn {\n\t\tfields: [...fields],\n\t\t...(input?.partition === undefined ? {} : { partition: input.partition }),\n\t\t...(input?.gates === undefined ? {} : { gates: input.gates }),\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { QualificationResult, QualifierInterface } from '@orkestrel/qualifier'\nimport type { RaterInterface, RatingResult } from '@orkestrel/rater'\nimport type { EvaluatorInterface, LogicalResult, ReasonInterface, Subject } from '@orkestrel/reason'\nimport type {\n\tAggregateGroup,\n\tAggregateProjection,\n\tAggregateResult,\n\tDetermination,\n\tProgramDefinition,\n\tProgramEventMap,\n\tProgramInterface,\n\tProgramOptions,\n\tProgramResult,\n\tProgramValidationResult,\n} from '../types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isArray } from '@orkestrel/contract'\nimport { createQualifier, isQualificationResult } from '@orkestrel/qualifier'\nimport { createRater, isRatingResult } from '@orkestrel/rater'\nimport {\n\tcreateEvaluator,\n\tcreateLogicalReasoner,\n\tcreateQuantitativeReasoner,\n\tcreateReason,\n\tisLogicalResult,\n} from '@orkestrel/reason'\nimport { DEFAULT_PROGRAM_VALIDATE, OUTCOME_KEY } from '../constants.js'\nimport { ProgramError } from '../errors.js'\nimport {\n\taggregateGroups,\n\taggregateSums,\n\tassertProgramDefinition,\n\tassertProgramSubject,\n\tbuildAggregateProjection,\n\tbuildAggregateRecord,\n\tbuildAggregateResult,\n\tbuildEmptyTallies,\n\tbuildLimitDeterminations,\n\tbuildNoticeDeterminations,\n\tbuildOutcomeProjection,\n\tbuildProgramResult,\n\tbuildQualificationSubject,\n\tderiveStatus,\n\tselectProgramLines,\n\ttallySubject,\n\tvalidateProgramDefinition,\n} from '../helpers.js'\n\n/**\n * Composes one qualifier and one rater over a shared reason engine, compiling one\n * authored definition and executing single subjects or aggregate-aware batches.\n *\n * @remarks\n * Qualification decides whether rating happens: a globally ineligible, referred,\n * or failed subject never reaches the rater, and a scoped ineligibility removes\n * only its line before the first rating call. The rater always receives the\n * original subject; the qualifier's aggregate projection stays private. When no\n * qualifier, rater, or engine is injected the program creates one shared\n * quantitative-plus-logical engine, injects it into the qualifier and rater it\n * creates, and destroys only what it owns. A definition failure during\n * construction (an invalid definition under `options.validate`) tears down\n * whatever the constructor had already allocated before throwing. Construction\n * snapshots the caller's definition once, runs the always-on assertions against\n * that snapshot, and seals its plain-object graph before exposure. A `Map`, `Set`,\n * or `Date` reached through a reason `Check.value` is cloned but remains mutable\n * because its contents live in internal slots. Uncloneable values and non-empty\n * typed arrays are refused with `ProgramError('DEFINITION')` and the host error\n * as its cause. `destroy()` is idempotent and reentrancy-safe — the destroyed\n * flag is set before any teardown or the `destroy` event fires, so a listener\n * that re-enters `destroy()` is a no-op — and tears the emitter down last.\n */\nexport class Program implements ProgramInterface {\n\treadonly #emitter: Emitter<ProgramEventMap>\n\treadonly #qualifier: QualifierInterface\n\treadonly #rater: RaterInterface\n\treadonly #engine: ReasonInterface\n\treadonly #evaluator: EvaluatorInterface\n\treadonly #qualifierOwned: boolean\n\treadonly #raterOwned: boolean\n\treadonly #engineOwned: boolean\n\treadonly #validate: boolean\n\treadonly #labels: Readonly<Record<string, string>> | undefined\n\t#destroyed = false\n\n\t/** Holds the authored id of the definition this program compiled. */\n\treadonly id: string\n\t/** Holds the authored display name of the definition this program compiled. */\n\treadonly name: string\n\t/** Holds the sealed snapshot of the authored definition this program compiled. */\n\treadonly definition: ProgramDefinition\n\n\t/**\n\t * Compiles one program from an authored definition.\n\t *\n\t * @param definition - The authored program definition\n\t * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks\n\t * @throws {@link ProgramError} Thrown when the definition cannot be cloned or\n\t * sealed, or when validation is enabled and the definition fails\n\t * (`'DEFINITION'`).\n\t * @throws {@link ProgramError} Thrown when a ruling or notice scope names no\n\t * rating line (`'MISSING'`).\n\t * @throws {@link ProgramError} Thrown when the definition repeats a rating-line\n\t * or notice id (`'DUPLICATE'`).\n\t */\n\tconstructor(definition: ProgramDefinition, options?: ProgramOptions) {\n\t\tlet snapshot: ProgramDefinition\n\t\ttry {\n\t\t\tsnapshot = structuredClone(definition)\n\t\t} catch (cause) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'DEFINITION',\n\t\t\t\t'Program definition could not be cloned',\n\t\t\t\tundefined,\n\t\t\t\tcause,\n\t\t\t)\n\t\t}\n\t\tassertProgramDefinition(snapshot)\n\t\tthis.id = snapshot.id\n\t\tthis.name = snapshot.name\n\t\tthis.definition = snapshot\n\t\ttry {\n\t\t\tthis.#seal()\n\t\t} catch (cause) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'DEFINITION',\n\t\t\t\t'Program definition could not be sealed',\n\t\t\t\tsnapshot.id,\n\t\t\t\tcause,\n\t\t\t)\n\t\t}\n\t\tthis.#emitter = new Emitter({\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\tthis.#evaluator = createEvaluator()\n\t\tthis.#engineOwned = options?.engine === undefined\n\t\tthis.#qualifierOwned = options?.qualifier === undefined\n\t\tthis.#raterOwned = options?.rater === undefined\n\t\tthis.#engine =\n\t\t\toptions?.engine ??\n\t\t\tcreateReason({\n\t\t\t\treasoners: [createQuantitativeReasoner(), createLogicalReasoner()],\n\t\t\t\tbail: false,\n\t\t\t})\n\t\tthis.#qualifier = options?.qualifier ?? createQualifier({ engine: this.#engine })\n\t\tthis.#rater = options?.rater ?? createRater({ engine: this.#engine })\n\t\tthis.#validate = options?.validate ?? DEFAULT_PROGRAM_VALIDATE\n\t\tthis.#labels = options?.labels\n\n\t\tif (this.#validate) {\n\t\t\tconst validation = this.validate()\n\t\t\tif (!validation.valid) {\n\t\t\t\tthis.destroy()\n\t\t\t\tthrow new ProgramError('DEFINITION', validation.errors.join('; '), snapshot.id)\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Holds the typed observation surface carrying `qualify`, `rate`, `determine`,\n\t * `decide`, `execute`, `aggregate`, and `destroy`.\n\t *\n\t * @returns The emitter this program owns\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgram } from '@orkestrel/program'\n\t *\n\t * const program = createProgram(definition)\n\t * program.emitter.on('execute', (result) => result.status)\n\t * program.destroy()\n\t * ```\n\t */\n\tget emitter(): EmitterInterface<ProgramEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t// Array overload first so a subject list resolves to the batch form.\n\t/**\n\t * Executes a subject list as one aggregate-aware batch.\n\t *\n\t * @remarks\n\t * Every subject is asserted before any work runs, so a reserved key in the last\n\t * subject rejects the batch before the first one qualifies. The batch sums,\n\t * partitions, and per-subject aggregate projections are computed next, each\n\t * subject executes in input order, every result tallies by status, and optional\n\t * aggregate gates run last against the batch aggregate record.\n\t *\n\t * @param subjects - The subjects to execute, in input order\n\t * @returns A fresh aggregate result carrying every subject result, the batch\n\t * determinations, partitions, tallies, and sums\n\t * @throws {@link ProgramError} Thrown when the program has been destroyed\n\t * (`'DESTROYED'`).\n\t * @throws {@link ProgramError} Thrown when a subject is not a record, or when a\n\t * borrowed qualifier, rater, or reason engine returns an off-contract result\n\t * (`'MISMATCH'`).\n\t * @throws {@link ProgramError} Thrown when a subject already carries the\n\t * `aggregate` or `outcome` key (`'RESERVED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgram } from '@orkestrel/program'\n\t *\n\t * const program = createProgram(definition)\n\t * program.execute([{ id: 'risk-1', licensed: true }]).count // 1\n\t * program.destroy()\n\t * ```\n\t */\n\texecute(subjects: readonly Subject[]): AggregateResult\n\t/**\n\t * Executes one subject through the composed qualify-rate-determine workflow.\n\t *\n\t * @remarks\n\t * Qualification decides whether rating happens: a globally ineligible, referred,\n\t * or failed subject never reaches the rater, and a scoped ineligibility removes\n\t * only its line before the first rating call. The rater always receives the\n\t * original subject. Notices, status, optional authority, and the optional\n\t * decision follow, in that order.\n\t *\n\t * @param subject - The subject to execute\n\t * @returns A fresh program result carrying the nested qualification and rating\n\t * evidence, determinations, status, and optional decision\n\t * @throws {@link ProgramError} Thrown when the program has been destroyed\n\t * (`'DESTROYED'`).\n\t * @throws {@link ProgramError} Thrown when the subject is not a record, or when a\n\t * borrowed qualifier, rater, or reason engine returns an off-contract result\n\t * (`'MISMATCH'`).\n\t * @throws {@link ProgramError} Thrown when the subject already carries the\n\t * `aggregate` or `outcome` key (`'RESERVED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgram } from '@orkestrel/program'\n\t *\n\t * const program = createProgram(definition)\n\t * program.execute({ id: 'risk-1', licensed: true }).status // 'eligible'\n\t * program.destroy()\n\t * ```\n\t */\n\texecute(subject: Subject): ProgramResult\n\texecute(input: Subject | readonly Subject[]): ProgramResult | AggregateResult {\n\t\tthis.#alive()\n\t\tif (isArray<Subject>(input)) return this.#aggregate(input)\n\t\treturn this.#subject(input)\n\t}\n\n\t/**\n\t * Validates this program's definition and every nested definition.\n\t *\n\t * @remarks\n\t * Exact shape is `isProgramDefinition`'s job. This checks the meaning: non-empty id\n\t * and name, every ruling and notice scope naming a rating line, unique non-empty\n\t * aggregate fields, and a non-empty partition field when present. Nested\n\t * qualification validation is delegated to the injected qualifier, and authority\n\t * and aggregate-gate validation to the shared reason engine.\n\t *\n\t * @returns A fresh validation result carrying `valid`, `errors`, and `warnings`\n\t * @throws {@link ProgramError} Thrown when the program has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgram } from '@orkestrel/program'\n\t *\n\t * const program = createProgram(definition, { validate: false })\n\t * program.validate().valid // true\n\t * program.destroy()\n\t * ```\n\t */\n\tvalidate(): ProgramValidationResult {\n\t\tthis.#alive()\n\t\treturn validateProgramDefinition(this.definition, this.#qualifier, this.#engine)\n\t}\n\n\t/**\n\t * Destroys this program, idempotently.\n\t *\n\t * @remarks\n\t * The destroyed flag is set before any teardown or the `destroy` event, so a\n\t * listener re-entering `destroy` is a no-op. An owned qualifier, rater, and reason\n\t * engine are destroyed; an injected one stays caller-owned. The emitter is torn\n\t * down last, and stays reachable afterwards.\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgram } from '@orkestrel/program'\n\t *\n\t * const program = createProgram(definition)\n\t * program.destroy()\n\t * program.destroy() // a second call is a no-op\n\t * ```\n\t */\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tif (this.#qualifierOwned) this.#qualifier.destroy()\n\t\tif (this.#raterOwned) this.#rater.destroy()\n\t\tif (this.#engineOwned) this.#engine.destroy()\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#subject(subject: Subject, aggregate?: AggregateProjection): ProgramResult {\n\t\tassertProgramSubject(subject)\n\t\tconst qualified = buildQualificationSubject(subject, aggregate)\n\t\tconst qualification = this.#qualifier.qualify(qualified, this.definition.qualification)\n\t\tif (!isQualificationResult(qualification)) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'MISMATCH',\n\t\t\t\t'Qualifier returned invalid qualification result',\n\t\t\t\tthis.definition.qualification.id,\n\t\t\t)\n\t\t}\n\t\tthis.#emitter.emit('qualify', qualification)\n\n\t\tif (!qualification.success || qualification.eligibility !== 'eligible') {\n\t\t\treturn this.#finish(subject, qualification, undefined)\n\t\t}\n\n\t\tconst lines = selectProgramLines(this.definition.rating?.lines ?? [], qualification.scopes)\n\t\tconst rating = lines.length === 0 ? undefined : this.#rater.rate(lines, subject)\n\t\tif (rating !== undefined) {\n\t\t\tif (!isRatingResult(rating)) {\n\t\t\t\tthrow new ProgramError(\n\t\t\t\t\t'MISMATCH',\n\t\t\t\t\t'Rater returned invalid rating result',\n\t\t\t\t\tthis.definition.rating?.id,\n\t\t\t\t)\n\t\t\t}\n\t\t\tthis.#emitter.emit('rate', rating)\n\t\t}\n\n\t\treturn this.#finish(subject, qualification, rating)\n\t}\n\n\t#finish(\n\t\tsubject: Subject,\n\t\tqualification: QualificationResult,\n\t\trating?: RatingResult,\n\t): ProgramResult {\n\t\tconst notices = buildNoticeDeterminations(this.definition.notices ?? [], subject)\n\t\tfor (const notice of notices) this.#emitter.emit('determine', notice)\n\n\t\tconst status = deriveStatus(this.definition, qualification, rating)\n\t\tlet result = buildProgramResult(this.definition, qualification, rating, notices, status)\n\n\t\tconst authority = this.definition.authority\n\t\tif (authority === undefined) {\n\t\t\tthis.#emitter.emit('execute', result)\n\t\t\treturn result\n\t\t}\n\n\t\tconst outcome = { [OUTCOME_KEY]: buildOutcomeProjection(result) }\n\t\tconst resolved = this.#engine.reason(outcome, authority)\n\t\tif (!isLogicalResult(resolved)) {\n\t\t\tthrow new ProgramError('MISMATCH', 'Authority returned invalid logical result', authority.id)\n\t\t}\n\n\t\tconst limits = buildLimitDeterminations(\n\t\t\tauthority,\n\t\t\tresolved,\n\t\t\toutcome,\n\t\t\tthis.#evaluator,\n\t\t\tthis.#labels,\n\t\t)\n\t\tfor (const limit of limits) this.#emitter.emit('determine', limit)\n\n\t\tresult = buildProgramResult(\n\t\t\tthis.definition,\n\t\t\tqualification,\n\t\t\trating,\n\t\t\t[...notices, ...limits],\n\t\t\tstatus,\n\t\t\t{ authority: resolved },\n\t\t)\n\n\t\tif (result.decision !== undefined) this.#emitter.emit('decide', result.decision, result)\n\t\tthis.#emitter.emit('execute', result)\n\t\treturn result\n\t}\n\n\t#aggregate(subjects: readonly Subject[]): AggregateResult {\n\t\tfor (const subject of subjects) assertProgramSubject(subject)\n\n\t\tconst definition = this.definition.aggregate\n\t\tconst fields = [...(definition?.fields ?? [])]\n\t\tconst sums = aggregateSums(subjects, fields)\n\t\tconst groups = aggregateGroups(subjects, fields, definition?.partition)\n\t\tlet tallies = buildEmptyTallies(fields)\n\t\tconst results = subjects.map((subject) => {\n\t\t\tconst projection =\n\t\t\t\tdefinition === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: buildAggregateProjection(subject, subjects.length, sums, groups, definition.partition)\n\t\t\tconst result = this.#subject(subject, projection)\n\t\t\ttallies = tallySubject(tallies, result, subject, fields)\n\t\t\treturn result\n\t\t})\n\n\t\tconst gates = this.#aggregateLimits(subjects.length, sums, groups)\n\t\tconst result = buildAggregateResult(\n\t\t\tthis.definition,\n\t\t\tresults,\n\t\t\tgates.determinations,\n\t\t\tgroups,\n\t\t\ttallies,\n\t\t\tsums,\n\t\t\tgates.resolved === undefined ? undefined : { gates: gates.resolved },\n\t\t)\n\t\tthis.#emitter.emit('aggregate', result)\n\t\treturn result\n\t}\n\n\t#aggregateLimits(\n\t\tcount: number,\n\t\tsums: Readonly<Record<string, number>>,\n\t\tgroups: readonly AggregateGroup[],\n\t): { readonly determinations: readonly Determination[]; readonly resolved?: LogicalResult } {\n\t\tconst gates = this.definition.aggregate?.gates\n\t\tif (gates === undefined) return { determinations: [] }\n\n\t\tconst record = buildAggregateRecord(count, sums, groups)\n\t\tconst resolved = this.#engine.reason(record, gates)\n\t\tif (!isLogicalResult(resolved)) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'MISMATCH',\n\t\t\t\t'Aggregate gates returned invalid logical result',\n\t\t\t\tgates.id,\n\t\t\t)\n\t\t}\n\n\t\tconst determinations = buildLimitDeterminations(\n\t\t\tgates,\n\t\t\tresolved,\n\t\t\trecord,\n\t\t\tthis.#evaluator,\n\t\t\tthis.#labels,\n\t\t)\n\t\tfor (const determination of determinations) this.#emitter.emit('determine', determination)\n\t\treturn { determinations, resolved }\n\t}\n\n\t#alive(): void {\n\t\tif (this.#destroyed) {\n\t\t\tthrow new ProgramError('DESTROYED', 'Program has been destroyed', this.id)\n\t\t}\n\t}\n\n\t#seal(): void {\n\t\tconst pending: object[] = [this.definition]\n\t\twhile (pending.length > 0) {\n\t\t\tconst value = pending.pop()\n\t\t\tif (value === undefined || Object.isFrozen(value)) continue\n\t\t\tObject.freeze(value)\n\t\t\tfor (const child of Object.values(value)) {\n\t\t\t\tif (child !== null && typeof child === 'object') pending.push(child)\n\t\t\t}\n\t\t}\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { QualifierInterface } from '@orkestrel/qualifier'\nimport type { RaterInterface } from '@orkestrel/rater'\nimport type { ReasonInterface } from '@orkestrel/reason'\nimport type {\n\tProgramDefinition,\n\tProgramInterface,\n\tProgramManagerEventMap,\n\tProgramManagerInterface,\n\tProgramManagerOptions,\n} from '../types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { createQualifier } from '@orkestrel/qualifier'\nimport { createRater } from '@orkestrel/rater'\nimport { createLogicalReasoner, createQuantitativeReasoner, createReason } from '@orkestrel/reason'\nimport { DEFAULT_PROGRAM_VALIDATE } from '../constants.js'\nimport { ProgramError } from '../errors.js'\nimport { createProgram } from '../factories.js'\n\n/**\n * Manages compiled {@link ProgramInterface} programs in order, sharing one\n * qualifier, rater, and reason engine across every program it compiles.\n *\n * @remarks\n * owns its ordered `#programs` collection and its own {@link Emitter} over\n * {@link ProgramManagerEventMap}. Creates or borrows one shared engine, qualifier,\n * and rater and injects the same instances into every compiled program. `remove`\n * destroys the programs it removes; `destroy()` removes all programs, then\n * destroys only the owned shared dependencies, and tears the emitter down last.\n * A seed-program failure during construction tears the manager down (destroying\n * whatever had already been compiled) before rethrowing the original error.\n * `destroy()` is reentrancy-safe — the destroyed flag is set before any teardown\n * or the `remove` / `destroy` events fire, so a `remove` listener that re-enters\n * `destroy()` is a no-op. Every call after `destroy()` throws {@link ProgramError}\n * `'DESTROYED'`.\n */\nexport class ProgramManager implements ProgramManagerInterface {\n\treadonly #emitter: Emitter<ProgramManagerEventMap>\n\treadonly #programs: ProgramInterface[] = []\n\treadonly #qualifier: QualifierInterface\n\treadonly #rater: RaterInterface\n\treadonly #engine: ReasonInterface\n\treadonly #qualifierOwned: boolean\n\treadonly #raterOwned: boolean\n\treadonly #engineOwned: boolean\n\treadonly #validate: boolean\n\treadonly #labels: Readonly<Record<string, string>> | undefined\n\t#destroyed = false\n\n\t/**\n\t * Creates one manager and compiles every seed definition in order.\n\t *\n\t * @param options - Optional injected qualifier, rater, engine, seed programs, validation, labels, and emitter hooks\n\t * @throws {@link ProgramError} Thrown when a seed definition fails to compile,\n\t * after the manager destroys whatever it had already compiled.\n\t */\n\tconstructor(options?: ProgramManagerOptions) {\n\t\tthis.#emitter = new Emitter({\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\tthis.#labels = options?.labels\n\t\tthis.#engineOwned = options?.engine === undefined\n\t\tthis.#qualifierOwned = options?.qualifier === undefined\n\t\tthis.#raterOwned = options?.rater === undefined\n\t\tthis.#engine =\n\t\t\toptions?.engine ??\n\t\t\tcreateReason({\n\t\t\t\treasoners: [createQuantitativeReasoner(), createLogicalReasoner()],\n\t\t\t\tbail: false,\n\t\t\t})\n\t\tthis.#qualifier = options?.qualifier ?? createQualifier({ engine: this.#engine })\n\t\tthis.#rater = options?.rater ?? createRater({ engine: this.#engine })\n\t\tthis.#validate = options?.validate ?? DEFAULT_PROGRAM_VALIDATE\n\n\t\ttry {\n\t\t\tfor (const definition of options?.programs ?? []) this.add(definition)\n\t\t} catch (error) {\n\t\t\tthis.destroy()\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Holds the typed observation surface carrying `add`, `remove`, and `destroy`.\n\t *\n\t * @returns The emitter this manager owns\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager()\n\t * manager.emitter.on('add', (id) => id)\n\t * manager.destroy()\n\t * ```\n\t */\n\tget emitter(): EmitterInterface<ProgramManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\t/**\n\t * Holds how many programs the manager has compiled.\n\t *\n\t * @returns The number of compiled programs\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.count // 1\n\t * manager.destroy()\n\t * ```\n\t */\n\tget count(): number {\n\t\tthis.#alive()\n\t\treturn this.#programs.length\n\t}\n\n\t/**\n\t * Reports whether an id names a compiled program.\n\t *\n\t * @param id - The program id to look for\n\t * @returns True if a compiled program carries the id; false otherwise\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.has('standard') // true\n\t * manager.destroy()\n\t * ```\n\t */\n\thas(id: string): boolean {\n\t\tthis.#alive()\n\t\treturn this.#programs.some((program) => program.id === id)\n\t}\n\n\t/**\n\t * Looks one compiled program up by id.\n\t *\n\t * @param id - The program id to look up\n\t * @returns The compiled program, or `undefined` when no program carries the id\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.program('standard')?.execute({ id: 'risk-1', licensed: true })\n\t * manager.destroy()\n\t * ```\n\t */\n\tprogram(id: string): ProgramInterface | undefined {\n\t\tthis.#alive()\n\t\treturn this.#programs.find((program) => program.id === id)\n\t}\n\n\t/**\n\t * Returns every compiled program, in insertion order.\n\t *\n\t * @remarks\n\t * The returned array is a fresh copy, so mutating it never reaches the manager's\n\t * own collection.\n\t *\n\t * @returns A fresh array of compiled programs, in insertion order\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.programs().map((program) => program.id) // ['standard']\n\t * manager.destroy()\n\t * ```\n\t */\n\tprograms(): readonly ProgramInterface[] {\n\t\tthis.#alive()\n\t\treturn [...this.#programs]\n\t}\n\n\t/**\n\t * Compiles one definition and appends it to the collection.\n\t *\n\t * @remarks\n\t * The compiled program borrows the manager's shared qualifier, rater, and reason\n\t * engine, and inherits the manager's `validate` and `labels` options. After\n\t * appending the program, the `add` event fires with its id.\n\t *\n\t * @param definition - The authored program definition to compile\n\t * @returns The compiled program\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t * @throws {@link ProgramError} Thrown when the manager already carries the\n\t * definition's id, or the definition repeats a rating-line or notice id\n\t * (`'DUPLICATE'`).\n\t * @throws {@link ProgramError} Thrown when a ruling or notice scope names no\n\t * rating line (`'MISSING'`).\n\t * @throws {@link ProgramError} Thrown when validation is enabled and the\n\t * definition fails (`'DEFINITION'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager()\n\t * manager.add(definition).id // 'standard'\n\t * manager.destroy()\n\t * ```\n\t */\n\tadd(definition: ProgramDefinition): ProgramInterface {\n\t\tthis.#alive()\n\t\tif (this.has(definition.id)) {\n\t\t\tthrow new ProgramError(\n\t\t\t\t'DUPLICATE',\n\t\t\t\t`Program \"${definition.id}\" already exists`,\n\t\t\t\tdefinition.id,\n\t\t\t)\n\t\t}\n\t\tconst program = createProgram(definition, {\n\t\t\tqualifier: this.#qualifier,\n\t\t\trater: this.#rater,\n\t\t\tengine: this.#engine,\n\t\t\tvalidate: this.#validate,\n\t\t\t...(this.#labels === undefined ? {} : { labels: this.#labels }),\n\t\t})\n\t\tthis.#programs.push(program)\n\t\tthis.#emitter.emit('add', program.id)\n\t\treturn program\n\t}\n\n\t// Array overload first so an id list resolves to the batch form.\n\t/**\n\t * Removes every listed id, destroying each removed program.\n\t *\n\t * @remarks\n\t * Every id is attempted, so one absent id does not stop the rest. Each removal\n\t * destroys its program and fires `remove` with that id. An empty list succeeds\n\t * vacuously.\n\t *\n\t * @param ids - The program ids to remove\n\t * @returns True if every listed id named a compiled program; false otherwise\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.remove(['standard', 'absent']) // false\n\t * manager.destroy()\n\t * ```\n\t */\n\tremove(ids: readonly string[]): boolean\n\t/**\n\t * Removes one id, destroying the program it named.\n\t *\n\t * @param id - The program id to remove\n\t * @returns True if the id named a compiled program; false otherwise\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.remove('standard') // true\n\t * manager.destroy()\n\t * ```\n\t */\n\tremove(id: string): boolean\n\t/**\n\t * Removes every compiled program, destroying each one.\n\t *\n\t * @remarks\n\t * Each removal fires `remove` with that program's id. The manager itself stays\n\t * usable, so a later `add` compiles into the drained collection.\n\t *\n\t * @throws {@link ProgramError} Thrown when the manager has been destroyed\n\t * (`'DESTROYED'`).\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.remove()\n\t * manager.destroy()\n\t * ```\n\t */\n\tremove(): void\n\tremove(input?: string | readonly string[]): boolean | void {\n\t\tthis.#alive()\n\t\tif (input === undefined) {\n\t\t\tthis.#drain()\n\t\t\treturn\n\t\t}\n\t\tif (Array.isArray(input)) {\n\t\t\tlet removed = true\n\t\t\tfor (const id of input) removed = this.#removeOne(id) && removed\n\t\t\treturn removed\n\t\t}\n\t\tif (typeof input === 'string') return this.#removeOne(input)\n\t}\n\n\t/**\n\t * Destroys this manager, idempotently.\n\t *\n\t * @remarks\n\t * The destroyed flag is set before any teardown or the `remove` and `destroy`\n\t * events, so a `remove` listener re-entering `destroy` is a no-op. Compiled\n\t * programs are destroyed first, then an owned qualifier, rater, and reason engine;\n\t * an injected one stays caller-owned. The emitter is torn down last, and stays\n\t * reachable afterwards.\n\t *\n\t * @example\n\t * ```ts\n\t * import { createProgramManager } from '@orkestrel/program'\n\t *\n\t * const manager = createProgramManager({ programs: [definition] })\n\t * manager.destroy()\n\t * manager.destroy() // a second call is a no-op\n\t * ```\n\t */\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tthis.#drain()\n\t\tif (this.#qualifierOwned) this.#qualifier.destroy()\n\t\tif (this.#raterOwned) this.#rater.destroy()\n\t\tif (this.#engineOwned) this.#engine.destroy()\n\t\tthis.#emitter.emit('destroy')\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#drain(): void {\n\t\tfor (const program of this.#programs.splice(0)) {\n\t\t\tprogram.destroy()\n\t\t\tthis.#emitter.emit('remove', program.id)\n\t\t}\n\t}\n\n\t#removeOne(id: string): boolean {\n\t\tconst index = this.#programs.findIndex((program) => program.id === id)\n\t\tif (index < 0) return false\n\t\tconst removed = this.#programs.splice(index, 1)[0]\n\t\tif (removed === undefined) return false\n\t\tremoved.destroy()\n\t\tthis.#emitter.emit('remove', removed.id)\n\t\treturn true\n\t}\n\n\t#alive(): void {\n\t\tif (this.#destroyed) {\n\t\t\tthrow new ProgramError('DESTROYED', 'Program manager has been destroyed')\n\t\t}\n\t}\n}\n","import type {\n\tProgramDefinition,\n\tProgramInterface,\n\tProgramManagerInterface,\n\tProgramManagerOptions,\n\tProgramOptions,\n} from './types.js'\nimport { Program } from './programs/Program.js'\nimport { ProgramManager } from './programs/ProgramManager.js'\n\n/**\n * Creates one compiled {@link ProgramInterface} over a qualifier and rater.\n *\n * @remarks\n * If `options.validate` is `true`, the program validates the definition at\n * construction; if `false`, it compiles the definition unvalidated. Default:\n * {@link DEFAULT_PROGRAM_VALIDATE}. A standalone program creates and owns one\n * shared quantitative-plus-logical reason engine and injects it into the qualifier\n * and rater it creates; injected dependencies remain caller-owned.\n *\n * @param definition - The authored program definition\n * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks\n * @returns A {@link ProgramInterface}\n *\n * @example Compile a program and a manager\n * ```ts\n * import { buildProgramDefinition, createProgram, createProgramManager } from '@orkestrel/program'\n *\n * const definition = buildProgramDefinition('standard', 'Standard', qualification, rating)\n *\n * const program = createProgram(definition)\n * const manager = createProgramManager({ programs: [definition] })\n *\n * program.execute({ id: 'risk-1' })\n *\n * program.destroy()\n * manager.destroy()\n * ```\n */\nexport function createProgram(\n\tdefinition: ProgramDefinition,\n\toptions?: ProgramOptions,\n): ProgramInterface {\n\treturn new Program(definition, options)\n}\n\n/**\n * Creates one ordered {@link ProgramManagerInterface} over compiled programs.\n *\n * @remarks\n * Creates or borrows one shared reason engine, qualifier, and rater and injects\n * them into every compiled program, so a batch of definitions shares one engine.\n * Seed definitions are compiled in order.\n *\n * @param options - Optional injected qualifier, rater, engine, seed programs, validation, labels, and emitter hooks\n * @returns A {@link ProgramManagerInterface}\n *\n * @example\n * ```ts\n * import { createProgramManager } from '@orkestrel/program'\n *\n * const manager = createProgramManager({ programs: [definition] })\n * manager.program('standard')?.execute(subject)\n * manager.destroy()\n * ```\n */\nexport function createProgramManager(options?: ProgramManagerOptions): ProgramManagerInterface {\n\treturn new ProgramManager(options)\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkestrel/program",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "A program composition layer that orchestrates @orkestrel/qualifier and @orkestrel/rater into one execute workflow with notices, authority, status, decisions, and batch aggregation. Part of the @orkestrel line.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"aggregate",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
54
54
|
"copy": "node -e \"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\"",
|
|
55
55
|
"scaffold": "scaffold",
|
|
56
|
-
"lint": "oxlint --config .oxlintrc.json --fix
|
|
56
|
+
"lint": "oxlint --config .oxlintrc.json --fix .",
|
|
57
57
|
"check": "tsc --noEmit --project tsconfig.json && npm run check:src",
|
|
58
58
|
"check:src": "npm run check:src:core",
|
|
59
59
|
"check:src:core": "tsc --noEmit -p configs/src/tsconfig.core.json",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"test:src:core": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
|
|
66
66
|
"test:policy": "vitest run --config vite.config.ts --no-cache --reporter=dot --project policy",
|
|
67
67
|
"test:config": "vitest run --config vite.config.ts --no-cache --reporter=dot --project config",
|
|
68
|
-
"test:guides": "
|
|
68
|
+
"test:guides": "node --experimental-strip-types tests/guides.test.ts",
|
|
69
69
|
"build": "npm run clean && npm run build:src",
|
|
70
70
|
"build:src": "npm run build:src:core",
|
|
71
71
|
"build:src:core": "vite build --config configs/src/vite.core.config.ts && npm run copy dist/src/core/index.d.ts dist/src/core/index.d.cts",
|
|
@@ -77,25 +77,23 @@
|
|
|
77
77
|
"test:setup": "vitest run --config vite.config.ts --no-cache --reporter=dot --project setup"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"@orkestrel/contract": "^0.0.
|
|
81
|
-
"@orkestrel/emitter": "^0.0.
|
|
82
|
-
"@orkestrel/qualifier": "^0.0.
|
|
83
|
-
"@orkestrel/rater": "^0.0.
|
|
84
|
-
"@orkestrel/reason": "^0.0.
|
|
80
|
+
"@orkestrel/contract": "^0.0.17",
|
|
81
|
+
"@orkestrel/emitter": "^0.0.10",
|
|
82
|
+
"@orkestrel/qualifier": "^0.0.14",
|
|
83
|
+
"@orkestrel/rater": "^0.0.14",
|
|
84
|
+
"@orkestrel/reason": "^0.0.10"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
|
-
"@microsoft/api-extractor": "^7.59.
|
|
88
|
-
"@orkestrel/guide": "^0.0.
|
|
89
|
-
"@orkestrel/probe": "^0.0.
|
|
90
|
-
"@orkestrel/scaffold": "^0.0.
|
|
91
|
-
"@orkestrel/test": "^0.0.
|
|
92
|
-
"@types/node": "^26.
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"oxlint": "^1.80.0",
|
|
87
|
+
"@microsoft/api-extractor": "^7.59.1",
|
|
88
|
+
"@orkestrel/guide": "^0.0.18",
|
|
89
|
+
"@orkestrel/probe": "^0.0.12",
|
|
90
|
+
"@orkestrel/scaffold": "^0.0.64",
|
|
91
|
+
"@orkestrel/test": "^0.0.14",
|
|
92
|
+
"@types/node": "^26.5.1",
|
|
93
|
+
"oxfmt": "^0.67.0",
|
|
94
|
+
"oxlint": "^1.82.0",
|
|
96
95
|
"typescript": "^6.0.3",
|
|
97
|
-
"vite": "^8.
|
|
98
|
-
"vite-plugin-dts": "^5.0.3",
|
|
96
|
+
"vite": "^8.3.0",
|
|
99
97
|
"vitest": "^4.1.11"
|
|
100
98
|
},
|
|
101
99
|
"engines": {
|