@orkestrel/program 0.0.11 → 0.0.12

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