@orkestrel/program 0.0.12 → 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.
@@ -1,25 +1,28 @@
1
- import { Eligibility } from '@orkestrel/qualifier';
2
- import { EmitterErrorHandler } from '@orkestrel/emitter';
3
- import { EmitterHooks } from '@orkestrel/emitter';
4
- import { EmitterInterface } from '@orkestrel/emitter';
5
- import { EvaluatorInterface } from '@orkestrel/reason';
6
- import { FieldPath } from '@orkestrel/contract';
7
- import { Guard } from '@orkestrel/contract';
8
- import { JSONValue } from '@orkestrel/contract';
9
- import { LineDefinition } from '@orkestrel/rater';
10
- import { LogicalDefinition } from '@orkestrel/reason';
11
- import { LogicalResult } from '@orkestrel/reason';
12
- import { Premise } from '@orkestrel/qualifier';
13
- import { QualificationDefinition } from '@orkestrel/qualifier';
14
- import { QualificationResult } from '@orkestrel/qualifier';
15
- import { QualifierInterface } from '@orkestrel/qualifier';
16
- import { RaterInterface } from '@orkestrel/rater';
17
- import { RatingDefinition } from '@orkestrel/rater';
18
- import { RatingResult } from '@orkestrel/rater';
19
- import { ReasonInterface } from '@orkestrel/reason';
20
- import { Subject } from '@orkestrel/reason';
21
-
22
- /** Names the reserved working-subject key a batch's aggregate projection is written under. */
1
+ import type { Eligibility } from '@orkestrel/qualifier';
2
+ import type { EmitterErrorHandler } from '@orkestrel/emitter';
3
+ import type { EmitterHooks } from '@orkestrel/emitter';
4
+ import type { EmitterInterface } from '@orkestrel/emitter';
5
+ import type { EvaluatorInterface } from '@orkestrel/reason';
6
+ import type { FieldPath } from '@orkestrel/contract';
7
+ import type { Guard } from '@orkestrel/contract';
8
+ import type { JSONValue } from '@orkestrel/contract';
9
+ import type { LineDefinition } from '@orkestrel/rater';
10
+ import type { LogicalDefinition } from '@orkestrel/reason';
11
+ import type { LogicalResult } from '@orkestrel/reason';
12
+ import type { Premise } from '@orkestrel/qualifier';
13
+ import type { QualificationDefinition } from '@orkestrel/qualifier';
14
+ import type { QualificationResult } from '@orkestrel/qualifier';
15
+ import type { QualifierInterface } from '@orkestrel/qualifier';
16
+ import type { RaterInterface } from '@orkestrel/rater';
17
+ import type { RatingDefinition } from '@orkestrel/rater';
18
+ import type { RatingResult } from '@orkestrel/rater';
19
+ import type { ReasonInterface } from '@orkestrel/reason';
20
+ import type { Subject } from '@orkestrel/reason';
21
+
22
+ /**
23
+ * Names the reserved working-subject key a batch's aggregate projection is written
24
+ * under, `'aggregate'`.
25
+ */
23
26
  export declare const AGGREGATE_KEY = "aggregate";
24
27
 
25
28
  /** Describes batch aggregate fields, an optional partition field, and optional gates. */
@@ -158,6 +161,10 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
158
161
  /**
159
162
  * Builds a fresh {@link AggregateDefinition}.
160
163
  *
164
+ * @remarks
165
+ * `fields` is copied into a fresh array; an absent `partition` or `gates` is
166
+ * omitted entirely rather than stored as `undefined`.
167
+ *
161
168
  * @param fields - The aggregate fields to sum across a batch
162
169
  * @param input - Optional partition field and aggregate gates
163
170
  * @returns A fresh aggregate definition
@@ -176,7 +183,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
176
183
  *
177
184
  * @remarks
178
185
  * The projection carries the whole-batch `count` and `sums` plus the subject's
179
- * OWN partition, located by the same {@link formatGroupKey} key
186
+ * own partition, located by the same {@link formatGroupKey} key
180
187
  * {@link aggregateGroups} partitions under.
181
188
  *
182
189
  * @param subject - The subject to project for
@@ -224,7 +231,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
224
231
  * @remarks
225
232
  * `count` is the subject count, `trace` / `errors` accumulate every subject's
226
233
  * plus the batch aggregate-gate evaluation's (`options.gates`), and `success`
227
- * requires every subject execution to succeed AND the gate evaluation to have
234
+ * requires every subject execution to succeed and the gate evaluation to have
228
235
  * produced no errors. A fired aggregate gate contributes a `limit`
229
236
  * determination, never a technical failure (a non-logical gate result is a
230
237
  * caller-facing `MISMATCH` thrown by `Program` before this assembles).
@@ -310,6 +317,9 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
310
317
  /**
311
318
  * Builds a fresh {@link Notice}.
312
319
  *
320
+ * @remarks
321
+ * An absent `scope` is omitted entirely rather than stored as `undefined`.
322
+ *
313
323
  * @param id - The notice id
314
324
  * @param message - The message template, carrying optional `{{token}}` placeholders
315
325
  * @param input - Optional presentation scope
@@ -401,8 +411,8 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
401
411
  * qualification succeeded, rating (when it ran) succeeded, and authority (when it
402
412
  * ran) produced no errors — a valid ineligible or referral outcome still
403
413
  * succeeds. `trace` and `errors` accumulate the qualification's, every rated
404
- * line's worksheet trail, and the authority's. A `decision` is present ONLY when
405
- * an authority ran (`options.authority`), the execution SUCCEEDED (`success`),
414
+ * line's worksheet trail, and the authority's. A `decision` is present only when
415
+ * an authority ran (`options.authority`), the execution succeeded (`success`),
406
416
  * no `limit` determination applied, and status is not `unrated`.
407
417
  *
408
418
  * @param definition - The authored program definition
@@ -463,33 +473,38 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
463
473
  export declare function completeTallies(entries: Partial<Record<Status, Tally>>): Readonly<Record<Status, Tally>>;
464
474
 
465
475
  /**
466
- * Creates one compiled program over a qualifier and rater.
476
+ * Creates one compiled {@link ProgramInterface} over a qualifier and rater.
467
477
  *
468
478
  * @remarks
469
479
  * If `options.validate` is `true`, the program validates the definition at
470
480
  * construction; if `false`, it compiles the definition unvalidated. Default:
471
- * {@link DEFAULT_PROGRAM_VALIDATE}. A standalone program creates and
472
- * OWNS one shared quantitative-plus-logical reason engine and injects it into the
473
- * qualifier and rater it creates; injected dependencies remain caller-owned.
481
+ * {@link DEFAULT_PROGRAM_VALIDATE}. A standalone program creates and owns one
482
+ * shared quantitative-plus-logical reason engine and injects it into the qualifier
483
+ * and rater it creates; injected dependencies remain caller-owned.
474
484
  *
475
485
  * @param definition - The authored program definition
476
486
  * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks
477
487
  * @returns A {@link ProgramInterface}
478
488
  *
479
- * @example
489
+ * @example Compile a program and a manager
480
490
  * ```ts
481
- * import { buildProgramDefinition, createProgram } from '@orkestrel/program'
491
+ * import { buildProgramDefinition, createProgram, createProgramManager } from '@orkestrel/program'
482
492
  *
483
493
  * const definition = buildProgramDefinition('standard', 'Standard', qualification, rating)
494
+ *
484
495
  * const program = createProgram(definition)
496
+ * const manager = createProgramManager({ programs: [definition] })
497
+ *
485
498
  * program.execute({ id: 'risk-1' })
499
+ *
486
500
  * program.destroy()
501
+ * manager.destroy()
487
502
  * ```
488
503
  */
489
504
  export declare function createProgram(definition: ProgramDefinition, options?: ProgramOptions): ProgramInterface;
490
505
 
491
506
  /**
492
- * Creates one ordered manager over compiled programs.
507
+ * Creates one ordered {@link ProgramManagerInterface} over compiled programs.
493
508
  *
494
509
  * @remarks
495
510
  * Creates or borrows one shared reason engine, qualifier, and rater and injects
@@ -529,7 +544,10 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
529
544
  /** Identifies a final authority outcome, derived from global eligibility. */
530
545
  export declare type Decision = 'approved' | 'denied' | 'submitted';
531
546
 
532
- /** Names the default definition validation policy for `createProgram` / `ProgramManager.add`. */
547
+ /**
548
+ * Names the default definition validation policy, `true`, for `createProgram` /
549
+ * `ProgramManager.add`.
550
+ */
533
551
  export declare const DEFAULT_PROGRAM_VALIDATE = true;
534
552
 
535
553
  /**
@@ -540,9 +558,9 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
540
558
  * Explicit policy, not an opaque precedence reduce: global
541
559
  * ineligibility or referral is terminal; a scoped referral yields `referral`;
542
560
  * an applied `condition` or an applied scoped `restriction` (a line was
543
- * removed but others rated) is `conditional`. When the definition OMITS
561
+ * removed but others rated) is `conditional`. When the definition omits
544
562
  * `rating` the program is eligibility-only — status resolves to `conditional`
545
- * or `eligible` and is NEVER `unrated`. Otherwise a subject with no successful
563
+ * or `eligible` and is never `unrated`. Otherwise a subject with no successful
546
564
  * rating is `unrated`.
547
565
  *
548
566
  * @param definition - The authored program definition
@@ -600,7 +618,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
600
618
  * @remarks
601
619
  * The key is the resolved field coerced with `String` — `undefined` collapses
602
620
  * to the empty string, so a subject missing the field and a subject whose
603
- * field is literally `''` land in the SAME partition, and a numeric `1`
621
+ * field is literally `''` land in the same partition, and a numeric `1`
604
622
  * collides with the string `'1'`.
605
623
  *
606
624
  * @param subject - The subject to key
@@ -924,19 +942,22 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
924
942
  readonly scope?: string;
925
943
  }
926
944
 
927
- /** Names the reserved working-subject key the authority's outcome projection is written under. */
945
+ /**
946
+ * Names the reserved working-subject key the authority's outcome projection is
947
+ * written under, `'outcome'`.
948
+ */
928
949
  export declare const OUTCOME_KEY = "outcome";
929
950
 
930
951
  /**
931
- * Composes one qualifier and one rater over a shared reason engine and executes
932
- * single subjects or aggregate-aware batches.
952
+ * Composes one qualifier and one rater over a shared reason engine, compiling one
953
+ * authored definition and executing single subjects or aggregate-aware batches.
933
954
  *
934
955
  * @remarks
935
956
  * Qualification decides whether rating happens: a globally ineligible, referred,
936
957
  * or failed subject never reaches the rater, and a scoped ineligibility removes
937
958
  * only its line before the first rating call. The rater always receives the
938
- * ORIGINAL subject; the qualifier's aggregate projection stays private. When no
939
- * qualifier, rater, or engine is injected the program creates ONE shared
959
+ * original subject; the qualifier's aggregate projection stays private. When no
960
+ * qualifier, rater, or engine is injected the program creates one shared
940
961
  * quantitative-plus-logical engine, injects it into the qualifier and rater it
941
962
  * creates, and destroys only what it owns. A definition failure during
942
963
  * construction (an invalid definition under `options.validate`) tears down
@@ -946,8 +967,8 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
946
967
  * or `Date` reached through a reason `Check.value` is cloned but remains mutable
947
968
  * because its contents live in internal slots. Uncloneable values and non-empty
948
969
  * typed arrays are refused with `ProgramError('DEFINITION')` and the host error
949
- * as its cause. `destroy()` is idempotent and REENTRANCY-SAFE — the destroyed
950
- * flag is set BEFORE any teardown or the `destroy` event fires, so a listener
970
+ * as its cause. `destroy()` is idempotent and reentrancy-safe — the destroyed
971
+ * flag is set before any teardown or the `destroy` event fires, so a listener
951
972
  * that re-enters `destroy()` is a no-op — and tears the emitter down last.
952
973
  */
953
974
  export declare class Program implements ProgramInterface {
@@ -1026,7 +1047,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1026
1047
  * Qualification decides whether rating happens: a globally ineligible, referred,
1027
1048
  * or failed subject never reaches the rater, and a scoped ineligibility removes
1028
1049
  * only its line before the first rating call. The rater always receives the
1029
- * ORIGINAL subject. Notices, status, optional authority, and the optional
1050
+ * original subject. Notices, status, optional authority, and the optional
1030
1051
  * decision follow, in that order.
1031
1052
  *
1032
1053
  * @param subject - The subject to execute
@@ -1078,7 +1099,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1078
1099
  * Destroys this program, idempotently.
1079
1100
  *
1080
1101
  * @remarks
1081
- * The destroyed flag is set BEFORE any teardown or the `destroy` event, so a
1102
+ * The destroyed flag is set before any teardown or the `destroy` event, so a
1082
1103
  * listener re-entering `destroy` is a no-op. An owned qualifier, rater, and reason
1083
1104
  * engine are destroyed; an injected one stays caller-owned. The emitter is torn
1084
1105
  * down last, and stays reachable afterwards.
@@ -1103,7 +1124,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1103
1124
  * over the lines scoped eligibility left standing, through `@orkestrel/rater`.
1104
1125
  * `authority` (a logical definition) runs last, over the assembled result
1105
1126
  * extended with an outcome projection, to derive limit determinations and the
1106
- * final decision. An omitted `rating` authors an ELIGIBILITY-ONLY program — the
1127
+ * final decision. An omitted `rating` authors an eligibility-only program — the
1107
1128
  * rater is never invoked, an eligible subject resolves to `'eligible'` (or
1108
1129
  * `'conditional'` under an applied condition or scoped restriction), status is
1109
1130
  * never `'unrated'`, and decisions remain reachable through `authority`. Program
@@ -1130,12 +1151,13 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1130
1151
  export declare type ProgramEffect = 'notice' | 'limit';
1131
1152
 
1132
1153
  /**
1133
- * Reports a coded programmer error thrown by the program layer.
1154
+ * Reports a coded programmer error thrown by the program layer, carrying a
1155
+ * machine-readable code and an optional context and cause.
1134
1156
  *
1135
1157
  * @remarks
1136
1158
  * `DUPLICATE` — a program id collision on `ProgramManager.add`, or a duplicate
1137
- * authored rating-line or notice id. `MISSING` — an
1138
- * authored notice or qualification ruling scope names no rating line.
1159
+ * authored rating-line or notice id. `MISSING` — an authored notice or
1160
+ * qualification ruling scope names no rating line.
1139
1161
  * `DEFINITION` — a program, qualification, rating, authority, or aggregate
1140
1162
  * policy failed validation. `MISMATCH` — an injected entity or a returned
1141
1163
  * reason result has the wrong contract. `RESERVED` — a subject already
@@ -1255,7 +1277,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1255
1277
  * Qualification decides whether rating happens: a globally ineligible, referred,
1256
1278
  * or failed subject never reaches the rater, and a scoped ineligibility removes
1257
1279
  * only its line before the first rating call. The rater always receives the
1258
- * ORIGINAL subject. Notices, status, optional authority, and the optional
1280
+ * original subject. Notices, status, optional authority, and the optional
1259
1281
  * decision follow, in that order.
1260
1282
  *
1261
1283
  * @param subject - The subject to execute
@@ -1307,7 +1329,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1307
1329
  * Destroys this program, idempotently.
1308
1330
  *
1309
1331
  * @remarks
1310
- * The destroyed flag is set BEFORE any teardown or the `destroy` event, so a
1332
+ * The destroyed flag is set before any teardown or the `destroy` event, so a
1311
1333
  * listener re-entering `destroy` is a no-op. An owned qualifier, rater, and reason
1312
1334
  * engine are destroyed; an injected one stays caller-owned. The emitter is torn
1313
1335
  * down last, and stays reachable afterwards.
@@ -1329,14 +1351,14 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1329
1351
  * qualifier, rater, and reason engine across every program it compiles.
1330
1352
  *
1331
1353
  * @remarks
1332
- * OWNS its ordered `#programs` collection and its own {@link Emitter} over
1354
+ * owns its ordered `#programs` collection and its own {@link Emitter} over
1333
1355
  * {@link ProgramManagerEventMap}. Creates or borrows one shared engine, qualifier,
1334
1356
  * and rater and injects the same instances into every compiled program. `remove`
1335
1357
  * destroys the programs it removes; `destroy()` removes all programs, then
1336
- * destroys only the owned shared dependencies, and tears the emitter down LAST.
1358
+ * destroys only the owned shared dependencies, and tears the emitter down last.
1337
1359
  * A seed-program failure during construction tears the manager down (destroying
1338
1360
  * whatever had already been compiled) before rethrowing the original error.
1339
- * `destroy()` is REENTRANCY-SAFE — the destroyed flag is set BEFORE any teardown
1361
+ * `destroy()` is reentrancy-safe — the destroyed flag is set before any teardown
1340
1362
  * or the `remove` / `destroy` events fire, so a `remove` listener that re-enters
1341
1363
  * `destroy()` is a no-op. Every call after `destroy()` throws {@link ProgramError}
1342
1364
  * `'DESTROYED'`.
@@ -1535,7 +1557,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1535
1557
  * Destroys this manager, idempotently.
1536
1558
  *
1537
1559
  * @remarks
1538
- * The destroyed flag is set BEFORE any teardown or the `remove` and `destroy`
1560
+ * The destroyed flag is set before any teardown or the `remove` and `destroy`
1539
1561
  * events, so a `remove` listener re-entering `destroy` is a no-op. Compiled
1540
1562
  * programs are destroyed first, then an owned qualifier, rater, and reason engine;
1541
1563
  * an injected one stays caller-owned. The emitter is torn down last, and stays
@@ -1725,7 +1747,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1725
1747
  * Destroys this manager, idempotently.
1726
1748
  *
1727
1749
  * @remarks
1728
- * The destroyed flag is set BEFORE any teardown or the `remove` and `destroy`
1750
+ * The destroyed flag is set before any teardown or the `remove` and `destroy`
1729
1751
  * events, so a `remove` listener re-entering `destroy` is a no-op. Compiled
1730
1752
  * programs are destroyed first, then an owned qualifier, rater, and reason engine;
1731
1753
  * an injected one stays caller-owned. The emitter is torn down last, and stays
@@ -1802,7 +1824,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1802
1824
  * Holds the final authority outcome.
1803
1825
  *
1804
1826
  * @remarks
1805
- * Present ONLY when the program HAS an `authority`, the execution SUCCEEDED
1827
+ * Present only when the program has an `authority`, the execution succeeded
1806
1828
  * (qualification, rating when it ran, and authority all produced no errors),
1807
1829
  * no `limit` determination applied, and status is not `unrated`.
1808
1830
  */
@@ -1829,7 +1851,7 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1829
1851
  * A scope names a rating-line id. A line survives when its scope is absent
1830
1852
  * (eligible by default), `eligible`, or a `condition` (which is not an
1831
1853
  * eligibility value and never appears here). A scoped `ineligible` or `referral`
1832
- * removes the line BEFORE the rater is invoked — the excluded line is never
1854
+ * removes the line before the rater is invoked — the excluded line is never
1833
1855
  * evaluated merely to discard its amount.
1834
1856
  *
1835
1857
  * @param lines - The program's authored rating lines
@@ -1848,14 +1870,17 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
1848
1870
  /** Identifies the presentation and tally status derived from eligibility, conditions, and rating success. */
1849
1871
  export declare type Status = (typeof STATUSES)[number];
1850
1872
 
1851
- /** Lists every {@link Status} literal — the source the union and its guard derive from. */
1873
+ /**
1874
+ * Lists every {@link Status} literal in tally order — the source the union and its
1875
+ * guard derive from.
1876
+ */
1852
1877
  export declare const STATUSES: readonly ["ineligible", "referral", "conditional", "unrated", "eligible"];
1853
1878
 
1854
1879
  /**
1855
1880
  * Folds one subject's finite aggregate field values into a sums record.
1856
1881
  *
1857
1882
  * @remarks
1858
- * Returns a FRESH record — `sums` is never mutated. Only finite numbers
1883
+ * Returns a fresh record — `sums` is never mutated. Only finite numbers
1859
1884
  * contribute; a non-numeric or absent value contributes zero (never a
1860
1885
  * coercion). A {@link FieldPath} may be nested — `formatField` renders the
1861
1886
  * dot-joined key the returned record is keyed by.
@@ -4,9 +4,15 @@ import { createRater, isRatingDefinition, isRatingResult } from "@orkestrel/rate
4
4
  import { createEvaluator, createLogicalReasoner, createQuantitativeReasoner, createReason, findDuplicates, formatField, isFieldPath, isLogicalDefinition, isLogicalResult, isReasonValidationResult } from "@orkestrel/reason";
5
5
  import { Emitter } from "@orkestrel/emitter";
6
6
  //#region src/core/constants.ts
7
- /** Names the default definition validation policy for `createProgram` / `ProgramManager.add`. */
7
+ /**
8
+ * Names the default definition validation policy, `true`, for `createProgram` /
9
+ * `ProgramManager.add`.
10
+ */
8
11
  var DEFAULT_PROGRAM_VALIDATE = true;
9
- /** Lists every {@link Status} literal — the source the union and its guard derive from. */
12
+ /**
13
+ * Lists every {@link Status} literal in tally order — the source the union and its
14
+ * guard derive from.
15
+ */
10
16
  var STATUSES = Object.freeze([
11
17
  "ineligible",
12
18
  "referral",
@@ -20,19 +26,26 @@ var ELIGIBILITY_DECISIONS = Object.freeze({
20
26
  ineligible: "denied",
21
27
  referral: "submitted"
22
28
  });
23
- /** Names the reserved working-subject key a batch's aggregate projection is written under. */
29
+ /**
30
+ * Names the reserved working-subject key a batch's aggregate projection is written
31
+ * under, `'aggregate'`.
32
+ */
24
33
  var AGGREGATE_KEY = "aggregate";
25
- /** Names the reserved working-subject key the authority's outcome projection is written under. */
34
+ /**
35
+ * Names the reserved working-subject key the authority's outcome projection is
36
+ * written under, `'outcome'`.
37
+ */
26
38
  var OUTCOME_KEY = "outcome";
27
39
  //#endregion
28
40
  //#region src/core/errors.ts
29
41
  /**
30
- * Reports a coded programmer error thrown by the program layer.
42
+ * Reports a coded programmer error thrown by the program layer, carrying a
43
+ * machine-readable code and an optional context and cause.
31
44
  *
32
45
  * @remarks
33
46
  * `DUPLICATE` — a program id collision on `ProgramManager.add`, or a duplicate
34
- * authored rating-line or notice id. `MISSING` — an
35
- * authored notice or qualification ruling scope names no rating line.
47
+ * authored rating-line or notice id. `MISSING` — an authored notice or
48
+ * qualification ruling scope names no rating line.
36
49
  * `DEFINITION` — a program, qualification, rating, authority, or aggregate
37
50
  * policy failed validation. `MISMATCH` — an injected entity or a returned
38
51
  * reason result has the wrong contract. `RESERVED` — a subject already
@@ -452,7 +465,7 @@ function assertProgramSubject(subject) {
452
465
  * A scope names a rating-line id. A line survives when its scope is absent
453
466
  * (eligible by default), `eligible`, or a `condition` (which is not an
454
467
  * eligibility value and never appears here). A scoped `ineligible` or `referral`
455
- * removes the line BEFORE the rater is invoked — the excluded line is never
468
+ * removes the line before the rater is invoked — the excluded line is never
456
469
  * evaluated merely to discard its amount.
457
470
  *
458
471
  * @param lines - The program's authored rating lines
@@ -480,9 +493,9 @@ function selectProgramLines(lines, scopes) {
480
493
  * Explicit policy, not an opaque precedence reduce: global
481
494
  * ineligibility or referral is terminal; a scoped referral yields `referral`;
482
495
  * an applied `condition` or an applied scoped `restriction` (a line was
483
- * removed but others rated) is `conditional`. When the definition OMITS
496
+ * removed but others rated) is `conditional`. When the definition omits
484
497
  * `rating` the program is eligibility-only — status resolves to `conditional`
485
- * or `eligible` and is NEVER `unrated`. Otherwise a subject with no successful
498
+ * or `eligible` and is never `unrated`. Otherwise a subject with no successful
486
499
  * rating is `unrated`.
487
500
  *
488
501
  * @param definition - The authored program definition
@@ -633,8 +646,8 @@ function buildOutcomeProjection(result) {
633
646
  * qualification succeeded, rating (when it ran) succeeded, and authority (when it
634
647
  * ran) produced no errors — a valid ineligible or referral outcome still
635
648
  * succeeds. `trace` and `errors` accumulate the qualification's, every rated
636
- * line's worksheet trail, and the authority's. A `decision` is present ONLY when
637
- * an authority ran (`options.authority`), the execution SUCCEEDED (`success`),
649
+ * line's worksheet trail, and the authority's. A `decision` is present only when
650
+ * an authority ran (`options.authority`), the execution succeeded (`success`),
638
651
  * no `limit` determination applied, and status is not `unrated`.
639
652
  *
640
653
  * @param definition - The authored program definition
@@ -864,7 +877,7 @@ function validateProgramDefinition(definition, qualifier, engine) {
864
877
  * @remarks
865
878
  * The key is the resolved field coerced with `String` — `undefined` collapses
866
879
  * to the empty string, so a subject missing the field and a subject whose
867
- * field is literally `''` land in the SAME partition, and a numeric `1`
880
+ * field is literally `''` land in the same partition, and a numeric `1`
868
881
  * collides with the string `'1'`.
869
882
  *
870
883
  * @param subject - The subject to key
@@ -885,7 +898,7 @@ function formatGroupKey(subject, partition) {
885
898
  * Folds one subject's finite aggregate field values into a sums record.
886
899
  *
887
900
  * @remarks
888
- * Returns a FRESH record — `sums` is never mutated. Only finite numbers
901
+ * Returns a fresh record — `sums` is never mutated. Only finite numbers
889
902
  * contribute; a non-numeric or absent value contributes zero (never a
890
903
  * coercion). A {@link FieldPath} may be nested — `formatField` renders the
891
904
  * dot-joined key the returned record is keyed by.
@@ -975,7 +988,7 @@ function aggregateGroups(subjects, fields, partition) {
975
988
  *
976
989
  * @remarks
977
990
  * The projection carries the whole-batch `count` and `sums` plus the subject's
978
- * OWN partition, located by the same {@link formatGroupKey} key
991
+ * own partition, located by the same {@link formatGroupKey} key
979
992
  * {@link aggregateGroups} partitions under.
980
993
  *
981
994
  * @param subject - The subject to project for
@@ -1139,7 +1152,7 @@ function tallySubject(tallies, result, subject, fields) {
1139
1152
  * @remarks
1140
1153
  * `count` is the subject count, `trace` / `errors` accumulate every subject's
1141
1154
  * plus the batch aggregate-gate evaluation's (`options.gates`), and `success`
1142
- * requires every subject execution to succeed AND the gate evaluation to have
1155
+ * requires every subject execution to succeed and the gate evaluation to have
1143
1156
  * produced no errors. A fired aggregate gate contributes a `limit`
1144
1157
  * determination, never a technical failure (a non-logical gate result is a
1145
1158
  * caller-facing `MISMATCH` thrown by `Program` before this assembles).
@@ -1218,6 +1231,9 @@ function buildProgramDefinition(id, name, qualification, rating, input) {
1218
1231
  /**
1219
1232
  * Builds a fresh {@link Notice}.
1220
1233
  *
1234
+ * @remarks
1235
+ * An absent `scope` is omitted entirely rather than stored as `undefined`.
1236
+ *
1221
1237
  * @param id - The notice id
1222
1238
  * @param message - The message template, carrying optional `{{token}}` placeholders
1223
1239
  * @param input - Optional presentation scope
@@ -1240,6 +1256,10 @@ function buildNotice(id, message, input) {
1240
1256
  /**
1241
1257
  * Builds a fresh {@link AggregateDefinition}.
1242
1258
  *
1259
+ * @remarks
1260
+ * `fields` is copied into a fresh array; an absent `partition` or `gates` is
1261
+ * omitted entirely rather than stored as `undefined`.
1262
+ *
1243
1263
  * @param fields - The aggregate fields to sum across a batch
1244
1264
  * @param input - Optional partition field and aggregate gates
1245
1265
  * @returns A fresh aggregate definition
@@ -1261,15 +1281,15 @@ function buildAggregateDefinition(fields, input) {
1261
1281
  //#endregion
1262
1282
  //#region src/core/programs/Program.ts
1263
1283
  /**
1264
- * Composes one qualifier and one rater over a shared reason engine and executes
1265
- * single subjects or aggregate-aware batches.
1284
+ * Composes one qualifier and one rater over a shared reason engine, compiling one
1285
+ * authored definition and executing single subjects or aggregate-aware batches.
1266
1286
  *
1267
1287
  * @remarks
1268
1288
  * Qualification decides whether rating happens: a globally ineligible, referred,
1269
1289
  * or failed subject never reaches the rater, and a scoped ineligibility removes
1270
1290
  * only its line before the first rating call. The rater always receives the
1271
- * ORIGINAL subject; the qualifier's aggregate projection stays private. When no
1272
- * qualifier, rater, or engine is injected the program creates ONE shared
1291
+ * original subject; the qualifier's aggregate projection stays private. When no
1292
+ * qualifier, rater, or engine is injected the program creates one shared
1273
1293
  * quantitative-plus-logical engine, injects it into the qualifier and rater it
1274
1294
  * creates, and destroys only what it owns. A definition failure during
1275
1295
  * construction (an invalid definition under `options.validate`) tears down
@@ -1279,8 +1299,8 @@ function buildAggregateDefinition(fields, input) {
1279
1299
  * or `Date` reached through a reason `Check.value` is cloned but remains mutable
1280
1300
  * because its contents live in internal slots. Uncloneable values and non-empty
1281
1301
  * typed arrays are refused with `ProgramError('DEFINITION')` and the host error
1282
- * as its cause. `destroy()` is idempotent and REENTRANCY-SAFE — the destroyed
1283
- * flag is set BEFORE any teardown or the `destroy` event fires, so a listener
1302
+ * as its cause. `destroy()` is idempotent and reentrancy-safe — the destroyed
1303
+ * flag is set before any teardown or the `destroy` event fires, so a listener
1284
1304
  * that re-enters `destroy()` is a no-op — and tears the emitter down last.
1285
1305
  */
1286
1306
  var Program = class {
@@ -1408,7 +1428,7 @@ var Program = class {
1408
1428
  * Destroys this program, idempotently.
1409
1429
  *
1410
1430
  * @remarks
1411
- * The destroyed flag is set BEFORE any teardown or the `destroy` event, so a
1431
+ * The destroyed flag is set before any teardown or the `destroy` event, so a
1412
1432
  * listener re-entering `destroy` is a no-op. An owned qualifier, rater, and reason
1413
1433
  * engine are destroyed; an injected one stays caller-owned. The emitter is torn
1414
1434
  * down last, and stays reachable afterwards.
@@ -1517,14 +1537,14 @@ var Program = class {
1517
1537
  * qualifier, rater, and reason engine across every program it compiles.
1518
1538
  *
1519
1539
  * @remarks
1520
- * OWNS its ordered `#programs` collection and its own {@link Emitter} over
1540
+ * owns its ordered `#programs` collection and its own {@link Emitter} over
1521
1541
  * {@link ProgramManagerEventMap}. Creates or borrows one shared engine, qualifier,
1522
1542
  * and rater and injects the same instances into every compiled program. `remove`
1523
1543
  * destroys the programs it removes; `destroy()` removes all programs, then
1524
- * destroys only the owned shared dependencies, and tears the emitter down LAST.
1544
+ * destroys only the owned shared dependencies, and tears the emitter down last.
1525
1545
  * A seed-program failure during construction tears the manager down (destroying
1526
1546
  * whatever had already been compiled) before rethrowing the original error.
1527
- * `destroy()` is REENTRANCY-SAFE — the destroyed flag is set BEFORE any teardown
1547
+ * `destroy()` is reentrancy-safe — the destroyed flag is set before any teardown
1528
1548
  * or the `remove` / `destroy` events fire, so a `remove` listener that re-enters
1529
1549
  * `destroy()` is a no-op. Every call after `destroy()` throws {@link ProgramError}
1530
1550
  * `'DESTROYED'`.
@@ -1734,7 +1754,7 @@ var ProgramManager = class {
1734
1754
  * Destroys this manager, idempotently.
1735
1755
  *
1736
1756
  * @remarks
1737
- * The destroyed flag is set BEFORE any teardown or the `remove` and `destroy`
1757
+ * The destroyed flag is set before any teardown or the `remove` and `destroy`
1738
1758
  * events, so a `remove` listener re-entering `destroy` is a no-op. Compiled
1739
1759
  * programs are destroyed first, then an owned qualifier, rater, and reason engine;
1740
1760
  * an injected one stays caller-owned. The emitter is torn down last, and stays
@@ -1781,34 +1801,39 @@ var ProgramManager = class {
1781
1801
  //#endregion
1782
1802
  //#region src/core/factories.ts
1783
1803
  /**
1784
- * Creates one compiled program over a qualifier and rater.
1804
+ * Creates one compiled {@link ProgramInterface} over a qualifier and rater.
1785
1805
  *
1786
1806
  * @remarks
1787
1807
  * If `options.validate` is `true`, the program validates the definition at
1788
1808
  * construction; if `false`, it compiles the definition unvalidated. Default:
1789
- * {@link DEFAULT_PROGRAM_VALIDATE}. A standalone program creates and
1790
- * OWNS one shared quantitative-plus-logical reason engine and injects it into the
1791
- * qualifier and rater it creates; injected dependencies remain caller-owned.
1809
+ * {@link DEFAULT_PROGRAM_VALIDATE}. A standalone program creates and owns one
1810
+ * shared quantitative-plus-logical reason engine and injects it into the qualifier
1811
+ * and rater it creates; injected dependencies remain caller-owned.
1792
1812
  *
1793
1813
  * @param definition - The authored program definition
1794
1814
  * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks
1795
1815
  * @returns A {@link ProgramInterface}
1796
1816
  *
1797
- * @example
1817
+ * @example Compile a program and a manager
1798
1818
  * ```ts
1799
- * import { buildProgramDefinition, createProgram } from '@orkestrel/program'
1819
+ * import { buildProgramDefinition, createProgram, createProgramManager } from '@orkestrel/program'
1800
1820
  *
1801
1821
  * const definition = buildProgramDefinition('standard', 'Standard', qualification, rating)
1822
+ *
1802
1823
  * const program = createProgram(definition)
1824
+ * const manager = createProgramManager({ programs: [definition] })
1825
+ *
1803
1826
  * program.execute({ id: 'risk-1' })
1827
+ *
1804
1828
  * program.destroy()
1829
+ * manager.destroy()
1805
1830
  * ```
1806
1831
  */
1807
1832
  function createProgram(definition, options) {
1808
1833
  return new Program(definition, options);
1809
1834
  }
1810
1835
  /**
1811
- * Creates one ordered manager over compiled programs.
1836
+ * Creates one ordered {@link ProgramManagerInterface} over compiled programs.
1812
1837
  *
1813
1838
  * @remarks
1814
1839
  * Creates or borrows one shared reason engine, qualifier, and rater and injects