@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.
@@ -1,51 +1,38 @@
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
- /** 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
- /** Batch aggregate fields, an optional partition key, and optional gates. */
28
+ /** Describes batch aggregate fields, an optional partition field, and optional gates. */
26
29
  export declare interface AggregateDefinition {
27
30
  readonly fields: readonly FieldPath[];
28
- readonly by?: FieldPath;
31
+ readonly partition?: FieldPath;
29
32
  readonly gates?: LogicalDefinition;
30
33
  }
31
34
 
32
- /**
33
- * Build an {@link AggregateDefinition}.
34
- *
35
- * @param fields - The aggregate fields to sum across a batch
36
- * @param input - Optional partition field and aggregate gates
37
- * @returns A fresh aggregate definition
38
- *
39
- * @example
40
- * ```ts
41
- * import { aggregateDefinition } from '@orkestrel/program'
42
- *
43
- * aggregateDefinition(['amount'], { by: 'location' })
44
- * ```
45
- */
46
- export declare function aggregateDefinition(fields: readonly FieldPath[], input?: AggregateInput): AggregateDefinition;
47
-
48
- /** One batch aggregate partition. */
35
+ /** Describes one batch aggregate partition. */
49
36
  export declare interface AggregateGroup {
50
37
  readonly key: string;
51
38
  readonly count: number;
@@ -53,7 +40,7 @@ export declare interface AggregateGroup {
53
40
  }
54
41
 
55
42
  /**
56
- * Partition a batch of subjects by a field, summing aggregate fields per key.
43
+ * Partitions a batch of subjects by a field, summing aggregate fields per key.
57
44
  *
58
45
  * @remarks
59
46
  * The partition key is derived by {@link formatGroupKey}. Group order follows
@@ -61,8 +48,8 @@ export declare interface AggregateGroup {
61
48
  *
62
49
  * @param subjects - The batch of subjects
63
50
  * @param fields - The fields to sum within each partition
64
- * @param by - The partition key field; no partition is built when absent
65
- * @returns A fresh list of aggregate groups, or an empty list when `by` is absent
51
+ * @param partition - The field the batch partitions on; no partition is built when absent
52
+ * @returns A fresh list of aggregate groups, or an empty list when `partition` is absent
66
53
  *
67
54
  * @example
68
55
  * ```ts
@@ -71,29 +58,29 @@ export declare interface AggregateGroup {
71
58
  * aggregateGroups([{ location: 'east', amount: 5 }], ['amount'], 'location')
72
59
  * ```
73
60
  */
74
- export declare function aggregateGroups(subjects: readonly Subject[], fields: readonly FieldPath[], by?: FieldPath): readonly AggregateGroup[];
61
+ export declare function aggregateGroups(subjects: readonly Subject[], fields: readonly FieldPath[], partition?: FieldPath): readonly AggregateGroup[];
75
62
 
76
63
  /**
77
- * Optional fields accepted by `aggregateDefinition`.
64
+ * Describes the optional fields accepted by `buildAggregateDefinition`.
78
65
  *
79
66
  * @remarks
80
- * `by` — the partition key field; omitted skips partitioning. `gates` — a
81
- * logical definition evaluated once over the whole batch to derive `limit`
82
- * determinations.
67
+ * `partition` — the field a batch partitions on; omitted skips partitioning.
68
+ * `gates` — a logical definition evaluated once over the whole batch to derive
69
+ * `limit` determinations.
83
70
  */
84
71
  export declare interface AggregateInput {
85
- readonly by?: FieldPath;
72
+ readonly partition?: FieldPath;
86
73
  readonly gates?: LogicalDefinition;
87
74
  }
88
75
 
89
- /** One subject's private aggregate working projection. */
76
+ /** Describes one subject's private aggregate working projection. */
90
77
  export declare interface AggregateProjection {
91
78
  readonly count: number;
92
79
  readonly sums: Readonly<Record<string, number>>;
93
80
  readonly group?: AggregateGroup;
94
81
  }
95
82
 
96
- /** A batch program outcome across every subject. */
83
+ /** Describes a batch program outcome across every subject. */
97
84
  export declare interface AggregateResult {
98
85
  readonly id: string;
99
86
  readonly name: string;
@@ -109,7 +96,7 @@ export declare interface AggregateResult {
109
96
  }
110
97
 
111
98
  /**
112
- * Sum aggregate fields across a batch of subjects.
99
+ * Sums aggregate fields across a batch of subjects.
113
100
  *
114
101
  * @remarks
115
102
  * A {@link FieldPath} may be nested — a nested path sums a nested subject field
@@ -131,7 +118,7 @@ export declare interface AggregateResult {
131
118
  export declare function aggregateSums(subjects: readonly Subject[], fields: readonly FieldPath[]): Readonly<Record<string, number>>;
132
119
 
133
120
  /**
134
- * Assert a program definition's always-on construction invariants — missing
121
+ * Asserts a program definition's always-on construction invariants — missing
135
122
  * scope references and duplicate rating-line or notice ids.
136
123
  *
137
124
  * @remarks
@@ -140,10 +127,10 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
140
127
  * an authoring mistake this severe cannot silently compile.
141
128
  *
142
129
  * @param definition - The program definition to assert
143
- * @throws {@link ProgramError} `'MISSING'` when a ruling or notice scope names
144
- * no rating line
145
- * @throws {@link ProgramError} `'DUPLICATE'` when two rating lines or two
146
- * notices share an id
130
+ * @throws {@link ProgramError} Thrown when a ruling or notice scope names no
131
+ * rating line (`'MISSING'`).
132
+ * @throws {@link ProgramError} Thrown when two rating lines or two notices share
133
+ * an id (`'DUPLICATE'`).
147
134
  *
148
135
  * @example
149
136
  * ```ts
@@ -155,1152 +142,1810 @@ export declare function aggregateSums(subjects: readonly Subject[], fields: read
155
142
  export declare function assertProgramDefinition(definition: ProgramDefinition): void;
156
143
 
157
144
  /**
158
- * Assert a value is a valid program {@link Subject}, narrowing it in place.
145
+ * Asserts a value is a valid program {@link Subject}, narrowing it in place.
159
146
  *
160
147
  * @param subject - The candidate subject to validate
161
- * @throws {@link ProgramError} `'MISMATCH'` when the value is not a record, or
162
- * `'RESERVED'` when it already carries the `aggregate` or `outcome` key
163
- *
164
- * @example
165
- * ```ts
166
- * import { assertProgramSubject } from '@orkestrel/program'
167
- *
168
- * assertProgramSubject({ id: 'r1' }) // does not throw
169
- * ```
170
- */
171
- export declare function assertProgramSubject(subject: unknown): asserts subject is Subject;
172
-
173
- /**
174
- * Build one subject's overall and optional group aggregate projection.
175
- *
176
- * @remarks
177
- * The projection carries the whole-batch `count` and `sums` plus the subject's
178
- * OWN partition, located by the same {@link formatGroupKey} key
179
- * {@link aggregateGroups} partitions under.
180
- *
181
- * @param subject - The subject to project for
182
- * @param count - The whole-batch subject count
183
- * @param sums - The whole-batch summed aggregate fields
184
- * @param groups - The batch partitions
185
- * @param by - The partition key field; no group is attached when absent
186
- * @returns A fresh aggregate projection
187
- *
188
- * @example
189
- * ```ts
190
- * import { buildAggregateProjection } from '@orkestrel/program'
191
- *
192
- * buildAggregateProjection(subject, 2, { amount: 8 }, groups, 'location')
193
- * ```
194
- */
195
- export declare function buildAggregateProjection(subject: Subject, count: number, sums: Readonly<Record<string, number>>, groups: readonly AggregateGroup[], by?: FieldPath): AggregateProjection;
196
-
197
- /**
198
- * Build the reserved-key record a batch aggregate-gate definition runs against.
199
- *
200
- * @remarks
201
- * Unlike a per-subject {@link buildAggregateProjection}, the batch record carries
202
- * every `group` (a `groups` array) under {@link AGGREGATE_KEY} so a gate rule can
203
- * read `aggregate.sums.<field>` (overall) or a partition inside `aggregate.groups`.
204
- *
205
- * @param count - The whole-batch subject count
206
- * @param sums - The whole-batch summed aggregate fields
207
- * @param groups - The batch partitions
208
- * @returns A fresh record carrying the batch aggregate under {@link AGGREGATE_KEY}
209
- *
210
- * @example
211
- * ```ts
212
- * import { buildAggregateRecord } from '@orkestrel/program'
213
- *
214
- * buildAggregateRecord(2, { amount: 8 }, [])
215
- * ```
216
- */
217
- export declare function buildAggregateRecord(count: number, sums: Readonly<Record<string, number>>, groups: readonly AggregateGroup[]): Readonly<Record<string, unknown>>;
218
-
219
- /**
220
- * Assemble one batch {@link AggregateResult} from its per-subject and aggregate
221
- * parts.
222
- *
223
- * @remarks
224
- * `count` is the subject count, `trace` / `errors` accumulate every subject's
225
- * plus the batch aggregate-gate evaluation's (`options.gates`), and `success`
226
- * requires every subject execution to succeed AND the gate evaluation to have
227
- * produced no errors. A fired aggregate gate contributes a `limit`
228
- * determination, never a technical failure (a non-logical gate result is a
229
- * caller-facing `MISMATCH` thrown by `Program` before this assembles).
230
- *
231
- * @param definition - The authored program definition
232
- * @param subjects - The per-subject program results, in input order
233
- * @param determinations - The batch aggregate-gate `limit` determinations
234
- * @param groups - The batch partitions
235
- * @param tallies - The completed status tallies
236
- * @param sums - The whole-batch summed aggregate fields
237
- * @param options - Optional resolved aggregate-gate result
238
- * @returns A fresh aggregate result
239
- *
240
- * @example
241
- * ```ts
242
- * import { buildAggregateResult } from '@orkestrel/program'
243
- *
244
- * buildAggregateResult(definition, subjects, [], [], tallies, { amount: 8 })
245
- * ```
246
- */
247
- export declare function buildAggregateResult(definition: ProgramDefinition, subjects: readonly ProgramResult[], determinations: readonly Determination[], groups: readonly AggregateGroup[], tallies: Readonly<Record<Status, Tally>>, sums: Readonly<Record<string, number>>, options?: {
248
- readonly gates?: LogicalResult;
249
- }): AggregateResult;
250
-
251
- /**
252
- * Convert a logical result's applied rules into `limit` {@link Determination}s.
253
- *
254
- * @remarks
255
- * Fires for both the per-subject authority and the batch aggregate gates — both
256
- * are plain {@link LogicalDefinition}s with no program-authored ruling map, so a
257
- * fired rule's own `description` (from `@orkestrel/reason`) is the message
258
- * template, interpolated against the working record the definition ran against.
259
- * Rich premises reuse the qualifier's {@link logicalPremises}. A rule that never
260
- * fires produces no determination — program has no authored ruling map to keep
261
- * evidence for.
262
- *
263
- * @param definition - The authority or aggregate-gate logical definition
264
- * @param result - The evaluated logical result
265
- * @param working - The working record the definition ran against
266
- * @param evaluator - The shared reason check evaluator
267
- * @param labels - Optional field-to-label overrides, keyed by dot-joined field
268
- * @returns A fresh list of `limit` determinations
269
- *
270
- * @example
271
- * ```ts
272
- * import { buildLimits } from '@orkestrel/program'
273
- *
274
- * buildLimits(authority, resolved, outcome, evaluator)
275
- * ```
276
- */
277
- export declare function buildLimits(definition: LogicalDefinition, result: LogicalResult, working: Readonly<Record<string, unknown>>, evaluator: EvaluatorInterface, labels?: Readonly<Record<string, string>>): readonly Determination[];
278
-
279
- /**
280
- * Resolve authored {@link Notice}s into unconditionally-applied `notice`
281
- * {@link Determination}s.
282
- *
283
- * @remarks
284
- * Notices are program output only — they never affect eligibility, status, line
285
- * selection, or the decision. Each message interpolates against the original
286
- * subject.
287
- *
288
- * @param notices - The authored notices
289
- * @param subject - The original subject notices interpolate against
290
- * @returns A fresh list of notice determinations
291
- *
292
- * @example
293
- * ```ts
294
- * import { buildNotices } from '@orkestrel/program'
295
- *
296
- * buildNotices([{ id: 'min', message: 'Minimum applies' }], { id: 'r1' })
297
- * ```
298
- */
299
- export declare function buildNotices(notices: readonly Notice[], subject: Readonly<Record<string, unknown>>): readonly Determination[];
300
-
301
- /**
302
- * Build the private authority outcome projection from an assembled program result.
303
- *
304
- * @remarks
305
- * The authority reads this record under {@link OUTCOME_KEY}; it never receives
306
- * the mutable internal state of either sibling engine. `total` is carried from
307
- * the nested rating result when rating occurred.
308
- *
309
- * @param result - The preliminary program result computed before authority runs
310
- * @returns A record shaped for the authority's `outcome` projection
311
- *
312
- * @example
313
- * ```ts
314
- * import { buildOutcomeProjection } from '@orkestrel/program'
315
- *
316
- * buildOutcomeProjection(result) // { id, eligibility, status, rated, scopes }
317
- * ```
318
- */
319
- export declare function buildOutcomeProjection(result: ProgramResult): Readonly<Record<string, unknown>>;
320
-
321
- /**
322
- * Assemble a {@link ProgramResult} from its qualification, rating, and
323
- * determination parts — before or after authority.
324
- *
325
- * @remarks
326
- * `eligibility` mirrors the qualification. `success` is execution integrity: the
327
- * qualification succeeded, rating (when it ran) succeeded, and authority (when it
328
- * ran) produced no errors — a valid ineligible or referral outcome still
329
- * succeeds. `trace` and `errors` accumulate the qualification's, every rated
330
- * line's worksheet trail, and the authority's. A `decision` is present ONLY when
331
- * an authority ran (`options.authority`), the execution SUCCEEDED (`success`),
332
- * no `limit` determination applied, and status is not `unrated`.
333
- *
334
- * @param definition - The authored program definition
335
- * @param qualification - The subject's qualification result
336
- * @param rating - The subject's rating result, when rating occurred
337
- * @param determinations - The program-scoped determinations (notices, then limits)
338
- * @param status - The already-derived status
339
- * @param options - Optional authority result driving the decision projection
340
- * @returns A fresh program result
341
- *
342
- * @example
343
- * ```ts
344
- * import { buildProgramResult } from '@orkestrel/program'
345
- *
346
- * buildProgramResult(definition, qualification, rating, [], 'eligible')
347
- * ```
348
- */
349
- export declare function buildProgramResult(definition: ProgramDefinition, qualification: QualificationResult, rating: RatingResult | undefined, determinations: readonly Determination[], status: Status, options?: {
350
- readonly authority?: LogicalResult;
351
- }): ProgramResult;
352
-
353
- /**
354
- * Add optional aggregate context to a private subject copy for qualification.
355
- *
356
- * @remarks
357
- * The original subject is returned unchanged when no aggregate context exists.
358
- * When context exists the helper creates a private copy under {@link AGGREGATE_KEY}
359
- * and defensively copies every nested record — the rater still receives the
360
- * original subject, never this copy.
361
- *
362
- * @param subject - The original caller subject
363
- * @param aggregate - The subject's aggregate projection, when a batch supplies one
364
- * @returns The subject, or a private copy carrying the aggregate projection
365
- *
366
- * @example
367
- * ```ts
368
- * import { buildQualificationSubject } from '@orkestrel/program'
369
- *
370
- * buildQualificationSubject({ id: 'r1' }) // { id: 'r1' }
371
- * ```
372
- */
373
- export declare function buildQualificationSubject(subject: Subject, aggregate?: AggregateProjection): Subject;
374
-
375
- /**
376
- * Complete a partial status tally record with zero entries for every missing
377
- * {@link Status}.
378
- *
379
- * @param entries - The partial tally entries to complete
380
- * @returns A record with all five statuses present
381
- *
382
- * @example
383
- * ```ts
384
- * import { completeTallies } from '@orkestrel/program'
385
- *
386
- * completeTallies({ eligible: { count: 1, sums: {} } })
387
- * ```
388
- */
389
- export declare function completeTallies(entries: Partial<Record<Status, Tally>>): Readonly<Record<Status, Tally>>;
390
-
391
- /**
392
- * Return a fresh JSON value tree that does not alias the input.
393
- *
394
- * @remarks
395
- * The input must be an acyclic JSON tree of bounded depth — a pathologically
396
- * deep tree throws the engine's `RangeError` (stack exhaustion) rather than
397
- * hanging. Each copied record uses `Object.defineProperty` for own-property
398
- * definition, which defends against prototype-pollution keys (`__proto__`).
399
- *
400
- * @param value - The JSON value to copy
401
- * @returns A fresh JSON value
402
- *
403
- * @example
404
- * ```ts
405
- * import { copyJSONValue } from '@orkestrel/program'
406
- *
407
- * copyJSONValue({ a: [1, 2] }) // { a: [1, 2] }, a fresh copy
408
- * ```
409
- */
410
- export declare function copyJSONValue(value: JSONValue): JSONValue;
411
-
412
- /**
413
- * Create one compiled program over a qualifier and rater.
414
- *
415
- * @remarks
416
- * Validates the definition at construction when `options.validate` is left at
417
- * its {@link DEFAULT_PROGRAM_VALIDATE} default. A standalone program creates and
418
- * OWNS one shared quantitative-plus-logical reason engine and injects it into the
419
- * qualifier and rater it creates; injected dependencies remain caller-owned.
420
- *
421
- * @param definition - The authored program definition
422
- * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks
423
- * @returns A {@link ProgramInterface}
424
- *
425
- * @example
426
- * ```ts
427
- * import { createProgram, programDefinition } from '@orkestrel/program'
428
- *
429
- * const program = createProgram(programDefinition('standard', 'Standard', qualification, rating))
430
- * program.execute({ id: 'risk-1' })
431
- * program.destroy()
432
- * ```
433
- */
434
- export declare function createProgram(definition: ProgramDefinition, options?: ProgramOptions): ProgramInterface;
435
-
436
- /**
437
- * Create one ordered manager over compiled programs.
438
- *
439
- * @remarks
440
- * Creates or borrows one shared reason engine, qualifier, and rater and injects
441
- * them into every compiled program, so a batch of definitions shares one engine.
442
- * Seed definitions are compiled in order.
443
- *
444
- * @param options - Optional injected qualifier, rater, engine, seed programs, validation, labels, and emitter hooks
445
- * @returns A {@link ProgramManagerInterface}
446
- *
447
- * @example
448
- * ```ts
449
- * import { createProgramManager } from '@orkestrel/program'
450
- *
451
- * const manager = createProgramManager({ programs: [definition] })
452
- * manager.program('standard')?.execute(subject)
453
- * manager.destroy()
454
- * ```
455
- */
456
- export declare function createProgramManager(options?: ProgramManagerOptions): ProgramManagerInterface;
457
-
458
- /**
459
- * Map a global {@link Eligibility} to its deterministic authority {@link Decision}.
460
- *
461
- * @param eligibility - The global eligibility
462
- * @returns The matching decision
463
- *
464
- * @example
465
- * ```ts
466
- * import { decideEligibility } from '@orkestrel/program'
467
- *
468
- * decideEligibility('eligible') // 'approved'
469
- * decideEligibility('referral') // 'submitted'
470
- * ```
471
- */
472
- export declare function decideEligibility(eligibility: Eligibility): Decision;
473
-
474
- /** A final authority outcome, derived from global eligibility. */
475
- export declare type Decision = 'approved' | 'denied' | 'submitted';
476
-
477
- /** Default definition validation policy for `createProgram` / `ProgramManager.add`. */
478
- export declare const DEFAULT_PROGRAM_VALIDATE = true;
479
-
480
- /**
481
- * Derive the final program {@link Status} from a definition's rating policy and
482
- * qualification/rating evidence.
483
- *
484
- * @remarks
485
- * Explicit policy, not an opaque precedence reduce (AGENTS §10): global
486
- * ineligibility or referral is terminal; a scoped referral yields `referral`;
487
- * an applied `condition` or an applied scoped `restriction` (a line was
488
- * removed but others rated) is `conditional`. When the definition OMITS
489
- * `rating` the program is eligibility-only — status resolves to `conditional`
490
- * or `eligible` and is NEVER `unrated`. Otherwise a subject with no successful
491
- * rating is `unrated`.
492
- *
493
- * @param definition - The authored program definition
494
- * @param qualification - The subject's qualification result
495
- * @param rating - The subject's rating result, when rating occurred
496
- * @returns The derived status
497
- *
498
- * @example
499
- * ```ts
500
- * import { deriveStatus } from '@orkestrel/program'
501
- *
502
- * deriveStatus(definition, qualification, rating) // 'eligible'
503
- * ```
504
- */
505
- export declare function deriveStatus(definition: ProgramDefinition, qualification: QualificationResult, rating?: RatingResult): Status;
506
-
507
- /** One resolved notice or authority-limit outcome. */
508
- export declare interface Determination {
509
- readonly id: string;
510
- readonly effect: ProgramEffect;
511
- readonly applied: boolean;
512
- readonly scope?: string;
513
- readonly message?: string;
514
- readonly premises: readonly Premise[];
515
- }
516
-
517
- /** The deterministic authority decision for each global eligibility. */
518
- export declare const ELIGIBILITY_DECISIONS: Readonly<Record<Eligibility, Decision>>;
519
-
520
- /**
521
- * Build a zero-sum record for a set of aggregate fields.
522
- *
523
- * @param fields - The fields to zero
524
- * @returns A fresh record of dot-joined field to `0`
525
- *
526
- * @example
527
- * ```ts
528
- * import { emptySums } from '@orkestrel/program'
529
- *
530
- * emptySums(['amount']) // { amount: 0 }
531
- * ```
532
- */
533
- export declare function emptySums(fields: readonly FieldPath[]): Readonly<Record<string, number>>;
534
-
535
- /**
536
- * Build complete zero status tallies in {@link STATUS_PRECEDENCE} order.
537
- *
538
- * @param fields - The fields each tally's sums are zeroed for
539
- * @returns A fresh, complete tally record
540
- *
541
- * @example
542
- * ```ts
543
- * import { emptyTallies } from '@orkestrel/program'
544
- *
545
- * emptyTallies(['amount'])
546
- * ```
547
- */
548
- export declare function emptyTallies(fields: readonly FieldPath[]): Readonly<Record<Status, Tally>>;
549
-
550
- /**
551
- * Return authored scopes (qualification ruling scopes or notice scopes) that
552
- * name no rating line on the program.
553
- *
554
- * @remarks
555
- * A scope is an opaque string to the qualifier — program alone matches it to a
556
- * rating-line id. A scope naming no line is a hard authoring error surfaced as
557
- * {@link ProgramError} `'MISSING'` at construction, regardless of the validate
558
- * option.
559
- *
560
- * @param definition - The program definition to check
561
- * @returns A fresh, deduped list of missing scope references
562
- *
563
- * @example
564
- * ```ts
565
- * import { findMissingScopes } from '@orkestrel/program'
566
- *
567
- * findMissingScopes(definition) // []
568
- * ```
569
- */
570
- export declare function findMissingScopes(definition: ProgramDefinition): readonly string[];
571
-
572
- /**
573
- * Coerce a subject's partition-key field to its group-key string.
574
- *
575
- * @remarks
576
- * The key is the resolved field coerced with `String` — `undefined` collapses
577
- * to the empty string, so a subject missing the field and a subject whose
578
- * field is literally `''` land in the SAME partition, and a numeric `1`
579
- * collides with the string `'1'`.
580
- *
581
- * @param subject - The subject to key
582
- * @param by - The partition key field
583
- * @returns The subject's group key
584
- *
585
- * @example
586
- * ```ts
587
- * import { formatGroupKey } from '@orkestrel/program'
588
- *
589
- * formatGroupKey({ location: 'east' }, 'location') // 'east'
590
- * ```
591
- */
592
- export declare function formatGroupKey(subject: Subject, by: FieldPath): string;
593
-
594
- /**
595
- * Determine whether a caller subject already carries a reserved program key.
596
- *
597
- * @remarks
598
- * `aggregate` and `outcome` are program-private working-subject namespaces — the
599
- * batch aggregate projection and the authority outcome projection are written
600
- * under them. A caller subject that already owns either key would silently
601
- * collide with a projection, so it is rejected before qualification.
602
- *
603
- * @param subject - The caller subject to check
604
- * @returns `true` when the subject owns `aggregate` or `outcome`
605
- *
606
- * @example
607
- * ```ts
608
- * import { hasReservedKey } from '@orkestrel/program'
609
- *
610
- * hasReservedKey({ id: 'r1' }) // false
611
- * hasReservedKey({ id: 'r1', aggregate: {} }) // true
612
- * ```
613
- */
614
- export declare function hasReservedKey(subject: Readonly<Record<string, unknown>>): boolean;
615
-
616
- /**
617
- * Determine whether a value is an exact {@link AggregateDefinition} record.
618
- *
619
- * @param value - The candidate value
620
- * @returns `true` when `value` is an {@link AggregateDefinition}
621
- *
622
- * @example
623
- * ```ts
624
- * import { isAggregateDefinition } from '@orkestrel/program'
625
- *
626
- * isAggregateDefinition({ fields: ['amount'] }) // true
627
- * ```
628
- */
629
- export declare function isAggregateDefinition(value: unknown): value is AggregateDefinition;
630
-
631
- /**
632
- * Determine whether a value is an open result-side {@link AggregateGroup}.
633
- *
634
- * @remarks
635
- * Unknown members and class instances are admitted. Arrays are refused.
636
- *
637
- * @param value - The candidate value
638
- * @returns `true` when every published aggregate-group member conforms
639
- *
640
- * @example
641
- * ```ts
642
- * import { isAggregateGroup } from '@orkestrel/program'
643
- *
644
- * isAggregateGroup({ key: 'east', count: 1, sums: { premium: 100 } }) // true
645
- * ```
646
- */
647
- export declare const isAggregateGroup: Guard<AggregateGroup>;
648
-
649
- /**
650
- * Determine whether a value is an open {@link AggregateResult}.
651
- *
652
- * @remarks
653
- * This guard is result-postured for values returned through a borrowed
654
- * {@link ProgramInterface}. It admits unknown members and class instances while
655
- * checking every nested program result, determination, group, total tally
656
- * record, and sums record. Arrays are refused.
657
- *
658
- * @param value - The candidate value
659
- * @returns `true` when every published aggregate-result member conforms
660
- *
661
- * @example
662
- * ```ts
663
- * import { isAggregateResult } from '@orkestrel/program'
664
- *
665
- * isAggregateResult(program.execute(subjects)) // true
666
- * ```
667
- */
668
- export declare const isAggregateResult: Guard<AggregateResult>;
669
-
670
- /**
671
- * Determine whether a value is a {@link Decision} literal.
672
- *
673
- * @param value - The candidate value
674
- * @returns `true` when `value` is a {@link Decision}
675
- *
676
- * @example
677
- * ```ts
678
- * import { isDecision } from '@orkestrel/program'
679
- *
680
- * isDecision('approved') // true
681
- * ```
682
- */
683
- export declare const isDecision: Guard<Decision>;
684
-
685
- /**
686
- * Determine whether a value is an open result-side {@link Determination}.
687
- *
688
- * @remarks
689
- * Unknown members and class instances are admitted. Arrays are refused.
690
- * Optional `scope` and `message` members may be absent or `undefined`.
691
- *
692
- * @param value - The candidate value
693
- * @returns `true` when every published determination member conforms
694
- *
695
- * @example
696
- * ```ts
697
- * import { isDetermination } from '@orkestrel/program'
698
- *
699
- * isDetermination({ id: 'audit', effect: 'notice', applied: true, premises: [] }) // true
700
- * ```
701
- */
702
- export declare const isDetermination: Guard<Determination>;
703
-
704
- /**
705
- * Determine whether a value is an exact {@link Notice} record.
706
- *
707
- * @param value - The candidate value
708
- * @returns `true` when `value` is a {@link Notice}
709
- *
710
- * @example
711
- * ```ts
712
- * import { isNotice } from '@orkestrel/program'
713
- *
714
- * isNotice({ id: 'minimum', message: 'Minimum applies' }) // true
715
- * ```
716
- */
717
- export declare function isNotice(value: unknown): value is Notice;
718
-
719
- /**
720
- * Determine whether a value is an exact {@link ProgramDefinition} record.
721
- *
722
- * @remarks
723
- * `rating` is optional — an omitted `rating` authors an eligibility-only
724
- * program (see {@link ProgramDefinition}).
725
- *
726
- * @param value - The candidate value
727
- * @returns `true` when `value` is a {@link ProgramDefinition}
728
- *
729
- * @example
730
- * ```ts
731
- * import { isProgramDefinition } from '@orkestrel/program'
732
- *
733
- * isProgramDefinition({ id: 'p', name: 'P', qualification }) // true
734
- * ```
735
- */
736
- export declare function isProgramDefinition(value: unknown): value is ProgramDefinition;
737
-
738
- /**
739
- * Determine whether a value is a {@link ProgramEffect} literal.
740
- *
741
- * @param value - The candidate value
742
- * @returns `true` when `value` is a {@link ProgramEffect}
743
- *
744
- * @example
745
- * ```ts
746
- * import { isProgramEffect } from '@orkestrel/program'
747
- *
748
- * isProgramEffect('notice') // true
749
- * ```
750
- */
751
- export declare const isProgramEffect: Guard<ProgramEffect>;
752
-
753
- /** Narrow a caught value to a {@link ProgramError}. */
754
- export declare function isProgramError(value: unknown): value is ProgramError;
755
-
756
- /**
757
- * Determine whether a value is an open {@link ProgramResult}.
758
- *
759
- * @remarks
760
- * This guard is result-postured for values returned through a borrowed
761
- * {@link ProgramInterface}. It admits unknown members and class instances while
762
- * composing qualifier's `isQualificationResult` and rater's `isRatingResult`
763
- * over their complete nested result closures. Arrays are refused.
764
- *
765
- * @param value - The candidate value
766
- * @returns `true` when every published program-result member conforms
767
- *
768
- * @example
769
- * ```ts
770
- * import { isProgramResult } from '@orkestrel/program'
771
- *
772
- * isProgramResult(program.execute(subject)) // true
773
- * ```
774
- */
775
- export declare const isProgramResult: Guard<ProgramResult>;
776
-
777
- /**
778
- * Determine whether a value is an open program sums record.
779
- *
780
- * @remarks
781
- * Every own string-named property is checked, including non-enumerable
782
- * properties. Inherited and symbol-named members are outside the record this
783
- * guard certifies. Values remain plain JavaScript numbers, including `NaN` and
784
- * infinities, because the published contract does not refine them.
785
- *
786
- * @param value - The candidate value
787
- * @returns `true` when every own string-named value is a number
788
- *
789
- * @example
790
- * ```ts
791
- * import { isProgramSums } from '@orkestrel/program'
792
- *
793
- * isProgramSums({ premium: 100 }) // true
794
- * ```
795
- */
796
- export declare function isProgramSums(value: unknown): value is Readonly<Record<string, number>>;
797
-
798
- /**
799
- * Determine whether a value is an open {@link ProgramValidationResult}.
800
- *
801
- * @remarks
802
- * `ProgramValidationResult` is this package's own declared interface, not an
803
- * alias of reason's validation result. This guard therefore checks the three
804
- * program-owned members directly so the contracts may evolve independently.
805
- * Unknown members and class instances are admitted. Arrays are refused.
806
- *
807
- * @param value - The candidate value
808
- * @returns `true` when every published program-validation member conforms
809
- *
810
- * @example
811
- * ```ts
812
- * import { isProgramValidationResult } from '@orkestrel/program'
813
- *
814
- * isProgramValidationResult({ valid: true, errors: [], warnings: [] }) // true
815
- * ```
816
- */
817
- export declare const isProgramValidationResult: Guard<ProgramValidationResult>;
818
-
819
- /**
820
- * Determine whether a value is a {@link Status} literal.
821
- *
822
- * @param value - The candidate value
823
- * @returns `true` when `value` is a {@link Status}
824
- *
825
- * @example
826
- * ```ts
827
- * import { isStatus } from '@orkestrel/program'
828
- *
829
- * isStatus('eligible') // true
830
- * ```
831
- */
832
- export declare const isStatus: Guard<Status>;
833
-
834
- /**
835
- * Determine whether a value is a total open status-tally record.
836
- *
837
- * @remarks
838
- * Every {@link Status} in {@link STATUS_PRECEDENCE} is required and checked.
839
- * Unknown members and class instances are admitted. Arrays are refused.
840
- *
841
- * @param value - The candidate value
842
- * @returns `true` when every required status member is a {@link Tally}
843
- *
844
- * @example
845
- * ```ts
846
- * import { emptyTallies, isTallies } from '@orkestrel/program'
847
- *
848
- * isTallies(emptyTallies([])) // true
849
- * ```
850
- */
851
- export declare function isTallies(value: unknown): value is Readonly<Record<Status, Tally>>;
852
-
853
- /**
854
- * Determine whether a value is an open result-side {@link Tally}.
855
- *
856
- * @remarks
857
- * Unknown members and class instances are admitted. Arrays are refused.
858
- *
859
- * @param value - The candidate value
860
- * @returns `true` when every published tally member conforms
861
- *
862
- * @example
863
- * ```ts
864
- * import { isTally } from '@orkestrel/program'
865
- *
866
- * isTally({ count: 1, sums: { premium: 100 } }) // true
867
- * ```
868
- */
869
- export declare const isTally: Guard<Tally>;
870
-
871
- /** An authored, unconditional program notice. */
872
- export declare interface Notice {
873
- readonly id: string;
874
- readonly message: string;
875
- readonly scope?: string;
876
- }
877
-
878
- /**
879
- * Build a {@link Notice}.
880
- *
881
- * @param id - The notice id
882
- * @param message - The message template, carrying optional `{{token}}`s
883
- * @param input - Optional presentation scope
884
- * @returns A fresh notice
885
- *
886
- * @example
887
- * ```ts
888
- * import { noticeDefinition } from '@orkestrel/program'
889
- *
890
- * noticeDefinition('minimum', 'Minimum earned premium applies')
891
- * ```
892
- */
893
- export declare function noticeDefinition(id: string, message: string, input?: NoticeInput): Notice;
894
-
895
- /**
896
- * Optional fields accepted by `noticeDefinition`.
897
- *
898
- * @remarks
899
- * `scope` — the rating-line id the notice presents against; omitted for an
900
- * unscoped, program-wide notice.
901
- */
902
- export declare interface NoticeInput {
903
- readonly scope?: string;
904
- }
905
-
906
- /** The reserved working-subject key the authority's outcome projection is written under. */
907
- export declare const OUTCOME_KEY = "outcome";
908
-
909
- /**
910
- * One compiled program — composes one qualifier and one rater over a shared
911
- * reason engine and executes single subjects or aggregate-aware batches.
912
- *
913
- * @remarks
914
- * Qualification decides whether rating happens: a globally ineligible, referred,
915
- * or failed subject never reaches the rater, and a scoped ineligibility removes
916
- * only its line before the first rating call. The rater always receives the
917
- * ORIGINAL subject; the qualifier's aggregate projection stays private. When no
918
- * qualifier, rater, or engine is injected the program creates ONE shared
919
- * quantitative-plus-logical engine, injects it into the qualifier and rater it
920
- * creates, and destroys only what it owns. A definition failure during
921
- * construction (an invalid definition under `options.validate`) tears down
922
- * whatever the constructor had already allocated before throwing. Construction
923
- * snapshots the caller's definition once, runs the always-on assertions against
924
- * that snapshot, and seals its plain-object graph before exposure. A `Map`, `Set`,
925
- * or `Date` reached through a reason `Check.value` is cloned but remains mutable
926
- * because its contents live in internal slots. Uncloneable values and non-empty
927
- * typed arrays are refused with `ProgramError('DEFINITION')` and the host error
928
- * as its cause. `destroy()` is idempotent and REENTRANCY-SAFE — the destroyed
929
- * flag is set BEFORE any teardown or the `destroy` event fires, so a listener
930
- * that re-enters `destroy()` is a no-op — and tears the emitter down last.
931
- */
932
- export declare class Program implements ProgramInterface {
933
- #private;
934
- readonly id: string;
935
- readonly name: string;
936
- readonly definition: ProgramDefinition;
937
- constructor(definition: ProgramDefinition, options?: ProgramOptions);
938
- get emitter(): EmitterInterface<ProgramEventMap>;
939
- execute(subjects: readonly Subject[]): AggregateResult;
940
- execute(subject: Subject): ProgramResult;
941
- validate(): ProgramValidationResult;
942
- destroy(): void;
943
- }
944
-
945
- /**
946
- * A pure authored program definition.
947
- *
948
- * @remarks
949
- * `qualification` runs first through `@orkestrel/qualifier`; `rating` runs only
950
- * over the lines scoped eligibility left standing, through `@orkestrel/rater`.
951
- * `authority` (a logical definition) runs last, over the assembled result
952
- * extended with an outcome projection, to derive limit determinations and the
953
- * final decision. An omitted `rating` authors an ELIGIBILITY-ONLY program — the
954
- * rater is never invoked, an eligible subject resolves to `'eligible'` (or
955
- * `'conditional'` under an applied condition or scoped restriction), status is
956
- * never `'unrated'`, and decisions remain reachable through `authority`. Program
957
- * construction clones the definition and seals its plain-object graph. A `Map`,
958
- * `Set`, or `Date` reached through a reason `Check.value` is cloned, but its
959
- * contents remain mutable because the seal cannot reach its internal slots. A
960
- * value that structured cloning cannot copy, or a non-empty typed array that
961
- * cannot be frozen, is refused with `ProgramError('DEFINITION')` and the host
962
- * error attached as its cause.
963
- */
964
- export declare interface ProgramDefinition {
965
- readonly id: string;
966
- readonly name: string;
967
- readonly description?: string;
968
- readonly qualification: QualificationDefinition;
969
- readonly rating?: RatingDefinition;
970
- readonly notices?: readonly Notice[];
971
- readonly authority?: LogicalDefinition;
972
- readonly aggregate?: AggregateDefinition;
973
- readonly metadata?: JSONValue;
974
- }
975
-
976
- /**
977
- * Build a {@link ProgramDefinition}.
978
- *
979
- * @remarks
980
- * Copies every collection and omits absent optional keys, so the returned
981
- * definition is a fresh, JSON-serializable value that never aliases its inputs.
982
- *
983
- * @param id - The program id
984
- * @param name - The display name
985
- * @param qualification - The nested qualification definition
986
- * @param rating - The nested rating definition; omit for an eligibility-only program
987
- * @param input - Optional description, notices, authority, aggregate, and metadata
988
- * @returns A fresh program definition
989
- *
990
- * @example
991
- * ```ts
992
- * import { programDefinition } from '@orkestrel/program'
993
- *
994
- * programDefinition('standard', 'Standard', qualification, rating, { notices: [notice] })
995
- * ```
996
- */
997
- export declare function programDefinition(id: string, name: string, qualification: QualificationDefinition, rating?: RatingDefinition, input?: ProgramInput): ProgramDefinition;
998
-
999
- /** A post-qualification program determination effect. */
1000
- export declare type ProgramEffect = 'notice' | 'limit';
1001
-
1002
- /**
1003
- * A coded programmer error thrown by the program layer.
1004
- *
1005
- * @remarks
1006
- * `DUPLICATE` — a program id collision on `ProgramManager.add`, or a duplicate
1007
- * authored rating-line or notice id. `MISSING` — an
1008
- * authored notice or qualification ruling scope names no rating line.
1009
- * `DEFINITION` — a program, qualification, rating, authority, or aggregate
1010
- * policy failed validation. `MISMATCH` — an injected entity or a returned
1011
- * reason result has the wrong contract. `RESERVED` — a subject already
1012
- * carries `aggregate` or `outcome`. `DESTROYED` — use of a destroyed entity.
1013
- */
1014
- export declare class ProgramError extends Error {
1015
- readonly code: ProgramErrorCode;
1016
- readonly context?: unknown;
1017
- constructor(code: ProgramErrorCode, message: string, context?: unknown);
1018
- }
1019
-
1020
- /** A coded {@link ProgramError} programmer-error code. */
1021
- export declare type ProgramErrorCode = 'DUPLICATE' | 'MISSING' | 'DEFINITION' | 'MISMATCH' | 'RESERVED' | 'DESTROYED';
1022
-
1023
- /**
1024
- * The push observation surface of a {@link ProgramInterface} (AGENTS §13).
1025
- *
1026
- * @remarks
1027
- * `rate` fires only when at least one line was selected. `determine` fires once
1028
- * per notice, then once per applied limit. `decide` fires only when a decision
1029
- * was reached.
1030
- */
1031
- export declare type ProgramEventMap = {
1032
- readonly qualify: readonly [result: QualificationResult];
1033
- readonly rate: readonly [result: RatingResult];
1034
- readonly determine: readonly [result: Determination];
1035
- readonly decide: readonly [decision: Decision, result: ProgramResult];
1036
- readonly execute: readonly [result: ProgramResult];
1037
- readonly aggregate: readonly [result: AggregateResult];
1038
- readonly destroy: readonly [];
1039
- };
1040
-
1041
- /**
1042
- * Optional fields accepted by `programDefinition`.
1043
- *
1044
- * @remarks
1045
- * `description` — a free-text summary. `notices` — authored unconditional
1046
- * notices. `authority` — a logical definition evaluated per subject to derive
1047
- * limit determinations and the decision. `aggregate` — batch aggregate fields,
1048
- * partition key, and gates. `metadata` — opaque caller data, copied fresh.
1049
- */
1050
- export declare interface ProgramInput {
1051
- readonly description?: string;
1052
- readonly notices?: readonly Notice[];
1053
- readonly authority?: LogicalDefinition;
1054
- readonly aggregate?: AggregateDefinition;
1055
- readonly metadata?: JSONValue;
1056
- }
1057
-
1058
- /**
1059
- * One compiled program — composes one qualifier and one rater over a shared
1060
- * reason engine.
1061
- *
1062
- * @remarks
1063
- * The array-of-subjects `execute` overload is declared FIRST (AGENTS §9.2) so a
1064
- * subject list resolves to one aggregate-aware batch execution.
1065
- */
1066
- export declare interface ProgramInterface {
1067
- readonly id: string;
1068
- readonly name: string;
1069
- readonly definition: ProgramDefinition;
1070
- readonly emitter: EmitterInterface<ProgramEventMap>;
1071
- execute(subjects: readonly Subject[]): AggregateResult;
1072
- execute(subject: Subject): ProgramResult;
1073
- validate(): ProgramValidationResult;
1074
- destroy(): void;
1075
- }
1076
-
1077
- /**
1078
- * An ordered manager over compiled {@link ProgramInterface}s (AGENTS §9), sharing
1079
- * one qualifier, rater, and reason engine across every program it compiles.
1080
- *
1081
- * @remarks
1082
- * OWNS its ordered `#programs` collection and its own {@link Emitter} over
1083
- * {@link ProgramManagerEventMap}. Creates or borrows one shared engine, qualifier,
1084
- * and rater and injects the same instances into every compiled program. `remove`
1085
- * destroys the programs it removes; `destroy()` removes all programs, then
1086
- * destroys only the owned shared dependencies, and tears the emitter down LAST.
1087
- * A seed-program failure during construction tears the manager down (destroying
1088
- * whatever had already been compiled) before rethrowing the original error.
1089
- * `destroy()` is REENTRANCY-SAFE — the destroyed flag is set BEFORE any teardown
1090
- * or the `remove` / `destroy` events fire, so a `remove` listener that re-enters
1091
- * `destroy()` is a no-op. Every call after `destroy()` throws {@link ProgramError}
1092
- * `'DESTROYED'`.
1093
- */
1094
- export declare class ProgramManager implements ProgramManagerInterface {
1095
- #private;
1096
- constructor(options?: ProgramManagerOptions);
1097
- get emitter(): EmitterInterface<ProgramManagerEventMap>;
1098
- get size(): number;
1099
- has(id: string): boolean;
1100
- program(id: string): ProgramInterface | undefined;
1101
- programs(): readonly ProgramInterface[];
1102
- add(definition: ProgramDefinition): ProgramInterface;
1103
- remove(ids: readonly string[]): boolean;
1104
- remove(id: string): boolean;
1105
- remove(): void;
1106
- destroy(): void;
1107
- }
1108
-
1109
- /** The push observation surface of a {@link ProgramManagerInterface} (AGENTS §13). */
1110
- export declare type ProgramManagerEventMap = {
1111
- readonly add: readonly [id: string];
1112
- readonly remove: readonly [id: string];
1113
- readonly destroy: readonly [];
1114
- };
1115
-
1116
- /** An ordered manager over compiled programs (AGENTS §9), sharing one qualifier and rater. */
1117
- export declare interface ProgramManagerInterface {
1118
- readonly emitter: EmitterInterface<ProgramManagerEventMap>;
1119
- readonly size: number;
1120
- has(id: string): boolean;
1121
- program(id: string): ProgramInterface | undefined;
1122
- programs(): readonly ProgramInterface[];
1123
- add(definition: ProgramDefinition): ProgramInterface;
1124
- remove(ids: readonly string[]): boolean;
1125
- remove(id: string): boolean;
1126
- remove(): void;
1127
- destroy(): void;
1128
- }
1129
-
1130
- /**
1131
- * Options for `createProgramManager` / the `ProgramManager` constructor.
1132
- *
1133
- * @remarks
1134
- * `qualifier` — an injected, caller-owned qualifier; created and owned when
1135
- * omitted. `rater` — an injected, caller-owned rater; created and owned when
1136
- * omitted. `engine` — an injected, caller-owned reason engine; created and
1137
- * owned when omitted. `programs` — seed definitions compiled in order.
1138
- * `validate` — validate each seeded/added definition at construction (default
1139
- * {@link DEFAULT_PROGRAM_VALIDATE}). `labels` — field-to-label overrides for
1140
- * determination premises, keyed by dot-joined field. `on` — initial emitter
1141
- * hooks. `error` — the emitter's listener-error handler.
1142
- */
1143
- export declare interface ProgramManagerOptions {
1144
- readonly qualifier?: QualifierInterface;
1145
- readonly rater?: RaterInterface;
1146
- readonly engine?: ReasonInterface;
1147
- readonly programs?: readonly ProgramDefinition[];
1148
- readonly validate?: boolean;
1149
- readonly labels?: Readonly<Record<string, string>>;
1150
- readonly on?: EmitterHooks<ProgramManagerEventMap>;
1151
- readonly error?: EmitterErrorHandler;
1152
- }
1153
-
1154
- /**
1155
- * Options for `createProgram` / the `Program` constructor.
1156
- *
1157
- * @remarks
1158
- * `qualifier` — an injected, caller-owned qualifier; created and owned by the
1159
- * program when omitted. `rater` — an injected, caller-owned rater; created and
1160
- * owned when omitted. `engine` — an injected, caller-owned reason engine;
1161
- * created and owned when omitted. `validate` — validate the definition at
1162
- * construction (default {@link DEFAULT_PROGRAM_VALIDATE}). `labels` —
1163
- * field-to-label overrides for determination premises, keyed by dot-joined
1164
- * field. `on` — initial emitter hooks. `error` — the emitter's listener-error
1165
- * handler.
1166
- */
1167
- export declare interface ProgramOptions {
1168
- readonly qualifier?: QualifierInterface;
1169
- readonly rater?: RaterInterface;
1170
- readonly engine?: ReasonInterface;
1171
- readonly validate?: boolean;
1172
- readonly labels?: Readonly<Record<string, string>>;
1173
- readonly on?: EmitterHooks<ProgramEventMap>;
1174
- readonly error?: EmitterErrorHandler;
1175
- }
1176
-
1177
- /** One subject's complete program outcome. */
1178
- export declare interface ProgramResult {
1179
- readonly id: string;
1180
- readonly name: string;
1181
- readonly eligibility: Eligibility;
1182
- readonly status: Status;
148
+ * @throws {@link ProgramError} Thrown when the value is not a record (`'MISMATCH'`).
149
+ * @throws {@link ProgramError} Thrown when the value already carries the `aggregate`
150
+ * or `outcome` key (`'RESERVED'`).
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * import { assertProgramSubject } from '@orkestrel/program'
155
+ *
156
+ * assertProgramSubject({ id: 'r1' }) // does not throw
157
+ * ```
158
+ */
159
+ export declare function assertProgramSubject(subject: unknown): asserts subject is Subject;
160
+
161
+ /**
162
+ * Builds a fresh {@link AggregateDefinition}.
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
+ *
168
+ * @param fields - The aggregate fields to sum across a batch
169
+ * @param input - Optional partition field and aggregate gates
170
+ * @returns A fresh aggregate definition
171
+ *
172
+ * @example
173
+ * ```ts
174
+ * import { buildAggregateDefinition } from '@orkestrel/program'
175
+ *
176
+ * buildAggregateDefinition(['amount'], { partition: 'location' })
177
+ * ```
178
+ */
179
+ export declare function buildAggregateDefinition(fields: readonly FieldPath[], input?: AggregateInput): AggregateDefinition;
180
+
181
+ /**
182
+ * Builds one subject's overall and optional group aggregate projection.
183
+ *
184
+ * @remarks
185
+ * The projection carries the whole-batch `count` and `sums` plus the subject's
186
+ * own partition, located by the same {@link formatGroupKey} key
187
+ * {@link aggregateGroups} partitions under.
188
+ *
189
+ * @param subject - The subject to project for
190
+ * @param count - The whole-batch subject count
191
+ * @param sums - The whole-batch summed aggregate fields
192
+ * @param groups - The batch partitions
193
+ * @param partition - The field the batch partitions on; no group is attached when absent
194
+ * @returns A fresh aggregate projection
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * import { buildAggregateProjection } from '@orkestrel/program'
199
+ *
200
+ * buildAggregateProjection(subject, 2, { amount: 8 }, groups, 'location')
201
+ * ```
202
+ */
203
+ export declare function buildAggregateProjection(subject: Subject, count: number, sums: Readonly<Record<string, number>>, groups: readonly AggregateGroup[], partition?: FieldPath): AggregateProjection;
204
+
1183
205
  /**
206
+ * Builds the reserved-key record a batch aggregate-gate definition runs against.
207
+ *
1184
208
  * @remarks
1185
- * Present ONLY when the program HAS an `authority`, the execution SUCCEEDED
1186
- * (qualification, rating when it ran, and authority all produced no errors),
209
+ * Unlike a per-subject {@link buildAggregateProjection}, the batch record carries
210
+ * every `group` (a `groups` array) under {@link AGGREGATE_KEY} so a gate rule can
211
+ * read `aggregate.sums.<field>` (overall) or a partition inside `aggregate.groups`.
212
+ *
213
+ * @param count - The whole-batch subject count
214
+ * @param sums - The whole-batch summed aggregate fields
215
+ * @param groups - The batch partitions
216
+ * @returns A fresh record carrying the batch aggregate under {@link AGGREGATE_KEY}
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * import { buildAggregateRecord } from '@orkestrel/program'
221
+ *
222
+ * buildAggregateRecord(2, { amount: 8 }, [])
223
+ * ```
224
+ */
225
+ export declare function buildAggregateRecord(count: number, sums: Readonly<Record<string, number>>, groups: readonly AggregateGroup[]): Readonly<Record<string, unknown>>;
226
+
227
+ /**
228
+ * Assembles one batch {@link AggregateResult} from its per-subject and aggregate
229
+ * parts.
230
+ *
231
+ * @remarks
232
+ * `count` is the subject count, `trace` / `errors` accumulate every subject's
233
+ * plus the batch aggregate-gate evaluation's (`options.gates`), and `success`
234
+ * requires every subject execution to succeed and the gate evaluation to have
235
+ * produced no errors. A fired aggregate gate contributes a `limit`
236
+ * determination, never a technical failure (a non-logical gate result is a
237
+ * caller-facing `MISMATCH` thrown by `Program` before this assembles).
238
+ *
239
+ * @param definition - The authored program definition
240
+ * @param subjects - The per-subject program results, in input order
241
+ * @param determinations - The batch aggregate-gate `limit` determinations
242
+ * @param groups - The batch partitions
243
+ * @param tallies - The completed status tallies
244
+ * @param sums - The whole-batch summed aggregate fields
245
+ * @param options - Optional resolved aggregate-gate result
246
+ * @returns A fresh aggregate result
247
+ *
248
+ * @example
249
+ * ```ts
250
+ * import { buildAggregateResult } from '@orkestrel/program'
251
+ *
252
+ * buildAggregateResult(definition, subjects, [], [], tallies, { amount: 8 })
253
+ * ```
254
+ */
255
+ export declare function buildAggregateResult(definition: ProgramDefinition, subjects: readonly ProgramResult[], determinations: readonly Determination[], groups: readonly AggregateGroup[], tallies: Readonly<Record<Status, Tally>>, sums: Readonly<Record<string, number>>, options?: {
256
+ readonly gates?: LogicalResult;
257
+ }): AggregateResult;
258
+
259
+ /**
260
+ * Builds a zero-sum record for a set of aggregate fields.
261
+ *
262
+ * @param fields - The fields to zero
263
+ * @returns A fresh record of dot-joined field to `0`
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * import { buildEmptySums } from '@orkestrel/program'
268
+ *
269
+ * buildEmptySums(['amount']) // { amount: 0 }
270
+ * ```
271
+ */
272
+ export declare function buildEmptySums(fields: readonly FieldPath[]): Readonly<Record<string, number>>;
273
+
274
+ /**
275
+ * Builds complete zero status tallies in {@link STATUSES} order.
276
+ *
277
+ * @param fields - The fields each tally's sums are zeroed for
278
+ * @returns A fresh, complete tally record
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * import { buildEmptyTallies } from '@orkestrel/program'
283
+ *
284
+ * buildEmptyTallies(['amount'])
285
+ * ```
286
+ */
287
+ export declare function buildEmptyTallies(fields: readonly FieldPath[]): Readonly<Record<Status, Tally>>;
288
+
289
+ /**
290
+ * Converts a logical result's applied rules into `limit` {@link Determination} values.
291
+ *
292
+ * @remarks
293
+ * Fires for both the per-subject authority and the batch aggregate gates — both
294
+ * are plain {@link LogicalDefinition} definitions with no program-authored ruling map, so a
295
+ * fired rule's own `description` (from `@orkestrel/reason`) is the message
296
+ * template, interpolated against the working record the definition ran against.
297
+ * Rich premises reuse the qualifier's {@link ruleToPremises}. A rule that never
298
+ * fires produces no determination — program has no authored ruling map to keep
299
+ * evidence for.
300
+ *
301
+ * @param definition - The authority or aggregate-gate logical definition
302
+ * @param result - The evaluated logical result
303
+ * @param working - The working record the definition ran against
304
+ * @param evaluator - The shared reason check evaluator
305
+ * @param labels - Optional field-to-label overrides, keyed by dot-joined field
306
+ * @returns A fresh list of `limit` determinations
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * import { buildLimitDeterminations } from '@orkestrel/program'
311
+ *
312
+ * buildLimitDeterminations(authority, resolved, outcome, evaluator)
313
+ * ```
314
+ */
315
+ export declare function buildLimitDeterminations(definition: LogicalDefinition, result: LogicalResult, working: Readonly<Record<string, unknown>>, evaluator: EvaluatorInterface, labels?: Readonly<Record<string, string>>): readonly Determination[];
316
+
317
+ /**
318
+ * Builds a fresh {@link Notice}.
319
+ *
320
+ * @remarks
321
+ * An absent `scope` is omitted entirely rather than stored as `undefined`.
322
+ *
323
+ * @param id - The notice id
324
+ * @param message - The message template, carrying optional `{{token}}` placeholders
325
+ * @param input - Optional presentation scope
326
+ * @returns A fresh notice
327
+ *
328
+ * @example
329
+ * ```ts
330
+ * import { buildNotice } from '@orkestrel/program'
331
+ *
332
+ * buildNotice('minimum', 'Minimum earned premium applies')
333
+ * ```
334
+ */
335
+ export declare function buildNotice(id: string, message: string, input?: NoticeInput): Notice;
336
+
337
+ /**
338
+ * Resolves authored {@link Notice} values into unconditionally-applied `notice`
339
+ * {@link Determination} values.
340
+ *
341
+ * @remarks
342
+ * Notices are program output only — they never affect eligibility, status, line
343
+ * selection, or the decision. Each message interpolates against the original
344
+ * subject.
345
+ *
346
+ * @param notices - The authored notices
347
+ * @param subject - The original subject notices interpolate against
348
+ * @returns A fresh list of notice determinations
349
+ *
350
+ * @example
351
+ * ```ts
352
+ * import { buildNoticeDeterminations } from '@orkestrel/program'
353
+ *
354
+ * buildNoticeDeterminations([{ id: 'min', message: 'Minimum applies' }], { id: 'r1' })
355
+ * ```
356
+ */
357
+ export declare function buildNoticeDeterminations(notices: readonly Notice[], subject: Readonly<Record<string, unknown>>): readonly Determination[];
358
+
359
+ /**
360
+ * Builds the private authority outcome projection from an assembled program result.
361
+ *
362
+ * @remarks
363
+ * The authority reads this record under {@link OUTCOME_KEY}; it never receives
364
+ * the mutable internal state of either sibling engine. `total` is carried from
365
+ * the nested rating result when rating occurred.
366
+ *
367
+ * @param result - The preliminary program result computed before authority runs
368
+ * @returns A record shaped for the authority's `outcome` projection
369
+ *
370
+ * @example
371
+ * ```ts
372
+ * import { buildOutcomeProjection } from '@orkestrel/program'
373
+ *
374
+ * buildOutcomeProjection(result) // { id, eligibility, status, rated, scopes }
375
+ * ```
376
+ */
377
+ export declare function buildOutcomeProjection(result: ProgramResult): Readonly<Record<string, unknown>>;
378
+
379
+ /**
380
+ * Builds a fresh {@link ProgramDefinition}.
381
+ *
382
+ * @remarks
383
+ * Omits absent optional keys. `metadata` is deep-copied with `structuredClone`.
384
+ * `notices` is copied as a fresh array whose elements are shared with the
385
+ * input. `qualification`, `rating`, `authority`, and `aggregate` are stored
386
+ * by reference. The {@link Program} constructor later snapshots and seals
387
+ * the whole graph.
388
+ *
389
+ * @param id - The program id
390
+ * @param name - The display name
391
+ * @param qualification - The nested qualification definition
392
+ * @param rating - The nested rating definition; omit for an eligibility-only program
393
+ * @param input - Optional description, notices, authority, aggregate, and metadata
394
+ * @returns A fresh program definition
395
+ *
396
+ * @example
397
+ * ```ts
398
+ * import { buildProgramDefinition } from '@orkestrel/program'
399
+ *
400
+ * buildProgramDefinition('standard', 'Standard', qualification, rating, { notices: [notice] })
401
+ * ```
402
+ */
403
+ export declare function buildProgramDefinition(id: string, name: string, qualification: QualificationDefinition, rating?: RatingDefinition, input?: ProgramInput): ProgramDefinition;
404
+
405
+ /**
406
+ * Assembles a {@link ProgramResult} from its qualification, rating, and
407
+ * determination parts — before or after authority.
408
+ *
409
+ * @remarks
410
+ * `eligibility` mirrors the qualification. `success` is execution integrity: the
411
+ * qualification succeeded, rating (when it ran) succeeded, and authority (when it
412
+ * ran) produced no errors — a valid ineligible or referral outcome still
413
+ * succeeds. `trace` and `errors` accumulate the qualification's, every rated
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`),
1187
416
  * no `limit` determination applied, and status is not `unrated`.
417
+ *
418
+ * @param definition - The authored program definition
419
+ * @param qualification - The subject's qualification result
420
+ * @param rating - The subject's rating result, when rating occurred
421
+ * @param determinations - The program-scoped determinations (notices, then limits)
422
+ * @param status - The already-derived status
423
+ * @param options - Optional authority result driving the decision projection
424
+ * @returns A fresh program result
425
+ *
426
+ * @example
427
+ * ```ts
428
+ * import { buildProgramResult } from '@orkestrel/program'
429
+ *
430
+ * buildProgramResult(definition, qualification, rating, [], 'eligible')
431
+ * ```
432
+ */
433
+ export declare function buildProgramResult(definition: ProgramDefinition, qualification: QualificationResult, rating: RatingResult | undefined, determinations: readonly Determination[], status: Status, options?: {
434
+ readonly authority?: LogicalResult;
435
+ }): ProgramResult;
436
+
437
+ /**
438
+ * Adds optional aggregate context to a private subject copy for qualification.
439
+ *
440
+ * @remarks
441
+ * The original subject is returned unchanged when no aggregate context exists.
442
+ * When context exists the helper creates a private copy under {@link AGGREGATE_KEY}
443
+ * and defensively copies every nested record — the rater still receives the
444
+ * original subject, never this copy.
445
+ *
446
+ * @param subject - The original caller subject
447
+ * @param aggregate - The subject's aggregate projection, when a batch supplies one
448
+ * @returns The subject, or a private copy carrying the aggregate projection
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * import { buildQualificationSubject } from '@orkestrel/program'
453
+ *
454
+ * buildQualificationSubject({ id: 'r1' }) // { id: 'r1' }
455
+ * ```
456
+ */
457
+ export declare function buildQualificationSubject(subject: Subject, aggregate?: AggregateProjection): Subject;
458
+
459
+ /**
460
+ * Completes a partial status tally record with zero entries for every missing
461
+ * {@link Status}.
462
+ *
463
+ * @param entries - The partial tally entries to complete
464
+ * @returns A record carrying every {@link Status}
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * import { completeTallies } from '@orkestrel/program'
469
+ *
470
+ * completeTallies({ eligible: { count: 1, sums: {} } })
471
+ * ```
472
+ */
473
+ export declare function completeTallies(entries: Partial<Record<Status, Tally>>): Readonly<Record<Status, Tally>>;
474
+
475
+ /**
476
+ * Creates one compiled {@link ProgramInterface} over a qualifier and rater.
477
+ *
478
+ * @remarks
479
+ * If `options.validate` is `true`, the program validates the definition at
480
+ * construction; if `false`, it compiles the definition unvalidated. Default:
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.
484
+ *
485
+ * @param definition - The authored program definition
486
+ * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks
487
+ * @returns A {@link ProgramInterface}
488
+ *
489
+ * @example Compile a program and a manager
490
+ * ```ts
491
+ * import { buildProgramDefinition, createProgram, createProgramManager } from '@orkestrel/program'
492
+ *
493
+ * const definition = buildProgramDefinition('standard', 'Standard', qualification, rating)
494
+ *
495
+ * const program = createProgram(definition)
496
+ * const manager = createProgramManager({ programs: [definition] })
497
+ *
498
+ * program.execute({ id: 'risk-1' })
499
+ *
500
+ * program.destroy()
501
+ * manager.destroy()
502
+ * ```
503
+ */
504
+ export declare function createProgram(definition: ProgramDefinition, options?: ProgramOptions): ProgramInterface;
505
+
506
+ /**
507
+ * Creates one ordered {@link ProgramManagerInterface} over compiled programs.
508
+ *
509
+ * @remarks
510
+ * Creates or borrows one shared reason engine, qualifier, and rater and injects
511
+ * them into every compiled program, so a batch of definitions shares one engine.
512
+ * Seed definitions are compiled in order.
513
+ *
514
+ * @param options - Optional injected qualifier, rater, engine, seed programs, validation, labels, and emitter hooks
515
+ * @returns A {@link ProgramManagerInterface}
516
+ *
517
+ * @example
518
+ * ```ts
519
+ * import { createProgramManager } from '@orkestrel/program'
520
+ *
521
+ * const manager = createProgramManager({ programs: [definition] })
522
+ * manager.program('standard')?.execute(subject)
523
+ * manager.destroy()
524
+ * ```
525
+ */
526
+ export declare function createProgramManager(options?: ProgramManagerOptions): ProgramManagerInterface;
527
+
528
+ /**
529
+ * Maps a global {@link Eligibility} to its deterministic authority {@link Decision}.
530
+ *
531
+ * @param eligibility - The global eligibility
532
+ * @returns The matching decision
533
+ *
534
+ * @example
535
+ * ```ts
536
+ * import { decideEligibility } from '@orkestrel/program'
537
+ *
538
+ * decideEligibility('eligible') // 'approved'
539
+ * decideEligibility('referral') // 'submitted'
540
+ * ```
541
+ */
542
+ export declare function decideEligibility(eligibility: Eligibility): Decision;
543
+
544
+ /** Identifies a final authority outcome, derived from global eligibility. */
545
+ export declare type Decision = 'approved' | 'denied' | 'submitted';
546
+
547
+ /**
548
+ * Names the default definition validation policy, `true`, for `createProgram` /
549
+ * `ProgramManager.add`.
550
+ */
551
+ export declare const DEFAULT_PROGRAM_VALIDATE = true;
552
+
553
+ /**
554
+ * Derives the final program {@link Status} from a definition's rating policy and
555
+ * qualification/rating evidence.
556
+ *
557
+ * @remarks
558
+ * Explicit policy, not an opaque precedence reduce: global
559
+ * ineligibility or referral is terminal; a scoped referral yields `referral`;
560
+ * an applied `condition` or an applied scoped `restriction` (a line was
561
+ * removed but others rated) is `conditional`. When the definition omits
562
+ * `rating` the program is eligibility-only — status resolves to `conditional`
563
+ * or `eligible` and is never `unrated`. Otherwise a subject with no successful
564
+ * rating is `unrated`.
565
+ *
566
+ * @param definition - The authored program definition
567
+ * @param qualification - The subject's qualification result
568
+ * @param rating - The subject's rating result, when rating occurred
569
+ * @returns The derived status
570
+ *
571
+ * @example
572
+ * ```ts
573
+ * import { deriveStatus } from '@orkestrel/program'
574
+ *
575
+ * deriveStatus(definition, qualification, rating) // 'eligible'
576
+ * ```
577
+ */
578
+ export declare function deriveStatus(definition: ProgramDefinition, qualification: QualificationResult, rating?: RatingResult): Status;
579
+
580
+ /** Describes one resolved notice or authority-limit outcome. */
581
+ export declare interface Determination {
582
+ readonly id: string;
583
+ readonly effect: ProgramEffect;
584
+ readonly applied: boolean;
585
+ readonly scope?: string;
586
+ readonly message?: string;
587
+ readonly premises: readonly Premise[];
588
+ }
589
+
590
+ /** Maps each global eligibility to its deterministic authority decision. */
591
+ export declare const ELIGIBILITY_DECISIONS: Readonly<Record<Eligibility, Decision>>;
592
+
593
+ /**
594
+ * Returns authored scopes (qualification ruling scopes or notice scopes) that
595
+ * name no rating line on the program.
596
+ *
597
+ * @remarks
598
+ * A scope is an opaque string to the qualifier — program alone matches it to a
599
+ * rating-line id. A scope naming no line is a hard authoring error surfaced as
600
+ * {@link ProgramError} `'MISSING'` at construction, regardless of the validate
601
+ * option.
602
+ *
603
+ * @param definition - The program definition to check
604
+ * @returns A fresh, deduped list of missing scope references
605
+ *
606
+ * @example
607
+ * ```ts
608
+ * import { findMissingScopes } from '@orkestrel/program'
609
+ *
610
+ * findMissingScopes(definition) // []
611
+ * ```
612
+ */
613
+ export declare function findMissingScopes(definition: ProgramDefinition): readonly string[];
614
+
615
+ /**
616
+ * Coerces a subject's partition-key field to its group-key string.
617
+ *
618
+ * @remarks
619
+ * The key is the resolved field coerced with `String` — `undefined` collapses
620
+ * to the empty string, so a subject missing the field and a subject whose
621
+ * field is literally `''` land in the same partition, and a numeric `1`
622
+ * collides with the string `'1'`.
623
+ *
624
+ * @param subject - The subject to key
625
+ * @param partition - The field the batch partitions on
626
+ * @returns The subject's group key
627
+ *
628
+ * @example
629
+ * ```ts
630
+ * import { formatGroupKey } from '@orkestrel/program'
631
+ *
632
+ * formatGroupKey({ location: 'east' }, 'location') // 'east'
633
+ * ```
634
+ */
635
+ export declare function formatGroupKey(subject: Subject, partition: FieldPath): string;
636
+
637
+ /**
638
+ * Determines whether a caller subject already carries a reserved program key.
639
+ *
640
+ * @remarks
641
+ * `aggregate` and `outcome` are program-private working-subject namespaces — the
642
+ * batch aggregate projection and the authority outcome projection are written
643
+ * under them. A caller subject that already owns either key would silently
644
+ * collide with a projection, so it is rejected before qualification.
645
+ *
646
+ * @param subject - The caller subject to check
647
+ * @returns True if the subject owns `aggregate` or `outcome`; false otherwise
648
+ *
649
+ * @example
650
+ * ```ts
651
+ * import { hasReservedKey } from '@orkestrel/program'
652
+ *
653
+ * hasReservedKey({ id: 'r1' }) // false
654
+ * hasReservedKey({ id: 'r1', aggregate: {} }) // true
655
+ * ```
656
+ */
657
+ export declare function hasReservedKey(subject: Readonly<Record<string, unknown>>): boolean;
658
+
659
+ /**
660
+ * Determines whether a value is an exact {@link AggregateDefinition} record.
661
+ *
662
+ * @param value - The candidate value
663
+ * @returns True if `value` is an {@link AggregateDefinition}; false otherwise
664
+ *
665
+ * @example
666
+ * ```ts
667
+ * import { isAggregateDefinition } from '@orkestrel/program'
668
+ *
669
+ * isAggregateDefinition({ fields: ['amount'] }) // true
670
+ * ```
671
+ */
672
+ export declare function isAggregateDefinition(value: unknown): value is AggregateDefinition;
673
+
674
+ /**
675
+ * Determines whether a value is an open result-side {@link AggregateGroup}.
676
+ *
677
+ * @remarks
678
+ * Unknown members and class instances are admitted. Arrays are refused.
679
+ *
680
+ * @param value - The candidate value
681
+ * @returns True if every published aggregate-group member conforms; false otherwise
682
+ *
683
+ * @example
684
+ * ```ts
685
+ * import { isAggregateGroup } from '@orkestrel/program'
686
+ *
687
+ * isAggregateGroup({ key: 'east', count: 1, sums: { premium: 100 } }) // true
688
+ * ```
689
+ */
690
+ export declare const isAggregateGroup: Guard<AggregateGroup>;
691
+
692
+ /**
693
+ * Determines whether a value is an open {@link AggregateResult}.
694
+ *
695
+ * @remarks
696
+ * This guard is result-postured for values returned through a borrowed
697
+ * {@link ProgramInterface}. It admits unknown members and class instances while
698
+ * checking every nested program result, determination, group, total tally
699
+ * record, and sums record. Arrays are refused.
700
+ *
701
+ * @param value - The candidate value
702
+ * @returns True if every published aggregate-result member conforms; false otherwise
703
+ *
704
+ * @example
705
+ * ```ts
706
+ * import { isAggregateResult } from '@orkestrel/program'
707
+ *
708
+ * isAggregateResult(program.execute(subjects)) // true
709
+ * ```
710
+ */
711
+ export declare const isAggregateResult: Guard<AggregateResult>;
712
+
713
+ /**
714
+ * Determines whether a value is a {@link Decision} literal.
715
+ *
716
+ * @param value - The candidate value
717
+ * @returns True if `value` is a {@link Decision}; false otherwise
718
+ *
719
+ * @example
720
+ * ```ts
721
+ * import { isDecision } from '@orkestrel/program'
722
+ *
723
+ * isDecision('approved') // true
724
+ * ```
725
+ */
726
+ export declare const isDecision: Guard<Decision>;
727
+
728
+ /**
729
+ * Determines whether a value is an open result-side {@link Determination}.
730
+ *
731
+ * @remarks
732
+ * Unknown members and class instances are admitted. Arrays are refused.
733
+ * Optional `scope` and `message` members may be absent or `undefined`.
734
+ *
735
+ * @param value - The candidate value
736
+ * @returns True if every published determination member conforms; false otherwise
737
+ *
738
+ * @example
739
+ * ```ts
740
+ * import { isDetermination } from '@orkestrel/program'
741
+ *
742
+ * isDetermination({ id: 'audit', effect: 'notice', applied: true, premises: [] }) // true
743
+ * ```
744
+ */
745
+ export declare const isDetermination: Guard<Determination>;
746
+
747
+ /**
748
+ * Determines whether a value is an exact {@link Notice} record.
749
+ *
750
+ * @param value - The candidate value
751
+ * @returns True if `value` is a {@link Notice}; false otherwise
752
+ *
753
+ * @example
754
+ * ```ts
755
+ * import { isNotice } from '@orkestrel/program'
756
+ *
757
+ * isNotice({ id: 'minimum', message: 'Minimum applies' }) // true
758
+ * ```
759
+ */
760
+ export declare function isNotice(value: unknown): value is Notice;
761
+
762
+ /**
763
+ * Determines whether a value is an exact {@link ProgramDefinition} record.
764
+ *
765
+ * @remarks
766
+ * `rating` is optional — an omitted `rating` authors an eligibility-only
767
+ * program (see {@link ProgramDefinition}).
768
+ *
769
+ * @param value - The candidate value
770
+ * @returns True if `value` is a {@link ProgramDefinition}; false otherwise
771
+ *
772
+ * @example
773
+ * ```ts
774
+ * import { isProgramDefinition } from '@orkestrel/program'
775
+ *
776
+ * isProgramDefinition({ id: 'p', name: 'P', qualification }) // true
777
+ * ```
778
+ */
779
+ export declare function isProgramDefinition(value: unknown): value is ProgramDefinition;
780
+
781
+ /**
782
+ * Determines whether a value is a {@link ProgramEffect} literal.
783
+ *
784
+ * @param value - The candidate value
785
+ * @returns True if `value` is a {@link ProgramEffect}; false otherwise
786
+ *
787
+ * @example
788
+ * ```ts
789
+ * import { isProgramEffect } from '@orkestrel/program'
790
+ *
791
+ * isProgramEffect('notice') // true
792
+ * ```
793
+ */
794
+ export declare const isProgramEffect: Guard<ProgramEffect>;
795
+
796
+ /**
797
+ * Determines whether a caught value is a {@link ProgramError}.
798
+ *
799
+ * @param value - The candidate value
800
+ * @returns True if the value is a {@link ProgramError}; false otherwise
801
+ *
802
+ * @example
803
+ * ```ts
804
+ * import { isProgramError, ProgramError } from '@orkestrel/program'
805
+ *
806
+ * isProgramError(new ProgramError('RESERVED', 'Subject carries a reserved key')) // true
807
+ * isProgramError(new Error('Subject carries a reserved key')) // false
808
+ * ```
809
+ */
810
+ export declare function isProgramError(value: unknown): value is ProgramError;
811
+
812
+ /**
813
+ * Determines whether a value is an open {@link ProgramResult}.
814
+ *
815
+ * @remarks
816
+ * This guard is result-postured for values returned through a borrowed
817
+ * {@link ProgramInterface}. It admits unknown members and class instances while
818
+ * composing qualifier's `isQualificationResult` and rater's `isRatingResult`
819
+ * over their complete nested result closures. Arrays are refused.
820
+ *
821
+ * @param value - The candidate value
822
+ * @returns True if every published program-result member conforms; false otherwise
823
+ *
824
+ * @example
825
+ * ```ts
826
+ * import { isProgramResult } from '@orkestrel/program'
827
+ *
828
+ * isProgramResult(program.execute(subject)) // true
829
+ * ```
830
+ */
831
+ export declare const isProgramResult: Guard<ProgramResult>;
832
+
833
+ /**
834
+ * Determines whether a value is an open program sums record.
835
+ *
836
+ * @remarks
837
+ * Every own string-named property is checked, including non-enumerable
838
+ * properties. Inherited and symbol-named members are outside the record this
839
+ * guard certifies. Values remain plain JavaScript numbers, including `NaN` and
840
+ * infinities, because the published contract does not refine them.
841
+ *
842
+ * @param value - The candidate value
843
+ * @returns True if every own string-named value is a number; false otherwise
844
+ *
845
+ * @example
846
+ * ```ts
847
+ * import { isProgramSums } from '@orkestrel/program'
848
+ *
849
+ * isProgramSums({ premium: 100 }) // true
850
+ * ```
851
+ */
852
+ export declare function isProgramSums(value: unknown): value is Readonly<Record<string, number>>;
853
+
854
+ /**
855
+ * Determines whether a value is an open {@link ProgramValidationResult}.
856
+ *
857
+ * @remarks
858
+ * `ProgramValidationResult` is this package's own declared interface, not an
859
+ * alias of reason's validation result. This guard therefore checks the
860
+ * program-owned members directly so the contracts may evolve independently.
861
+ * Unknown members and class instances are admitted. Arrays are refused.
862
+ *
863
+ * @param value - The candidate value
864
+ * @returns True if every published program-validation member conforms; false otherwise
865
+ *
866
+ * @example
867
+ * ```ts
868
+ * import { isProgramValidationResult } from '@orkestrel/program'
869
+ *
870
+ * isProgramValidationResult({ valid: true, errors: [], warnings: [] }) // true
871
+ * ```
872
+ */
873
+ export declare const isProgramValidationResult: Guard<ProgramValidationResult>;
874
+
875
+ /**
876
+ * Determines whether a value is a {@link Status} literal.
877
+ *
878
+ * @param value - The candidate value
879
+ * @returns True if `value` is a {@link Status}; false otherwise
880
+ *
881
+ * @example
882
+ * ```ts
883
+ * import { isStatus } from '@orkestrel/program'
884
+ *
885
+ * isStatus('eligible') // true
886
+ * ```
887
+ */
888
+ export declare const isStatus: Guard<Status>;
889
+
890
+ /**
891
+ * Determines whether a value is a total open status-tally record.
892
+ *
893
+ * @remarks
894
+ * Every {@link Status} in {@link STATUSES} is required and checked.
895
+ * Unknown members and class instances are admitted. Arrays are refused.
896
+ *
897
+ * @param value - The candidate value
898
+ * @returns True if every required status member is a {@link Tally}; false otherwise
899
+ *
900
+ * @example
901
+ * ```ts
902
+ * import { buildEmptyTallies, isTallies } from '@orkestrel/program'
903
+ *
904
+ * isTallies(buildEmptyTallies([])) // true
905
+ * ```
906
+ */
907
+ export declare function isTallies(value: unknown): value is Readonly<Record<Status, Tally>>;
908
+
909
+ /**
910
+ * Determines whether a value is an open result-side {@link Tally}.
911
+ *
912
+ * @remarks
913
+ * Unknown members and class instances are admitted. Arrays are refused.
914
+ *
915
+ * @param value - The candidate value
916
+ * @returns True if every published tally member conforms; false otherwise
917
+ *
918
+ * @example
919
+ * ```ts
920
+ * import { isTally } from '@orkestrel/program'
921
+ *
922
+ * isTally({ count: 1, sums: { premium: 100 } }) // true
923
+ * ```
924
+ */
925
+ export declare const isTally: Guard<Tally>;
926
+
927
+ /** Describes an authored, unconditional program notice. */
928
+ export declare interface Notice {
929
+ readonly id: string;
930
+ readonly message: string;
931
+ readonly scope?: string;
932
+ }
933
+
934
+ /**
935
+ * Describes the optional fields accepted by `buildNotice`.
936
+ *
937
+ * @remarks
938
+ * `scope` — the rating-line id the notice presents against; omitted for an
939
+ * unscoped, program-wide notice.
940
+ */
941
+ export declare interface NoticeInput {
942
+ readonly scope?: string;
943
+ }
944
+
945
+ /**
946
+ * Names the reserved working-subject key the authority's outcome projection is
947
+ * written under, `'outcome'`.
948
+ */
949
+ export declare const OUTCOME_KEY = "outcome";
950
+
951
+ /**
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.
954
+ *
955
+ * @remarks
956
+ * Qualification decides whether rating happens: a globally ineligible, referred,
957
+ * or failed subject never reaches the rater, and a scoped ineligibility removes
958
+ * only its line before the first rating call. The rater always receives the
959
+ * original subject; the qualifier's aggregate projection stays private. When no
960
+ * qualifier, rater, or engine is injected the program creates one shared
961
+ * quantitative-plus-logical engine, injects it into the qualifier and rater it
962
+ * creates, and destroys only what it owns. A definition failure during
963
+ * construction (an invalid definition under `options.validate`) tears down
964
+ * whatever the constructor had already allocated before throwing. Construction
965
+ * snapshots the caller's definition once, runs the always-on assertions against
966
+ * that snapshot, and seals its plain-object graph before exposure. A `Map`, `Set`,
967
+ * or `Date` reached through a reason `Check.value` is cloned but remains mutable
968
+ * because its contents live in internal slots. Uncloneable values and non-empty
969
+ * typed arrays are refused with `ProgramError('DEFINITION')` and the host error
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
972
+ * that re-enters `destroy()` is a no-op — and tears the emitter down last.
1188
973
  */
1189
- readonly decision?: Decision;
1190
- readonly qualification: QualificationResult;
1191
- readonly rating?: RatingResult;
1192
- readonly determinations: readonly Determination[];
1193
- readonly success: boolean;
1194
- readonly trace: readonly string[];
1195
- readonly errors: readonly string[];
1196
- }
1197
-
1198
- /** Semantic definition validation. */
1199
- export declare interface ProgramValidationResult {
1200
- readonly valid: boolean;
1201
- readonly errors: readonly string[];
1202
- readonly warnings: readonly string[];
1203
- }
1204
-
1205
- /**
1206
- * Select the rating lines a subject may be rated on from scoped eligibility.
1207
- *
1208
- * @remarks
1209
- * A scope names a rating-line id. A line survives when its scope is absent
1210
- * (eligible by default), `eligible`, or a `condition` (which is not an
1211
- * eligibility value and never appears here). A scoped `ineligible` or `referral`
1212
- * removes the line BEFORE the rater is invoked — the excluded line is never
1213
- * evaluated merely to discard its amount.
1214
- *
1215
- * @param lines - The program's authored rating lines
1216
- * @param scopes - The qualification's per-scope eligibility
1217
- * @returns The surviving line definitions, in authored order
1218
- *
1219
- * @example
1220
- * ```ts
1221
- * import { selectProgramLines } from '@orkestrel/program'
1222
- *
1223
- * selectProgramLines(lines, { wind: 'ineligible' }) // every line except 'wind'
1224
- * ```
1225
- */
1226
- export declare function selectProgramLines(lines: readonly LineDefinition[], scopes: Readonly<Record<string, Eligibility>>): readonly LineDefinition[];
1227
-
1228
- /** The presentation and tally status derived from eligibility, conditions, and rating success. */
1229
- export declare type Status = 'ineligible' | 'referral' | 'conditional' | 'unrated' | 'eligible';
1230
-
1231
- /** Status tally precedence order least to most resolved. */
1232
- export declare const STATUS_PRECEDENCE: readonly Status[];
1233
-
1234
- /**
1235
- * Fold one subject's finite aggregate field values into a sums record.
1236
- *
1237
- * @remarks
1238
- * Returns a FRESH record `sums` is never mutated. Only finite numbers
1239
- * contribute; a non-numeric or absent value contributes zero (never a
1240
- * coercion). A {@link FieldPath} may be nested `formatField` renders the
1241
- * dot-joined key the returned record is keyed by.
1242
- *
1243
- * @param sums - The sums record to fold into
1244
- * @param subject - The subject to fold in
1245
- * @param fields - The fields to sum
1246
- * @returns A fresh sums record with `subject`'s contribution added
1247
- *
1248
- * @example
1249
- * ```ts
1250
- * import { sumFields } from '@orkestrel/program'
1251
- *
1252
- * sumFields({ amount: 0 }, { amount: 5 }, ['amount']) // { amount: 5 }
1253
- * ```
1254
- */
1255
- export declare function sumFields(sums: Readonly<Record<string, number>>, subject: Subject, fields: readonly FieldPath[]): Readonly<Record<string, number>>;
1256
-
1257
- /** A status tally — a count plus summed aggregate fields. */
1258
- export declare interface Tally {
1259
- readonly count: number;
1260
- readonly sums: Readonly<Record<string, number>>;
1261
- }
1262
-
1263
- /**
1264
- * Add one subject's aggregate contribution to a status tally record.
1265
- *
1266
- * @param tallies - The tallies to update
1267
- * @param result - The subject's program result (its `status` selects the tally)
1268
- * @param subject - The subject to fold in
1269
- * @param fields - The fields to sum
1270
- * @returns A fresh, complete tally record with the subject folded in
1271
- *
1272
- * @example
1273
- * ```ts
1274
- * import { tallyProgram } from '@orkestrel/program'
1275
- *
1276
- * tallyProgram(tallies, result, { id: 'r1', amount: 5 }, ['amount'])
1277
- * ```
1278
- */
1279
- export declare function tallyProgram(tallies: Readonly<Record<Status, Tally>>, result: ProgramResult, subject: Subject, fields: readonly FieldPath[]): Readonly<Record<Status, Tally>>;
1280
-
1281
- /**
1282
- * Validate a program definition's shape, references, and nested definitions.
1283
- *
1284
- * @remarks
1285
- * The single semantic-validation implementation used by `Program.validate`. It
1286
- * establishes exact shape through {@link isProgramDefinition}, validates the
1287
- * rating structurally through the rater's {@link isRatingDefinition} guard (the
1288
- * rater exposes no `validate`), delegates qualification validation to the
1289
- * injected qualifier and authority / aggregate-gate validation to the shared
1290
- * reason engine, and checks scope, notice, and aggregate-field references here.
1291
- *
1292
- * @param definition - The program definition to validate
1293
- * @param qualifier - The qualifier that validates the nested qualification
1294
- * @param engine - The reason engine that validates authority and aggregate gates
1295
- * @returns A structured validation result
1296
- *
1297
- * @example
1298
- * ```ts
1299
- * import { validateProgramDefinition } from '@orkestrel/program'
1300
- *
1301
- * validateProgramDefinition(definition, qualifier, engine) // { valid: true, ... }
1302
- * ```
1303
- */
1304
- export declare function validateProgramDefinition(definition: ProgramDefinition, qualifier: QualifierInterface, engine: ReasonInterface): ProgramValidationResult;
1305
-
1306
- export { }
974
+ export declare class Program implements ProgramInterface {
975
+ #private;
976
+ /** Holds the authored id of the definition this program compiled. */
977
+ readonly id: string;
978
+ /** Holds the authored display name of the definition this program compiled. */
979
+ readonly name: string;
980
+ /** Holds the sealed snapshot of the authored definition this program compiled. */
981
+ readonly definition: ProgramDefinition;
982
+ /**
983
+ * Compiles one program from an authored definition.
984
+ *
985
+ * @param definition - The authored program definition
986
+ * @param options - Optional injected qualifier, rater, engine, validation, labels, and emitter hooks
987
+ * @throws {@link ProgramError} Thrown when the definition cannot be cloned or
988
+ * sealed, or when validation is enabled and the definition fails
989
+ * (`'DEFINITION'`).
990
+ * @throws {@link ProgramError} Thrown when a ruling or notice scope names no
991
+ * rating line (`'MISSING'`).
992
+ * @throws {@link ProgramError} Thrown when the definition repeats a rating-line
993
+ * or notice id (`'DUPLICATE'`).
994
+ */
995
+ constructor(definition: ProgramDefinition, options?: ProgramOptions);
996
+ /**
997
+ * Holds the typed observation surface carrying `qualify`, `rate`, `determine`,
998
+ * `decide`, `execute`, `aggregate`, and `destroy`.
999
+ *
1000
+ * @returns The emitter this program owns
1001
+ *
1002
+ * @example
1003
+ * ```ts
1004
+ * import { createProgram } from '@orkestrel/program'
1005
+ *
1006
+ * const program = createProgram(definition)
1007
+ * program.emitter.on('execute', (result) => result.status)
1008
+ * program.destroy()
1009
+ * ```
1010
+ */
1011
+ get emitter(): EmitterInterface<ProgramEventMap>;
1012
+ /**
1013
+ * Executes a subject list as one aggregate-aware batch.
1014
+ *
1015
+ * @remarks
1016
+ * Every subject is asserted before any work runs, so a reserved key in the last
1017
+ * subject rejects the batch before the first one qualifies. The batch sums,
1018
+ * partitions, and per-subject aggregate projections are computed next, each
1019
+ * subject executes in input order, every result tallies by status, and optional
1020
+ * aggregate gates run last against the batch aggregate record.
1021
+ *
1022
+ * @param subjects - The subjects to execute, in input order
1023
+ * @returns A fresh aggregate result carrying every subject result, the batch
1024
+ * determinations, partitions, tallies, and sums
1025
+ * @throws {@link ProgramError} Thrown when the program has been destroyed
1026
+ * (`'DESTROYED'`).
1027
+ * @throws {@link ProgramError} Thrown when a subject is not a record, or when a
1028
+ * borrowed qualifier, rater, or reason engine returns an off-contract result
1029
+ * (`'MISMATCH'`).
1030
+ * @throws {@link ProgramError} Thrown when a subject already carries the
1031
+ * `aggregate` or `outcome` key (`'RESERVED'`).
1032
+ *
1033
+ * @example
1034
+ * ```ts
1035
+ * import { createProgram } from '@orkestrel/program'
1036
+ *
1037
+ * const program = createProgram(definition)
1038
+ * program.execute([{ id: 'risk-1', licensed: true }]).count // 1
1039
+ * program.destroy()
1040
+ * ```
1041
+ */
1042
+ execute(subjects: readonly Subject[]): AggregateResult;
1043
+ /**
1044
+ * Executes one subject through the composed qualify-rate-determine workflow.
1045
+ *
1046
+ * @remarks
1047
+ * Qualification decides whether rating happens: a globally ineligible, referred,
1048
+ * or failed subject never reaches the rater, and a scoped ineligibility removes
1049
+ * only its line before the first rating call. The rater always receives the
1050
+ * original subject. Notices, status, optional authority, and the optional
1051
+ * decision follow, in that order.
1052
+ *
1053
+ * @param subject - The subject to execute
1054
+ * @returns A fresh program result carrying the nested qualification and rating
1055
+ * evidence, determinations, status, and optional decision
1056
+ * @throws {@link ProgramError} Thrown when the program has been destroyed
1057
+ * (`'DESTROYED'`).
1058
+ * @throws {@link ProgramError} Thrown when the subject is not a record, or when a
1059
+ * borrowed qualifier, rater, or reason engine returns an off-contract result
1060
+ * (`'MISMATCH'`).
1061
+ * @throws {@link ProgramError} Thrown when the subject already carries the
1062
+ * `aggregate` or `outcome` key (`'RESERVED'`).
1063
+ *
1064
+ * @example
1065
+ * ```ts
1066
+ * import { createProgram } from '@orkestrel/program'
1067
+ *
1068
+ * const program = createProgram(definition)
1069
+ * program.execute({ id: 'risk-1', licensed: true }).status // 'eligible'
1070
+ * program.destroy()
1071
+ * ```
1072
+ */
1073
+ execute(subject: Subject): ProgramResult;
1074
+ /**
1075
+ * Validates this program's definition and every nested definition.
1076
+ *
1077
+ * @remarks
1078
+ * Exact shape is `isProgramDefinition`'s job. This checks the meaning: non-empty id
1079
+ * and name, every ruling and notice scope naming a rating line, unique non-empty
1080
+ * aggregate fields, and a non-empty partition field when present. Nested
1081
+ * qualification validation is delegated to the injected qualifier, and authority
1082
+ * and aggregate-gate validation to the shared reason engine.
1083
+ *
1084
+ * @returns A fresh validation result carrying `valid`, `errors`, and `warnings`
1085
+ * @throws {@link ProgramError} Thrown when the program has been destroyed
1086
+ * (`'DESTROYED'`).
1087
+ *
1088
+ * @example
1089
+ * ```ts
1090
+ * import { createProgram } from '@orkestrel/program'
1091
+ *
1092
+ * const program = createProgram(definition, { validate: false })
1093
+ * program.validate().valid // true
1094
+ * program.destroy()
1095
+ * ```
1096
+ */
1097
+ validate(): ProgramValidationResult;
1098
+ /**
1099
+ * Destroys this program, idempotently.
1100
+ *
1101
+ * @remarks
1102
+ * The destroyed flag is set before any teardown or the `destroy` event, so a
1103
+ * listener re-entering `destroy` is a no-op. An owned qualifier, rater, and reason
1104
+ * engine are destroyed; an injected one stays caller-owned. The emitter is torn
1105
+ * down last, and stays reachable afterwards.
1106
+ *
1107
+ * @example
1108
+ * ```ts
1109
+ * import { createProgram } from '@orkestrel/program'
1110
+ *
1111
+ * const program = createProgram(definition)
1112
+ * program.destroy()
1113
+ * program.destroy() // a second call is a no-op
1114
+ * ```
1115
+ */
1116
+ destroy(): void;
1117
+ }
1118
+
1119
+ /**
1120
+ * Describes a pure authored program definition.
1121
+ *
1122
+ * @remarks
1123
+ * `qualification` runs first through `@orkestrel/qualifier`; `rating` runs only
1124
+ * over the lines scoped eligibility left standing, through `@orkestrel/rater`.
1125
+ * `authority` (a logical definition) runs last, over the assembled result
1126
+ * extended with an outcome projection, to derive limit determinations and the
1127
+ * final decision. An omitted `rating` authors an eligibility-only program — the
1128
+ * rater is never invoked, an eligible subject resolves to `'eligible'` (or
1129
+ * `'conditional'` under an applied condition or scoped restriction), status is
1130
+ * never `'unrated'`, and decisions remain reachable through `authority`. Program
1131
+ * construction clones the definition and seals its plain-object graph. A `Map`,
1132
+ * `Set`, or `Date` reached through a reason `Check.value` is cloned, but its
1133
+ * contents remain mutable because the seal cannot reach its internal slots. A
1134
+ * value that structured cloning cannot copy, or a non-empty typed array that
1135
+ * cannot be frozen, is refused with `ProgramError('DEFINITION')` and the host
1136
+ * error attached as its cause.
1137
+ */
1138
+ export declare interface ProgramDefinition {
1139
+ readonly id: string;
1140
+ readonly name: string;
1141
+ readonly description?: string;
1142
+ readonly qualification: QualificationDefinition;
1143
+ readonly rating?: RatingDefinition;
1144
+ readonly notices?: readonly Notice[];
1145
+ readonly authority?: LogicalDefinition;
1146
+ readonly aggregate?: AggregateDefinition;
1147
+ readonly metadata?: JSONValue;
1148
+ }
1149
+
1150
+ /** Identifies a post-qualification program determination effect. */
1151
+ export declare type ProgramEffect = 'notice' | 'limit';
1152
+
1153
+ /**
1154
+ * Reports a coded programmer error thrown by the program layer, carrying a
1155
+ * machine-readable code and an optional context and cause.
1156
+ *
1157
+ * @remarks
1158
+ * `DUPLICATE` — a program id collision on `ProgramManager.add`, or a duplicate
1159
+ * authored rating-line or notice id. `MISSING` — an authored notice or
1160
+ * qualification ruling scope names no rating line.
1161
+ * `DEFINITION` — a program, qualification, rating, authority, or aggregate
1162
+ * policy failed validation. `MISMATCH` — an injected entity or a returned
1163
+ * reason result has the wrong contract. `RESERVED` — a subject already
1164
+ * carries `aggregate` or `outcome`. `DESTROYED` — use of a destroyed entity.
1165
+ *
1166
+ * @example
1167
+ * ```ts
1168
+ * import { ProgramError } from '@orkestrel/program'
1169
+ *
1170
+ * const error = new ProgramError('RESERVED', 'Subject carries a reserved key', 'aggregate')
1171
+ * error.code // 'RESERVED'
1172
+ * ```
1173
+ */
1174
+ export declare class ProgramError extends Error {
1175
+ readonly code: ProgramErrorCode;
1176
+ readonly context?: unknown;
1177
+ /**
1178
+ * Creates a coded program error.
1179
+ *
1180
+ * @param code - The machine-readable failure category
1181
+ * @param message - The human-readable failure description
1182
+ * @param context - Optional structured context for the failure
1183
+ * @param cause - Optional underlying value the failure wraps
1184
+ */
1185
+ constructor(code: ProgramErrorCode, message: string, context?: unknown, cause?: unknown);
1186
+ }
1187
+
1188
+ /** Identifies a coded {@link ProgramError} programmer-error code. */
1189
+ export declare type ProgramErrorCode = 'DUPLICATE' | 'MISSING' | 'DEFINITION' | 'MISMATCH' | 'RESERVED' | 'DESTROYED';
1190
+
1191
+ /**
1192
+ * Describes the push observation surface of a {@link ProgramInterface}.
1193
+ *
1194
+ * @remarks
1195
+ * `rate` fires only when at least one line was selected. `determine` fires once
1196
+ * per notice, then once per applied limit. `decide` fires only when a decision
1197
+ * was reached.
1198
+ */
1199
+ export declare type ProgramEventMap = {
1200
+ readonly qualify: readonly [result: QualificationResult];
1201
+ readonly rate: readonly [result: RatingResult];
1202
+ readonly determine: readonly [result: Determination];
1203
+ readonly decide: readonly [decision: Decision, result: ProgramResult];
1204
+ readonly execute: readonly [result: ProgramResult];
1205
+ readonly aggregate: readonly [result: AggregateResult];
1206
+ readonly destroy: readonly [];
1207
+ };
1208
+
1209
+ /**
1210
+ * Describes the optional fields accepted by `buildProgramDefinition`.
1211
+ *
1212
+ * @remarks
1213
+ * `description` — a free-text summary. `notices` — authored unconditional
1214
+ * notices. `authority` — a logical definition evaluated per subject to derive
1215
+ * limit determinations and the decision. `aggregate` — batch aggregate fields,
1216
+ * partition field, and gates. `metadata` — opaque caller data, copied fresh.
1217
+ */
1218
+ export declare interface ProgramInput {
1219
+ readonly description?: string;
1220
+ readonly notices?: readonly Notice[];
1221
+ readonly authority?: LogicalDefinition;
1222
+ readonly aggregate?: AggregateDefinition;
1223
+ readonly metadata?: JSONValue;
1224
+ }
1225
+
1226
+ /**
1227
+ * Defines one compiled program that composes one qualifier and one rater over a
1228
+ * shared reason engine.
1229
+ */
1230
+ export declare interface ProgramInterface {
1231
+ /** Holds the authored id of the definition this program compiled. */
1232
+ readonly id: string;
1233
+ /** Holds the authored display name of the definition this program compiled. */
1234
+ readonly name: string;
1235
+ /** Holds the sealed snapshot of the authored definition this program compiled. */
1236
+ readonly definition: ProgramDefinition;
1237
+ /**
1238
+ * Holds the typed observation surface carrying `qualify`, `rate`, `determine`,
1239
+ * `decide`, `execute`, `aggregate`, and `destroy`.
1240
+ */
1241
+ readonly emitter: EmitterInterface<ProgramEventMap>;
1242
+ /**
1243
+ * Executes a subject list as one aggregate-aware batch.
1244
+ *
1245
+ * @remarks
1246
+ * Every subject is asserted before any work runs, so a reserved key in the last
1247
+ * subject rejects the batch before the first one qualifies. The batch sums,
1248
+ * partitions, and per-subject aggregate projections are computed next, each
1249
+ * subject executes in input order, every result tallies by status, and optional
1250
+ * aggregate gates run last against the batch aggregate record.
1251
+ *
1252
+ * @param subjects - The subjects to execute, in input order
1253
+ * @returns A fresh aggregate result carrying every subject result, the batch
1254
+ * determinations, partitions, tallies, and sums
1255
+ * @throws {@link ProgramError} Thrown when the program has been destroyed
1256
+ * (`'DESTROYED'`).
1257
+ * @throws {@link ProgramError} Thrown when a subject is not a record, or when a
1258
+ * borrowed qualifier, rater, or reason engine returns an off-contract result
1259
+ * (`'MISMATCH'`).
1260
+ * @throws {@link ProgramError} Thrown when a subject already carries the
1261
+ * `aggregate` or `outcome` key (`'RESERVED'`).
1262
+ *
1263
+ * @example
1264
+ * ```ts
1265
+ * import { createProgram } from '@orkestrel/program'
1266
+ *
1267
+ * const program = createProgram(definition)
1268
+ * program.execute([{ id: 'risk-1', licensed: true }]).count // 1
1269
+ * program.destroy()
1270
+ * ```
1271
+ */
1272
+ execute(subjects: readonly Subject[]): AggregateResult;
1273
+ /**
1274
+ * Executes one subject through the composed qualify-rate-determine workflow.
1275
+ *
1276
+ * @remarks
1277
+ * Qualification decides whether rating happens: a globally ineligible, referred,
1278
+ * or failed subject never reaches the rater, and a scoped ineligibility removes
1279
+ * only its line before the first rating call. The rater always receives the
1280
+ * original subject. Notices, status, optional authority, and the optional
1281
+ * decision follow, in that order.
1282
+ *
1283
+ * @param subject - The subject to execute
1284
+ * @returns A fresh program result carrying the nested qualification and rating
1285
+ * evidence, determinations, status, and optional decision
1286
+ * @throws {@link ProgramError} Thrown when the program has been destroyed
1287
+ * (`'DESTROYED'`).
1288
+ * @throws {@link ProgramError} Thrown when the subject is not a record, or when a
1289
+ * borrowed qualifier, rater, or reason engine returns an off-contract result
1290
+ * (`'MISMATCH'`).
1291
+ * @throws {@link ProgramError} Thrown when the subject already carries the
1292
+ * `aggregate` or `outcome` key (`'RESERVED'`).
1293
+ *
1294
+ * @example
1295
+ * ```ts
1296
+ * import { createProgram } from '@orkestrel/program'
1297
+ *
1298
+ * const program = createProgram(definition)
1299
+ * program.execute({ id: 'risk-1', licensed: true }).status // 'eligible'
1300
+ * program.destroy()
1301
+ * ```
1302
+ */
1303
+ execute(subject: Subject): ProgramResult;
1304
+ /**
1305
+ * Validates this program's definition and every nested definition.
1306
+ *
1307
+ * @remarks
1308
+ * Exact shape is `isProgramDefinition`'s job. This checks the meaning: non-empty id
1309
+ * and name, every ruling and notice scope naming a rating line, unique non-empty
1310
+ * aggregate fields, and a non-empty partition field when present. Nested
1311
+ * qualification validation is delegated to the injected qualifier, and authority
1312
+ * and aggregate-gate validation to the shared reason engine.
1313
+ *
1314
+ * @returns A fresh validation result carrying `valid`, `errors`, and `warnings`
1315
+ * @throws {@link ProgramError} Thrown when the program has been destroyed
1316
+ * (`'DESTROYED'`).
1317
+ *
1318
+ * @example
1319
+ * ```ts
1320
+ * import { createProgram } from '@orkestrel/program'
1321
+ *
1322
+ * const program = createProgram(definition, { validate: false })
1323
+ * program.validate().valid // true
1324
+ * program.destroy()
1325
+ * ```
1326
+ */
1327
+ validate(): ProgramValidationResult;
1328
+ /**
1329
+ * Destroys this program, idempotently.
1330
+ *
1331
+ * @remarks
1332
+ * The destroyed flag is set before any teardown or the `destroy` event, so a
1333
+ * listener re-entering `destroy` is a no-op. An owned qualifier, rater, and reason
1334
+ * engine are destroyed; an injected one stays caller-owned. The emitter is torn
1335
+ * down last, and stays reachable afterwards.
1336
+ *
1337
+ * @example
1338
+ * ```ts
1339
+ * import { createProgram } from '@orkestrel/program'
1340
+ *
1341
+ * const program = createProgram(definition)
1342
+ * program.destroy()
1343
+ * program.destroy() // a second call is a no-op
1344
+ * ```
1345
+ */
1346
+ destroy(): void;
1347
+ }
1348
+
1349
+ /**
1350
+ * Manages compiled {@link ProgramInterface} programs in order, sharing one
1351
+ * qualifier, rater, and reason engine across every program it compiles.
1352
+ *
1353
+ * @remarks
1354
+ * owns its ordered `#programs` collection and its own {@link Emitter} over
1355
+ * {@link ProgramManagerEventMap}. Creates or borrows one shared engine, qualifier,
1356
+ * and rater and injects the same instances into every compiled program. `remove`
1357
+ * destroys the programs it removes; `destroy()` removes all programs, then
1358
+ * destroys only the owned shared dependencies, and tears the emitter down last.
1359
+ * A seed-program failure during construction tears the manager down (destroying
1360
+ * whatever had already been compiled) before rethrowing the original error.
1361
+ * `destroy()` is reentrancy-safe — the destroyed flag is set before any teardown
1362
+ * or the `remove` / `destroy` events fire, so a `remove` listener that re-enters
1363
+ * `destroy()` is a no-op. Every call after `destroy()` throws {@link ProgramError}
1364
+ * `'DESTROYED'`.
1365
+ */
1366
+ export declare class ProgramManager implements ProgramManagerInterface {
1367
+ #private;
1368
+ /**
1369
+ * Creates one manager and compiles every seed definition in order.
1370
+ *
1371
+ * @param options - Optional injected qualifier, rater, engine, seed programs, validation, labels, and emitter hooks
1372
+ * @throws {@link ProgramError} Thrown when a seed definition fails to compile,
1373
+ * after the manager destroys whatever it had already compiled.
1374
+ */
1375
+ constructor(options?: ProgramManagerOptions);
1376
+ /**
1377
+ * Holds the typed observation surface carrying `add`, `remove`, and `destroy`.
1378
+ *
1379
+ * @returns The emitter this manager owns
1380
+ *
1381
+ * @example
1382
+ * ```ts
1383
+ * import { createProgramManager } from '@orkestrel/program'
1384
+ *
1385
+ * const manager = createProgramManager()
1386
+ * manager.emitter.on('add', (id) => id)
1387
+ * manager.destroy()
1388
+ * ```
1389
+ */
1390
+ get emitter(): EmitterInterface<ProgramManagerEventMap>;
1391
+ /**
1392
+ * Holds how many programs the manager has compiled.
1393
+ *
1394
+ * @returns The number of compiled programs
1395
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1396
+ * (`'DESTROYED'`).
1397
+ *
1398
+ * @example
1399
+ * ```ts
1400
+ * import { createProgramManager } from '@orkestrel/program'
1401
+ *
1402
+ * const manager = createProgramManager({ programs: [definition] })
1403
+ * manager.count // 1
1404
+ * manager.destroy()
1405
+ * ```
1406
+ */
1407
+ get count(): number;
1408
+ /**
1409
+ * Reports whether an id names a compiled program.
1410
+ *
1411
+ * @param id - The program id to look for
1412
+ * @returns True if a compiled program carries the id; false otherwise
1413
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1414
+ * (`'DESTROYED'`).
1415
+ *
1416
+ * @example
1417
+ * ```ts
1418
+ * import { createProgramManager } from '@orkestrel/program'
1419
+ *
1420
+ * const manager = createProgramManager({ programs: [definition] })
1421
+ * manager.has('standard') // true
1422
+ * manager.destroy()
1423
+ * ```
1424
+ */
1425
+ has(id: string): boolean;
1426
+ /**
1427
+ * Looks one compiled program up by id.
1428
+ *
1429
+ * @param id - The program id to look up
1430
+ * @returns The compiled program, or `undefined` when no program carries the id
1431
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1432
+ * (`'DESTROYED'`).
1433
+ *
1434
+ * @example
1435
+ * ```ts
1436
+ * import { createProgramManager } from '@orkestrel/program'
1437
+ *
1438
+ * const manager = createProgramManager({ programs: [definition] })
1439
+ * manager.program('standard')?.execute({ id: 'risk-1', licensed: true })
1440
+ * manager.destroy()
1441
+ * ```
1442
+ */
1443
+ program(id: string): ProgramInterface | undefined;
1444
+ /**
1445
+ * Returns every compiled program, in insertion order.
1446
+ *
1447
+ * @remarks
1448
+ * The returned array is a fresh copy, so mutating it never reaches the manager's
1449
+ * own collection.
1450
+ *
1451
+ * @returns A fresh array of compiled programs, in insertion order
1452
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1453
+ * (`'DESTROYED'`).
1454
+ *
1455
+ * @example
1456
+ * ```ts
1457
+ * import { createProgramManager } from '@orkestrel/program'
1458
+ *
1459
+ * const manager = createProgramManager({ programs: [definition] })
1460
+ * manager.programs().map((program) => program.id) // ['standard']
1461
+ * manager.destroy()
1462
+ * ```
1463
+ */
1464
+ programs(): readonly ProgramInterface[];
1465
+ /**
1466
+ * Compiles one definition and appends it to the collection.
1467
+ *
1468
+ * @remarks
1469
+ * The compiled program borrows the manager's shared qualifier, rater, and reason
1470
+ * engine, and inherits the manager's `validate` and `labels` options. After
1471
+ * appending the program, the `add` event fires with its id.
1472
+ *
1473
+ * @param definition - The authored program definition to compile
1474
+ * @returns The compiled program
1475
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1476
+ * (`'DESTROYED'`).
1477
+ * @throws {@link ProgramError} Thrown when the manager already carries the
1478
+ * definition's id, or the definition repeats a rating-line or notice id
1479
+ * (`'DUPLICATE'`).
1480
+ * @throws {@link ProgramError} Thrown when a ruling or notice scope names no
1481
+ * rating line (`'MISSING'`).
1482
+ * @throws {@link ProgramError} Thrown when validation is enabled and the
1483
+ * definition fails (`'DEFINITION'`).
1484
+ *
1485
+ * @example
1486
+ * ```ts
1487
+ * import { createProgramManager } from '@orkestrel/program'
1488
+ *
1489
+ * const manager = createProgramManager()
1490
+ * manager.add(definition).id // 'standard'
1491
+ * manager.destroy()
1492
+ * ```
1493
+ */
1494
+ add(definition: ProgramDefinition): ProgramInterface;
1495
+ /**
1496
+ * Removes every listed id, destroying each removed program.
1497
+ *
1498
+ * @remarks
1499
+ * Every id is attempted, so one absent id does not stop the rest. Each removal
1500
+ * destroys its program and fires `remove` with that id. An empty list succeeds
1501
+ * vacuously.
1502
+ *
1503
+ * @param ids - The program ids to remove
1504
+ * @returns True if every listed id named a compiled program; false otherwise
1505
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1506
+ * (`'DESTROYED'`).
1507
+ *
1508
+ * @example
1509
+ * ```ts
1510
+ * import { createProgramManager } from '@orkestrel/program'
1511
+ *
1512
+ * const manager = createProgramManager({ programs: [definition] })
1513
+ * manager.remove(['standard', 'absent']) // false
1514
+ * manager.destroy()
1515
+ * ```
1516
+ */
1517
+ remove(ids: readonly string[]): boolean;
1518
+ /**
1519
+ * Removes one id, destroying the program it named.
1520
+ *
1521
+ * @param id - The program id to remove
1522
+ * @returns True if the id named a compiled program; false otherwise
1523
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1524
+ * (`'DESTROYED'`).
1525
+ *
1526
+ * @example
1527
+ * ```ts
1528
+ * import { createProgramManager } from '@orkestrel/program'
1529
+ *
1530
+ * const manager = createProgramManager({ programs: [definition] })
1531
+ * manager.remove('standard') // true
1532
+ * manager.destroy()
1533
+ * ```
1534
+ */
1535
+ remove(id: string): boolean;
1536
+ /**
1537
+ * Removes every compiled program, destroying each one.
1538
+ *
1539
+ * @remarks
1540
+ * Each removal fires `remove` with that program's id. The manager itself stays
1541
+ * usable, so a later `add` compiles into the drained collection.
1542
+ *
1543
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1544
+ * (`'DESTROYED'`).
1545
+ *
1546
+ * @example
1547
+ * ```ts
1548
+ * import { createProgramManager } from '@orkestrel/program'
1549
+ *
1550
+ * const manager = createProgramManager({ programs: [definition] })
1551
+ * manager.remove()
1552
+ * manager.destroy()
1553
+ * ```
1554
+ */
1555
+ remove(): void;
1556
+ /**
1557
+ * Destroys this manager, idempotently.
1558
+ *
1559
+ * @remarks
1560
+ * The destroyed flag is set before any teardown or the `remove` and `destroy`
1561
+ * events, so a `remove` listener re-entering `destroy` is a no-op. Compiled
1562
+ * programs are destroyed first, then an owned qualifier, rater, and reason engine;
1563
+ * an injected one stays caller-owned. The emitter is torn down last, and stays
1564
+ * reachable afterwards.
1565
+ *
1566
+ * @example
1567
+ * ```ts
1568
+ * import { createProgramManager } from '@orkestrel/program'
1569
+ *
1570
+ * const manager = createProgramManager({ programs: [definition] })
1571
+ * manager.destroy()
1572
+ * manager.destroy() // a second call is a no-op
1573
+ * ```
1574
+ */
1575
+ destroy(): void;
1576
+ }
1577
+
1578
+ /** Describes the push observation surface of a {@link ProgramManagerInterface}. */
1579
+ export declare type ProgramManagerEventMap = {
1580
+ readonly add: readonly [id: string];
1581
+ readonly remove: readonly [id: string];
1582
+ readonly destroy: readonly [];
1583
+ };
1584
+
1585
+ /** Defines an ordered manager over compiled programs, sharing one qualifier and rater. */
1586
+ export declare interface ProgramManagerInterface {
1587
+ /**
1588
+ * Holds the typed observation surface carrying `add`, `remove`, and `destroy`.
1589
+ */
1590
+ readonly emitter: EmitterInterface<ProgramManagerEventMap>;
1591
+ /**
1592
+ * Holds how many programs the manager has compiled.
1593
+ *
1594
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1595
+ * (`'DESTROYED'`).
1596
+ */
1597
+ readonly count: number;
1598
+ /**
1599
+ * Reports whether an id names a compiled program.
1600
+ *
1601
+ * @param id - The program id to look for
1602
+ * @returns True if a compiled program carries the id; false otherwise
1603
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1604
+ * (`'DESTROYED'`).
1605
+ *
1606
+ * @example
1607
+ * ```ts
1608
+ * import { createProgramManager } from '@orkestrel/program'
1609
+ *
1610
+ * const manager = createProgramManager({ programs: [definition] })
1611
+ * manager.has('standard') // true
1612
+ * manager.destroy()
1613
+ * ```
1614
+ */
1615
+ has(id: string): boolean;
1616
+ /**
1617
+ * Looks one compiled program up by id.
1618
+ *
1619
+ * @param id - The program id to look up
1620
+ * @returns The compiled program, or `undefined` when no program carries the id
1621
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1622
+ * (`'DESTROYED'`).
1623
+ *
1624
+ * @example
1625
+ * ```ts
1626
+ * import { createProgramManager } from '@orkestrel/program'
1627
+ *
1628
+ * const manager = createProgramManager({ programs: [definition] })
1629
+ * manager.program('standard')?.execute({ id: 'risk-1', licensed: true })
1630
+ * manager.destroy()
1631
+ * ```
1632
+ */
1633
+ program(id: string): ProgramInterface | undefined;
1634
+ /**
1635
+ * Returns every compiled program, in insertion order.
1636
+ *
1637
+ * @remarks
1638
+ * The returned array is a fresh copy, so mutating it never reaches the manager's
1639
+ * own collection.
1640
+ *
1641
+ * @returns A fresh array of compiled programs, in insertion order
1642
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1643
+ * (`'DESTROYED'`).
1644
+ *
1645
+ * @example
1646
+ * ```ts
1647
+ * import { createProgramManager } from '@orkestrel/program'
1648
+ *
1649
+ * const manager = createProgramManager({ programs: [definition] })
1650
+ * manager.programs().map((program) => program.id) // ['standard']
1651
+ * manager.destroy()
1652
+ * ```
1653
+ */
1654
+ programs(): readonly ProgramInterface[];
1655
+ /**
1656
+ * Compiles one definition and appends it to the collection.
1657
+ *
1658
+ * @remarks
1659
+ * The compiled program borrows the manager's shared qualifier, rater, and reason
1660
+ * engine, and inherits the manager's `validate` and `labels` options. After
1661
+ * appending the program, the `add` event fires with its id.
1662
+ *
1663
+ * @param definition - The authored program definition to compile
1664
+ * @returns The compiled program
1665
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1666
+ * (`'DESTROYED'`).
1667
+ * @throws {@link ProgramError} Thrown when the manager already carries the
1668
+ * definition's id, or the definition repeats a rating-line or notice id
1669
+ * (`'DUPLICATE'`).
1670
+ * @throws {@link ProgramError} Thrown when a ruling or notice scope names no
1671
+ * rating line (`'MISSING'`).
1672
+ * @throws {@link ProgramError} Thrown when validation is enabled and the
1673
+ * definition fails (`'DEFINITION'`).
1674
+ *
1675
+ * @example
1676
+ * ```ts
1677
+ * import { createProgramManager } from '@orkestrel/program'
1678
+ *
1679
+ * const manager = createProgramManager()
1680
+ * manager.add(definition).id // 'standard'
1681
+ * manager.destroy()
1682
+ * ```
1683
+ */
1684
+ add(definition: ProgramDefinition): ProgramInterface;
1685
+ /**
1686
+ * Removes every listed id, destroying each removed program.
1687
+ *
1688
+ * @remarks
1689
+ * Every id is attempted, so one absent id does not stop the rest. Each removal
1690
+ * destroys its program and fires `remove` with that id. An empty list succeeds
1691
+ * vacuously.
1692
+ *
1693
+ * @param ids - The program ids to remove
1694
+ * @returns True if every listed id named a compiled program; false otherwise
1695
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1696
+ * (`'DESTROYED'`).
1697
+ *
1698
+ * @example
1699
+ * ```ts
1700
+ * import { createProgramManager } from '@orkestrel/program'
1701
+ *
1702
+ * const manager = createProgramManager({ programs: [definition] })
1703
+ * manager.remove(['standard', 'absent']) // false
1704
+ * manager.destroy()
1705
+ * ```
1706
+ */
1707
+ remove(ids: readonly string[]): boolean;
1708
+ /**
1709
+ * Removes one id, destroying the program it named.
1710
+ *
1711
+ * @param id - The program id to remove
1712
+ * @returns True if the id named a compiled program; false otherwise
1713
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1714
+ * (`'DESTROYED'`).
1715
+ *
1716
+ * @example
1717
+ * ```ts
1718
+ * import { createProgramManager } from '@orkestrel/program'
1719
+ *
1720
+ * const manager = createProgramManager({ programs: [definition] })
1721
+ * manager.remove('standard') // true
1722
+ * manager.destroy()
1723
+ * ```
1724
+ */
1725
+ remove(id: string): boolean;
1726
+ /**
1727
+ * Removes every compiled program, destroying each one.
1728
+ *
1729
+ * @remarks
1730
+ * Each removal fires `remove` with that program's id. The manager itself stays
1731
+ * usable, so a later `add` compiles into the drained collection.
1732
+ *
1733
+ * @throws {@link ProgramError} Thrown when the manager has been destroyed
1734
+ * (`'DESTROYED'`).
1735
+ *
1736
+ * @example
1737
+ * ```ts
1738
+ * import { createProgramManager } from '@orkestrel/program'
1739
+ *
1740
+ * const manager = createProgramManager({ programs: [definition] })
1741
+ * manager.remove()
1742
+ * manager.destroy()
1743
+ * ```
1744
+ */
1745
+ remove(): void;
1746
+ /**
1747
+ * Destroys this manager, idempotently.
1748
+ *
1749
+ * @remarks
1750
+ * The destroyed flag is set before any teardown or the `remove` and `destroy`
1751
+ * events, so a `remove` listener re-entering `destroy` is a no-op. Compiled
1752
+ * programs are destroyed first, then an owned qualifier, rater, and reason engine;
1753
+ * an injected one stays caller-owned. The emitter is torn down last, and stays
1754
+ * reachable afterwards.
1755
+ *
1756
+ * @example
1757
+ * ```ts
1758
+ * import { createProgramManager } from '@orkestrel/program'
1759
+ *
1760
+ * const manager = createProgramManager({ programs: [definition] })
1761
+ * manager.destroy()
1762
+ * manager.destroy() // a second call is a no-op
1763
+ * ```
1764
+ */
1765
+ destroy(): void;
1766
+ }
1767
+
1768
+ /**
1769
+ * Describes the options for `createProgramManager` / the `ProgramManager` constructor.
1770
+ *
1771
+ * @remarks
1772
+ * `qualifier` — an injected, caller-owned qualifier; created and owned when
1773
+ * omitted. `rater` — an injected, caller-owned rater; created and owned when
1774
+ * omitted. `engine` — an injected, caller-owned reason engine; created and
1775
+ * owned when omitted. `programs` — seed definitions compiled in order.
1776
+ * `validate` — if `true`, the manager validates each seeded and added
1777
+ * definition; if `false`, it compiles each definition unvalidated.
1778
+ * Default: {@link DEFAULT_PROGRAM_VALIDATE}. `labels` — field-to-label
1779
+ * overrides for determination premises, keyed by dot-joined field. `on` —
1780
+ * initial emitter hooks. `error` — the emitter's listener-error handler.
1781
+ */
1782
+ export declare interface ProgramManagerOptions {
1783
+ readonly qualifier?: QualifierInterface;
1784
+ readonly rater?: RaterInterface;
1785
+ readonly engine?: ReasonInterface;
1786
+ readonly programs?: readonly ProgramDefinition[];
1787
+ readonly validate?: boolean;
1788
+ readonly labels?: Readonly<Record<string, string>>;
1789
+ readonly on?: EmitterHooks<ProgramManagerEventMap>;
1790
+ readonly error?: EmitterErrorHandler;
1791
+ }
1792
+
1793
+ /**
1794
+ * Describes the options for `createProgram` / the `Program` constructor.
1795
+ *
1796
+ * @remarks
1797
+ * `qualifier` — an injected, caller-owned qualifier; created and owned by the
1798
+ * program when omitted. `rater` — an injected, caller-owned rater; created and
1799
+ * owned when omitted. `engine` — an injected, caller-owned reason engine;
1800
+ * created and owned when omitted. `validate` — if `true`, the program validates
1801
+ * the definition at construction; if `false`, it compiles the definition
1802
+ * unvalidated. Default: {@link DEFAULT_PROGRAM_VALIDATE}. `labels` —
1803
+ * field-to-label overrides for determination premises, keyed by dot-joined
1804
+ * field. `on` — initial emitter hooks. `error` — the emitter's listener-error
1805
+ * handler.
1806
+ */
1807
+ export declare interface ProgramOptions {
1808
+ readonly qualifier?: QualifierInterface;
1809
+ readonly rater?: RaterInterface;
1810
+ readonly engine?: ReasonInterface;
1811
+ readonly validate?: boolean;
1812
+ readonly labels?: Readonly<Record<string, string>>;
1813
+ readonly on?: EmitterHooks<ProgramEventMap>;
1814
+ readonly error?: EmitterErrorHandler;
1815
+ }
1816
+
1817
+ /** Describes one subject's complete program outcome. */
1818
+ export declare interface ProgramResult {
1819
+ readonly id: string;
1820
+ readonly name: string;
1821
+ readonly eligibility: Eligibility;
1822
+ readonly status: Status;
1823
+ /**
1824
+ * Holds the final authority outcome.
1825
+ *
1826
+ * @remarks
1827
+ * Present only when the program has an `authority`, the execution succeeded
1828
+ * (qualification, rating when it ran, and authority all produced no errors),
1829
+ * no `limit` determination applied, and status is not `unrated`.
1830
+ */
1831
+ readonly decision?: Decision;
1832
+ readonly qualification: QualificationResult;
1833
+ readonly rating?: RatingResult;
1834
+ readonly determinations: readonly Determination[];
1835
+ readonly success: boolean;
1836
+ readonly trace: readonly string[];
1837
+ readonly errors: readonly string[];
1838
+ }
1839
+
1840
+ /** Describes semantic definition validation. */
1841
+ export declare interface ProgramValidationResult {
1842
+ readonly valid: boolean;
1843
+ readonly errors: readonly string[];
1844
+ readonly warnings: readonly string[];
1845
+ }
1846
+
1847
+ /**
1848
+ * Selects the rating lines a subject may be rated on from scoped eligibility.
1849
+ *
1850
+ * @remarks
1851
+ * A scope names a rating-line id. A line survives when its scope is absent
1852
+ * (eligible by default), `eligible`, or a `condition` (which is not an
1853
+ * eligibility value and never appears here). A scoped `ineligible` or `referral`
1854
+ * removes the line before the rater is invoked — the excluded line is never
1855
+ * evaluated merely to discard its amount.
1856
+ *
1857
+ * @param lines - The program's authored rating lines
1858
+ * @param scopes - The qualification's per-scope eligibility
1859
+ * @returns The surviving line definitions, in authored order
1860
+ *
1861
+ * @example
1862
+ * ```ts
1863
+ * import { selectProgramLines } from '@orkestrel/program'
1864
+ *
1865
+ * selectProgramLines(lines, { wind: 'ineligible' }) // every line except 'wind'
1866
+ * ```
1867
+ */
1868
+ export declare function selectProgramLines(lines: readonly LineDefinition[], scopes: Readonly<Record<string, Eligibility>>): readonly LineDefinition[];
1869
+
1870
+ /** Identifies the presentation and tally status derived from eligibility, conditions, and rating success. */
1871
+ export declare type Status = (typeof STATUSES)[number];
1872
+
1873
+ /**
1874
+ * Lists every {@link Status} literal in tally order — the source the union and its
1875
+ * guard derive from.
1876
+ */
1877
+ export declare const STATUSES: readonly ["ineligible", "referral", "conditional", "unrated", "eligible"];
1878
+
1879
+ /**
1880
+ * Folds one subject's finite aggregate field values into a sums record.
1881
+ *
1882
+ * @remarks
1883
+ * Returns a fresh record — `sums` is never mutated. Only finite numbers
1884
+ * contribute; a non-numeric or absent value contributes zero (never a
1885
+ * coercion). A {@link FieldPath} may be nested — `formatField` renders the
1886
+ * dot-joined key the returned record is keyed by.
1887
+ *
1888
+ * @param sums - The sums record to fold into
1889
+ * @param subject - The subject to fold in
1890
+ * @param fields - The fields to sum
1891
+ * @returns A fresh sums record with `subject`'s contribution added
1892
+ *
1893
+ * @example
1894
+ * ```ts
1895
+ * import { sumFields } from '@orkestrel/program'
1896
+ *
1897
+ * sumFields({ amount: 0 }, { amount: 5 }, ['amount']) // { amount: 5 }
1898
+ * ```
1899
+ */
1900
+ export declare function sumFields(sums: Readonly<Record<string, number>>, subject: Subject, fields: readonly FieldPath[]): Readonly<Record<string, number>>;
1901
+
1902
+ /** Describes a status tally — a count plus summed aggregate fields. */
1903
+ export declare interface Tally {
1904
+ readonly count: number;
1905
+ readonly sums: Readonly<Record<string, number>>;
1906
+ }
1907
+
1908
+ /**
1909
+ * Adds one subject's aggregate contribution to a status tally record.
1910
+ *
1911
+ * @param tallies - The tallies to update
1912
+ * @param result - The subject's program result (its `status` selects the tally)
1913
+ * @param subject - The subject to fold in
1914
+ * @param fields - The fields to sum
1915
+ * @returns A fresh, complete tally record with the subject folded in
1916
+ *
1917
+ * @example
1918
+ * ```ts
1919
+ * import { tallySubject } from '@orkestrel/program'
1920
+ *
1921
+ * tallySubject(tallies, result, { id: 'r1', amount: 5 }, ['amount'])
1922
+ * ```
1923
+ */
1924
+ export declare function tallySubject(tallies: Readonly<Record<Status, Tally>>, result: ProgramResult, subject: Subject, fields: readonly FieldPath[]): Readonly<Record<Status, Tally>>;
1925
+
1926
+ /**
1927
+ * Validates a program definition's shape, references, and nested definitions.
1928
+ *
1929
+ * @remarks
1930
+ * The single semantic-validation implementation used by `Program.validate`. It
1931
+ * establishes exact shape through {@link isProgramDefinition}, validates the
1932
+ * rating structurally through the rater's {@link isRatingDefinition} guard (the
1933
+ * rater exposes no `validate`), delegates qualification validation to the
1934
+ * injected qualifier and authority / aggregate-gate validation to the shared
1935
+ * reason engine, and checks scope, notice, and aggregate-field references here.
1936
+ *
1937
+ * @param definition - The program definition to validate
1938
+ * @param qualifier - The qualifier that validates the nested qualification
1939
+ * @param engine - The reason engine that validates authority and aggregate gates
1940
+ * @returns A structured validation result
1941
+ *
1942
+ * @example
1943
+ * ```ts
1944
+ * import { validateProgramDefinition } from '@orkestrel/program'
1945
+ *
1946
+ * validateProgramDefinition(definition, qualifier, engine) // { valid: true, ... }
1947
+ * ```
1948
+ */
1949
+ export declare function validateProgramDefinition(definition: ProgramDefinition, qualifier: QualifierInterface, engine: ReasonInterface): ProgramValidationResult;
1950
+
1951
+ export { }