@orkestrel/reason 0.0.1

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.
@@ -0,0 +1,4852 @@
1
+ import { EmitterErrorHandler } from '@orkestrel/emitter';
2
+ import { EmitterHooks } from '@orkestrel/emitter';
3
+ import { EmitterInterface } from '@orkestrel/emitter';
4
+ import { FieldPath } from '@orkestrel/contract';
5
+ import { Guard } from '@orkestrel/contract';
6
+
7
+ /**
8
+ * Upsert one entry of a {@link SymbolicDefinition}'s `variables`.
9
+ *
10
+ * @remarks
11
+ * `variables` is a name-keyed unordered record, so `add`/`remove` (no
12
+ * placement) are the correct verbs — mirrored by {@link removeVariable}.
13
+ *
14
+ * @param definition - The definition to update
15
+ * @param name - The variable name
16
+ * @param value - The variable's value
17
+ * @returns A fresh definition with the variable set
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { addVariable, symbolicDefinition } from '@src/core'
22
+ *
23
+ * addVariable(symbolicDefinition('e', 'E', []), 'x', 5).variables // { x: 5 }
24
+ * ```
25
+ */
26
+ export declare function addVariable(definition: SymbolicDefinition, name: string, value: number): SymbolicDefinition;
27
+
28
+ /**
29
+ * How the {@link AggregatorInterface} reduces a list of numbers to one.
30
+ *
31
+ * @remarks
32
+ * When weights apply: `sum` multiplies each value by its weight, `product`
33
+ * raises each value to its weight (weight-as-exponent), `average` is the
34
+ * weighted mean, and `minimum` / `maximum` ignore weights entirely.
35
+ */
36
+ export declare type Aggregation = 'sum' | 'product' | 'average' | 'minimum' | 'maximum';
37
+
38
+ /**
39
+ * Reduces number lists to one number per {@link Aggregation} — the quantitative
40
+ * reasoner's group and definition combiner.
41
+ *
42
+ * @remarks
43
+ * TOTAL: never throws. Empty-input identities: `sum` / `average` → `0`,
44
+ * `product` → `1`, `minimum` / `maximum` → `NaN` (the deliberate "no data"
45
+ * signal). Weights are honored ONLY when their length matches `values` exactly
46
+ * (otherwise silently unweighted): a weight multiplies into a `sum`, acts as an
47
+ * EXPONENT for a `product`, is the weight of a weighted mean for `average`
48
+ * (a zero total weight yields `0`, never a division blow-up), and is ignored by
49
+ * `minimum` / `maximum`. An unknown aggregation yields `0`. Stateless and
50
+ * deterministic.
51
+ */
52
+ export declare class Aggregator implements AggregatorInterface {
53
+ #private;
54
+ constructor(options?: AggregatorOptions);
55
+ get id(): string;
56
+ aggregate(values: readonly number[], aggregation: Aggregation, weights?: readonly number[]): number;
57
+ }
58
+
59
+ /** Default `id` for an `Aggregator`. */
60
+ export declare const AGGREGATOR_ID = "aggregator";
61
+
62
+ /**
63
+ * Reduces number lists to one number per {@link Aggregation}.
64
+ *
65
+ * @remarks
66
+ * Total: never throws. Empty-input identities: `sum` / `average` → `0`,
67
+ * `product` → `1`, `minimum` / `maximum` → `NaN`. `weights` are honored ONLY
68
+ * when their length matches `values` exactly (otherwise silently unweighted).
69
+ */
70
+ export declare interface AggregatorInterface {
71
+ readonly id: string;
72
+ aggregate(values: readonly number[], aggregation: Aggregation, weights?: readonly number[]): number;
73
+ }
74
+
75
+ /**
76
+ * Options for `createAggregator` / the `Aggregator` constructor.
77
+ *
78
+ * @remarks
79
+ * `id` — the aggregator's identity string (defaults to `AGGREGATOR_ID`).
80
+ */
81
+ export declare interface AggregatorOptions {
82
+ readonly id?: string;
83
+ }
84
+
85
+ /**
86
+ * Insert `item` into an id-keyed collection, deduping any existing element
87
+ * sharing its id, then placing it at the END (or immediately AFTER `target`).
88
+ *
89
+ * @remarks
90
+ * `filtered` is `items` with every `item.id` twin removed FIRST (dedup-on-
91
+ * insert — input arrays may already carry same-id twins per PROPOSAL.md §7).
92
+ * Re-appending an existing id therefore REPOSITIONS it rather than updating it
93
+ * in place — {@link replaceById} is the position-preserving alternative. With
94
+ * no `target`, `item` lands at the end; with a `target`, it lands immediately
95
+ * after the element whose `id === target` (searched in the DEDUPED array). A
96
+ * `target` naming no element throws {@link ReasonError} (`'TARGET'`).
97
+ *
98
+ * @typeParam T - An id-carrying element type
99
+ * @param items - The collection to insert into
100
+ * @param item - The element to insert
101
+ * @param target - Optional id to insert immediately after; appends at the end when absent
102
+ * @returns A fresh array with `item` inserted
103
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no element in `items`
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * import { appendById } from '@src/core'
108
+ *
109
+ * appendById([{ id: 'a' }, { id: 'b' }], { id: 'c' }) // [a, b, c]
110
+ * appendById([{ id: 'a' }, { id: 'b' }], { id: 'c' }, 'a') // [a, c, b]
111
+ * ```
112
+ */
113
+ export declare function appendById<T extends {
114
+ readonly id: string;
115
+ }>(items: readonly T[], item: T, target?: string): readonly T[];
116
+
117
+ /**
118
+ * Insert `equation` into a {@link SymbolicDefinition}'s `equations` — dedup-
119
+ * then-insert at the end, or immediately after `target`.
120
+ *
121
+ * @remarks
122
+ * Order is STRONGLY load-bearing: equations solve strictly in order and each
123
+ * rounded solution feeds forward.
124
+ *
125
+ * @param definition - The definition to insert into
126
+ * @param source - The equation to insert
127
+ * @param target - Optional equation id to insert immediately after
128
+ * @returns A fresh definition with `equation` inserted
129
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing equation
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * import { appendEquation, constant, equation, symbolicDefinition, variable } from '@src/core'
134
+ *
135
+ * appendEquation(symbolicDefinition('e', 'E', []), equation('e1', variable('x'), constant(1), 'x'))
136
+ * ```
137
+ */
138
+ export declare function appendEquation(definition: SymbolicDefinition, source: Equation, target?: string): SymbolicDefinition;
139
+
140
+ /**
141
+ * Insert `fact` into an {@link InferentialDefinition}'s `facts` — dedup-then-
142
+ * insert at the end, or immediately after `target`.
143
+ *
144
+ * @remarks
145
+ * `Fact.id` is an AUTHORING label — the runtime content-dedups facts by
146
+ * predicate+arity+terms ({@link factToKey}), independently of this helper's
147
+ * id-keyed dedup.
148
+ *
149
+ * @param definition - The definition to insert into
150
+ * @param source - The fact to insert
151
+ * @param target - Optional fact id to insert immediately after
152
+ * @returns A fresh definition with `fact` inserted
153
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing fact
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * import { appendFact, fact, inferentialDefinition } from '@src/core'
158
+ *
159
+ * appendFact(inferentialDefinition('m', 'M', [], []), fact('f1', 'human', ['socrates']))
160
+ * ```
161
+ */
162
+ export declare function appendFact(definition: InferentialDefinition, source: Fact, target?: string): InferentialDefinition;
163
+
164
+ /**
165
+ * Insert `factor` into a {@link FactorGroup}'s `factors` — dedup-then-insert
166
+ * at the end, or immediately after `target`.
167
+ *
168
+ * @remarks
169
+ * Factor order is LOAD-BEARING: the same-priority tiebreak is declaration
170
+ * order ({@link sortByPriority} is a stable ascending sort). Operates on the
171
+ * factor's DIRECT container — compose into a definition via
172
+ * `appendGroup(def, appendFactor(group, factor))`.
173
+ *
174
+ * @param group - The group to insert into
175
+ * @param factor - The factor to insert
176
+ * @param target - Optional factor id to insert immediately after
177
+ * @returns A fresh group with `factor` inserted
178
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing factor
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * import { appendFactor, factorGroup, staticFactor } from '@src/core'
183
+ *
184
+ * appendFactor(factorGroup('g1', 'sum', []), staticFactor('f1', 10))
185
+ * ```
186
+ */
187
+ export declare function appendFactor(group: FactorGroup, factor: Factor, target?: string): FactorGroup;
188
+
189
+ /**
190
+ * Insert `group` into a {@link QuantitativeDefinition}'s `groups` — dedup-then-
191
+ * insert at the end, or immediately after `target`.
192
+ *
193
+ * @remarks
194
+ * Group order is COSMETIC (group aggregation is order-independent) but honored
195
+ * uniformly, same as every `append*` helper. Composes with {@link appendFactor}:
196
+ * `appendGroup(def, appendFactor(group, factor))`.
197
+ *
198
+ * @param definition - The definition to insert into
199
+ * @param group - The group to insert
200
+ * @param target - Optional group id to insert immediately after
201
+ * @returns A fresh definition with `group` inserted
202
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing group
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * import { appendGroup, factorGroup, quantitativeDefinition } from '@src/core'
207
+ *
208
+ * appendGroup(quantitativeDefinition('risk', 'Risk', []), factorGroup('g1', 'sum', []))
209
+ * ```
210
+ */
211
+ export declare function appendGroup(definition: QuantitativeDefinition, group: FactorGroup, target?: string): QuantitativeDefinition;
212
+
213
+ /**
214
+ * Insert `inference` into an {@link InferentialDefinition}'s `inferences` —
215
+ * dedup-then-insert at the end, or immediately after `target`.
216
+ *
217
+ * @remarks
218
+ * Order is LOAD-BEARING: backward proving iterates in declaration order and
219
+ * returns on first success.
220
+ *
221
+ * @param definition - The definition to insert into
222
+ * @param source - The inference to insert
223
+ * @param target - Optional inference id to insert immediately after
224
+ * @returns A fresh definition with `inference` inserted
225
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing inference
226
+ *
227
+ * @example
228
+ * ```ts
229
+ * import { appendInference, fact, inference, inferentialDefinition } from '@src/core'
230
+ *
231
+ * appendInference(
232
+ * inferentialDefinition('m', 'M', [], []),
233
+ * inference('i1', [fact('p', 'human', ['?x'])], fact('c', 'mortal', ['?x'])),
234
+ * )
235
+ * ```
236
+ */
237
+ export declare function appendInference(definition: InferentialDefinition, source: Inference, target?: string): InferentialDefinition;
238
+
239
+ /**
240
+ * Insert `rule` into a {@link LogicalDefinition}'s `rules` — dedup-then-insert
241
+ * at the end, or immediately after `target`.
242
+ *
243
+ * @remarks
244
+ * Order is LOAD-BEARING: the forward conclusion is the LAST declared
245
+ * non-disabled rule, so `appendRule` without a `target` makes the new rule the
246
+ * conclusion.
247
+ *
248
+ * @param definition - The definition to insert into
249
+ * @param source - The rule to insert
250
+ * @param target - Optional rule id to insert immediately after
251
+ * @returns A fresh definition with `rule` inserted
252
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing rule
253
+ *
254
+ * @example
255
+ * ```ts
256
+ * import { appendRule, atom, logicalDefinition, rule } from '@src/core'
257
+ *
258
+ * appendRule(logicalDefinition('e', 'E', []), rule('r1', [], atom('a', 'equals', true)))
259
+ * ```
260
+ */
261
+ export declare function appendRule(definition: LogicalDefinition, source: Rule, target?: string): LogicalDefinition;
262
+
263
+ /**
264
+ * Apply one binary/unary math operation to already-evaluated operands.
265
+ *
266
+ * @remarks
267
+ * The arithmetic core of the symbolic reasoner's expression evaluation: the full
268
+ * {@link MathOperation} vocabulary plus its zero / unary conventions — `divide`
269
+ * by zero is `NaN` (never a throw), the unary operations (`round` / `ceil` /
270
+ * `floor` / `abs`) ignore `right`, and `percentage` is `left * (right / 100)`.
271
+ * `operator` is typed `string` because untrusted definitions reach here
272
+ * unchecked; the ONE throwing path is the unknown-operator default (caught per
273
+ * equation upstream).
274
+ *
275
+ * @param operator - The operation name (untrusted — an unknown one throws)
276
+ * @param left - The left operand
277
+ * @param right - The right operand (ignored by the unary operations)
278
+ * @returns The operation's result (`NaN` on divide-by-zero)
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * import { applyOperation } from '@src/core'
283
+ *
284
+ * applyOperation('add', 2, 3) // 5
285
+ * applyOperation('divide', 1, 0) // NaN
286
+ * ```
287
+ */
288
+ export declare function applyOperation(operator: string, left: number, right: number): number;
289
+
290
+ /**
291
+ * Upsert one field of a {@link Subject} — copy-on-write spread.
292
+ *
293
+ * @remarks
294
+ * Id-agnostic: overwrites an `id` key like any other field — id protection is
295
+ * an entity's job, not this helper's.
296
+ *
297
+ * @param subject - The subject to update
298
+ * @param key - The field to set
299
+ * @param value - The value to set it to
300
+ * @returns A fresh subject with `key` set to `value`
301
+ *
302
+ * @example
303
+ * ```ts
304
+ * import { assignField } from '@src/core'
305
+ *
306
+ * assignField({ id: 's1', age: 30 }, 'age', 31) // { id: 's1', age: 31 }
307
+ * ```
308
+ */
309
+ export declare function assignField(subject: Subject, key: string, value: unknown): Subject;
310
+
311
+ /** A leaf boolean expression — one {@link Check} against the subject. */
312
+ export declare interface Atom {
313
+ readonly form: 'atom';
314
+ readonly check: Check;
315
+ }
316
+
317
+ /**
318
+ * Build an atom {@link Expression} — a leaf wrapping one {@link Check}.
319
+ *
320
+ * @param field - The subject field to resolve
321
+ * @param operator - The comparison to apply
322
+ * @param value - The expected value
323
+ * @returns A fresh atom expression
324
+ *
325
+ * @example
326
+ * ```ts
327
+ * import { atom } from '@src/core'
328
+ *
329
+ * atom('age', 'from', 18) // { form: 'atom', check: { field: 'age', operator: 'from', value: 18 } }
330
+ * ```
331
+ */
332
+ export declare function atom(field: FieldPath, operator: Comparison, value: unknown): Expression;
333
+
334
+ /**
335
+ * An inclusive numeric clamp — either side may be absent (unbounded).
336
+ */
337
+ export declare interface Bounds {
338
+ readonly minimum?: number;
339
+ readonly maximum?: number;
340
+ }
341
+
342
+ /**
343
+ * Build a {@link Bounds} — an inclusive numeric clamp.
344
+ *
345
+ * @remarks
346
+ * Absent sides are OMITTED (never set to `undefined`) — an absent bound is
347
+ * unbounded on that side.
348
+ *
349
+ * @param minimum - The inclusive lower bound
350
+ * @param maximum - The inclusive upper bound
351
+ * @returns A fresh bounds record
352
+ *
353
+ * @example
354
+ * ```ts
355
+ * import { bounds } from '@src/core'
356
+ *
357
+ * bounds(0, 100) // { minimum: 0, maximum: 100 }
358
+ * bounds(undefined, 100) // { maximum: 100 }
359
+ * ```
360
+ */
361
+ export declare function bounds(minimum?: number, maximum?: number): Bounds;
362
+
363
+ /**
364
+ * Build the empty, type-shaped failure {@link ReasonResult} matching a
365
+ * definition's reasoning.
366
+ *
367
+ * @remarks
368
+ * The `bail: false` fallback of the `Reason` orchestrator: when a reasoner
369
+ * throws and bail is off, the throw becomes an empty failure result carrying the
370
+ * message as its sole `errors` entry. Each reasoning gets its own zero-valued
371
+ * shape (`quantitative` → `value: 0` / empty `groups`; `logical` → `conclusion:
372
+ * false` / empty `rules`; `symbolic` → empty `solutions`; `inferential` → empty
373
+ * `derived`), always with `success: false` and an empty `trace`.
374
+ *
375
+ * @param definition - The definition whose reasoning selects the result shape
376
+ * @param message - The error message to carry as the result's sole `errors` entry
377
+ * @returns A fresh failure result of the matching reasoning
378
+ *
379
+ * @example
380
+ * ```ts
381
+ * import { buildErrorResult, logicalDefinition } from '@src/core'
382
+ *
383
+ * const result = buildErrorResult(logicalDefinition('e', 'E', []), 'boom')
384
+ * // { reasoning: 'logical', conclusion: false, rules: [], count: 0, success: false, trace: [], errors: ['boom'] }
385
+ * ```
386
+ */
387
+ export declare function buildErrorResult(definition: Definition, message: string): ReasonResult;
388
+
389
+ /**
390
+ * How a chaining reasoner walks its rules: `forward` (data-driven fixpoint) or
391
+ * `backward` (goal-driven proving).
392
+ */
393
+ export declare type ChainingStrategy = 'forward' | 'backward';
394
+
395
+ /**
396
+ * A single field predicate: resolve `field` from the subject and compare it to
397
+ * `value` with `operator`.
398
+ *
399
+ * @remarks
400
+ * `field` follows the {@link FieldPath} idiom — a string is ONE key (never
401
+ * dot-split), an array descends into nested objects. `value` is unconstrained
402
+ * (`unknown`): the operator decides what shapes are meaningful.
403
+ */
404
+ export declare interface Check {
405
+ readonly field: FieldPath;
406
+ readonly operator: Comparison;
407
+ readonly value: unknown;
408
+ }
409
+
410
+ /**
411
+ * Build a {@link Check} — one field predicate.
412
+ *
413
+ * @param field - The subject field to resolve (a string is ONE key; an array descends)
414
+ * @param operator - The comparison to apply
415
+ * @param value - The expected value (any type — the operator decides what is meaningful)
416
+ * @returns A fresh check
417
+ *
418
+ * @example
419
+ * ```ts
420
+ * import { check } from '@src/core'
421
+ *
422
+ * check('age', 'from', 18) // { field: 'age', operator: 'from', value: 18 }
423
+ * ```
424
+ */
425
+ export declare function check(field: FieldPath, operator: Comparison, value: unknown): Check;
426
+
427
+ /**
428
+ * The outcome of one {@link Check} evaluation.
429
+ *
430
+ * @remarks
431
+ * `actual` is the resolved subject value (possibly `undefined`); `error` is set
432
+ * ONLY when evaluation itself failed (an unknown operator) — a merely-unmet
433
+ * check carries no `error`.
434
+ */
435
+ export declare interface CheckResult {
436
+ readonly field: FieldPath;
437
+ readonly met: boolean;
438
+ readonly actual: unknown;
439
+ readonly error?: string;
440
+ }
441
+
442
+ /**
443
+ * Clamp a number to inclusive {@link Bounds}.
444
+ *
445
+ * @remarks
446
+ * An absent bound (or absent `bounds` entirely) never constrains that side.
447
+ * `NaN` flows through unchanged (every comparison with `NaN` is false).
448
+ *
449
+ * @param value - The number to clamp
450
+ * @param limit - The inclusive bounds (either side optional)
451
+ * @returns The clamped number
452
+ *
453
+ * @example
454
+ * ```ts
455
+ * import { clamp } from '@src/core'
456
+ *
457
+ * clamp(150, { minimum: 0, maximum: 100 }) // 100
458
+ * clamp(150) // 150 — unbounded
459
+ * ```
460
+ */
461
+ export declare function clamp(value: number, limit?: Bounds): number;
462
+
463
+ /**
464
+ * Delete one optional field of an {@link InferentialDefinition}.
465
+ *
466
+ * @param definition - The definition to update
467
+ * @param key - The optional field to clear
468
+ * @returns A fresh definition with `key` omitted
469
+ *
470
+ * @example
471
+ * ```ts
472
+ * import { clearInferentialDefinition, inferentialDefinition } from '@src/core'
473
+ *
474
+ * const definition = inferentialDefinition('m', 'M', [], [], { depth: 5 })
475
+ * 'depth' in clearInferentialDefinition(definition, 'depth') // false
476
+ * ```
477
+ */
478
+ export declare function clearInferentialDefinition(definition: InferentialDefinition, key: 'description' | 'depth'): InferentialDefinition;
479
+
480
+ /**
481
+ * Delete one optional field of a {@link LogicalDefinition}.
482
+ *
483
+ * @param definition - The definition to update
484
+ * @param key - The optional field to clear
485
+ * @returns A fresh definition with `key` omitted
486
+ *
487
+ * @example
488
+ * ```ts
489
+ * import { clearLogicalDefinition, logicalDefinition } from '@src/core'
490
+ *
491
+ * const definition = logicalDefinition('e', 'E', [], { depth: 5 })
492
+ * 'depth' in clearLogicalDefinition(definition, 'depth') // false
493
+ * ```
494
+ */
495
+ export declare function clearLogicalDefinition(definition: LogicalDefinition, key: 'description' | 'depth'): LogicalDefinition;
496
+
497
+ /**
498
+ * Delete one optional field of a {@link QuantitativeDefinition}.
499
+ *
500
+ * @param definition - The definition to update
501
+ * @param key - The optional field to clear
502
+ * @returns A fresh definition with `key` omitted
503
+ *
504
+ * @example
505
+ * ```ts
506
+ * import { clearQuantitativeDefinition, quantitativeDefinition } from '@src/core'
507
+ *
508
+ * const definition = quantitativeDefinition('risk', 'Risk', [], { precision: 2 })
509
+ * 'precision' in clearQuantitativeDefinition(definition, 'precision') // false
510
+ * ```
511
+ */
512
+ export declare function clearQuantitativeDefinition(definition: QuantitativeDefinition, key: 'description' | 'base' | 'bounds' | 'precision'): QuantitativeDefinition;
513
+
514
+ /**
515
+ * Delete one optional field of a {@link SymbolicDefinition}.
516
+ *
517
+ * @param definition - The definition to update
518
+ * @param key - The optional field to clear
519
+ * @returns A fresh definition with `key` omitted
520
+ *
521
+ * @example
522
+ * ```ts
523
+ * import { clearSymbolicDefinition, symbolicDefinition } from '@src/core'
524
+ *
525
+ * const definition = symbolicDefinition('e', 'E', [], { precision: 2 })
526
+ * 'precision' in clearSymbolicDefinition(definition, 'precision') // false
527
+ * ```
528
+ */
529
+ export declare function clearSymbolicDefinition(definition: SymbolicDefinition, key: 'description' | 'precision'): SymbolicDefinition;
530
+
531
+ /**
532
+ * The comparison a {@link Check} applies between a resolved subject field and
533
+ * its expected value.
534
+ *
535
+ * @remarks
536
+ * `equals` / `not` — strict `===` / `!==` (no coercion). `above` / `below` /
537
+ * `from` / `to` — `>` / `<` / `>=` / `<=`, requiring numbers on BOTH sides
538
+ * (anything else is not met). `any` / `none` — array membership / non-membership
539
+ * (a non-array expected value is not met for BOTH — `none` is not the raw
540
+ * complement of `any` on malformed input). `between` / `outside` — inclusive
541
+ * range test on the first two numeric elements of the expected array; `outside`
542
+ * IS the pure negation of `between`, so a malformed range is `outside`.
543
+ */
544
+ export declare type Comparison = 'equals' | 'not' | 'above' | 'below' | 'from' | 'to' | 'any' | 'none' | 'between' | 'outside';
545
+
546
+ /** A compound boolean expression — a {@link LogicalOperator} over nested operands. */
547
+ export declare interface Compound {
548
+ readonly form: 'compound';
549
+ readonly operator: LogicalOperator;
550
+ readonly operands: readonly Expression[];
551
+ }
552
+
553
+ /**
554
+ * Build a compound {@link Expression} — a logical connective over nested
555
+ * operands.
556
+ *
557
+ * @param operator - The logical connective
558
+ * @param operands - The nested expressions it combines
559
+ * @returns A fresh compound expression
560
+ *
561
+ * @example
562
+ * ```ts
563
+ * import { atom, compound } from '@src/core'
564
+ *
565
+ * compound('and', [atom('age', 'from', 18), atom('state', 'equals', 'CA')])
566
+ * ```
567
+ */
568
+ export declare function compound(operator: LogicalOperator, operands: readonly Expression[]): Expression;
569
+
570
+ /**
571
+ * Decimal places a derived fact's confidence is rounded to during forward
572
+ * inferential chaining.
573
+ *
574
+ * @remarks
575
+ * Fixed — unlike {@link DEFAULT_PRECISION} it is NOT overridable per
576
+ * definition, so confidence products stay comparable across derivations.
577
+ */
578
+ export declare const CONFIDENCE_PRECISION = 4;
579
+
580
+ /** A symbolic expression leaf holding a fixed number. */
581
+ export declare interface Constant {
582
+ readonly form: 'constant';
583
+ readonly value: number;
584
+ }
585
+
586
+ /**
587
+ * Build a constant {@link SymbolicExpression} leaf.
588
+ *
589
+ * @param value - The fixed number
590
+ * @returns A fresh constant node
591
+ *
592
+ * @example
593
+ * ```ts
594
+ * import { constant } from '@src/core'
595
+ *
596
+ * constant(42) // { form: 'constant', value: 42 }
597
+ * ```
598
+ */
599
+ export declare function constant(value: number): SymbolicExpression;
600
+
601
+ /**
602
+ * Determine whether a symbolic expression contains an UNBOUND occurrence of a
603
+ * target variable.
604
+ *
605
+ * @remarks
606
+ * The variable-presence probe of the symbolic reasoner's isolation: a `variable`
607
+ * node matches only when its name is `target` AND `target` is not already in
608
+ * `bindings` (a pre-bound target is a known value, not an unknown to isolate); a
609
+ * `constant` never matches; an `operation` recurses into both operands (the
610
+ * `right` operand may be absent on a unary node). The walk is an ITERATIVE
611
+ * worklist (never recursive) with short-circuit `true` on the first hit, so it
612
+ * stays total on pathologically deep expression trees.
613
+ *
614
+ * @param expression - The expression to probe
615
+ * @param target - The variable name being sought
616
+ * @param bindings - The known bindings (a bound target does NOT count as present)
617
+ * @returns `true` when an unbound `target` occurs in the expression
618
+ *
619
+ * @example
620
+ * ```ts
621
+ * import { containsVariable, operation, variable, constant } from '@src/core'
622
+ *
623
+ * containsVariable(operation('add', variable('x'), constant(1)), 'x', {}) // true
624
+ * containsVariable(operation('add', variable('x'), constant(1)), 'x', { x: 5 }) // false — pre-bound
625
+ * ```
626
+ */
627
+ export declare function containsVariable(expression: SymbolicExpression, target: string, bindings: Record<string, number>): boolean;
628
+
629
+ /**
630
+ * Create a number aggregator.
631
+ *
632
+ * @remarks
633
+ * `id` — the aggregator's identity string (defaults to `'aggregator'`).
634
+ *
635
+ * @param options - Optional `id`
636
+ * @returns A stateless {@link AggregatorInterface}
637
+ *
638
+ * @example
639
+ * ```ts
640
+ * import { createAggregator } from '@src/core'
641
+ *
642
+ * const aggregator = createAggregator()
643
+ * aggregator.aggregate([10, 20], 'average', [1, 3]) // 17.5 — weighted mean
644
+ * ```
645
+ */
646
+ export declare function createAggregator(options?: AggregatorOptions): AggregatorInterface;
647
+
648
+ /**
649
+ * Create a `DefinitionBuilder` — a stateful workspace builder accumulating a
650
+ * {@link Definition} through seven self-owning manager properties.
651
+ *
652
+ * @remarks
653
+ * `id` defaults to `seed.id`. Each manager slot is BRING-YOUR-OWN (a supplied
654
+ * one is reused, else a fresh one is seeded from the seed's matching
655
+ * collection). `on` — initial event listeners (AGENTS §8). `error` — the
656
+ * emitter's listener-error handler (AGENTS §13). Mutate through the manager
657
+ * properties (`groups` / `factors` / `rules` / `equations` / `variables` /
658
+ * `facts` / `inferences`) and `merge` / `clear`, then call `build()` to produce
659
+ * a fresh, plain {@link Definition} snapshot.
660
+ *
661
+ * @param seed - The starting definition (any of the four reasoning kinds)
662
+ * @param options - Optional `id` override, manager injections, and emitter hooks
663
+ * @returns A {@link DefinitionBuilderInterface}
664
+ *
665
+ * @example
666
+ * ```ts
667
+ * import { createDefinitionBuilder, quantitativeDefinition } from '@src/core'
668
+ *
669
+ * const definition = createDefinitionBuilder(quantitativeDefinition('risk', 'Risk', []))
670
+ * definition.groups.append({ id: 'g1', name: 'g1', aggregation: 'sum', factors: [] })
671
+ * definition.build() // a fresh QuantitativeDefinition with the group applied
672
+ * definition.destroy()
673
+ * ```
674
+ */
675
+ export declare function createDefinitionBuilder(seed: Definition, options?: DefinitionBuilderOptions): DefinitionBuilderInterface;
676
+
677
+ /**
678
+ * Create an `EquationManager` — a self-owning manager over a symbolic
679
+ * definition's `equations`.
680
+ *
681
+ * @remarks
682
+ * `equations` — the initial collection (defaults to empty). `on` / `error` —
683
+ * emitter hooks (AGENTS §8 / §13). Equation order is strongly load-bearing.
684
+ *
685
+ * @param options - Optional seed collection and emitter hooks
686
+ * @returns An {@link EquationManagerInterface}
687
+ *
688
+ * @example
689
+ * ```ts
690
+ * import { constant, createEquationManager, equation, variable } from '@src/core'
691
+ *
692
+ * const equations = createEquationManager()
693
+ * equations.append(equation('e1', variable('y'), constant(2), 'y'))
694
+ * ```
695
+ */
696
+ export declare function createEquationManager(options?: EquationManagerOptions): EquationManagerInterface;
697
+
698
+ /**
699
+ * Create a check evaluator.
700
+ *
701
+ * @remarks
702
+ * `id` — the evaluator's identity string (defaults to `'evaluator'`).
703
+ *
704
+ * @param options - Optional `id`
705
+ * @returns A stateless {@link EvaluatorInterface}
706
+ *
707
+ * @example
708
+ * ```ts
709
+ * import { createEvaluator } from '@src/core'
710
+ *
711
+ * const evaluator = createEvaluator()
712
+ * evaluator.evaluate({ field: 'age', operator: 'above', value: 18 }, { age: 25 })
713
+ * // { field: 'age', met: true, actual: 25 }
714
+ * ```
715
+ */
716
+ export declare function createEvaluator(options?: EvaluatorOptions): EvaluatorInterface;
717
+
718
+ /**
719
+ * Create a `FactManager` — a self-owning manager over an inferential
720
+ * definition's `facts`.
721
+ *
722
+ * @remarks
723
+ * `facts` — the initial collection (defaults to empty). `on` / `error` —
724
+ * emitter hooks (AGENTS §8 / §13).
725
+ *
726
+ * @param options - Optional seed collection and emitter hooks
727
+ * @returns A {@link FactManagerInterface}
728
+ *
729
+ * @example
730
+ * ```ts
731
+ * import { createFactManager, fact } from '@src/core'
732
+ *
733
+ * const facts = createFactManager()
734
+ * facts.append(fact('f1', 'human', ['socrates']))
735
+ * ```
736
+ */
737
+ export declare function createFactManager(options?: FactManagerOptions): FactManagerInterface;
738
+
739
+ /**
740
+ * Create a `FactorManager` — the divergent manager over a group's `factors`,
741
+ * threaded through a required `groupId` locator.
742
+ *
743
+ * @remarks
744
+ * Holds no collection state of its own — it reads and writes factors through
745
+ * the injected sibling {@link GroupManagerInterface}. `on` / `error` — emitter
746
+ * hooks (AGENTS §8 / §13).
747
+ *
748
+ * @param groups - The sibling group manager factors are located within
749
+ * @param options - Optional emitter hooks
750
+ * @returns A {@link FactorManagerInterface}
751
+ *
752
+ * @example
753
+ * ```ts
754
+ * import { createFactorManager, createGroupManager, factorGroup, staticFactor } from '@src/core'
755
+ *
756
+ * const groups = createGroupManager({ groups: [factorGroup('g1', 'sum', [])] })
757
+ * const factors = createFactorManager(groups)
758
+ * factors.append('g1', staticFactor('f1', 10))
759
+ * ```
760
+ */
761
+ export declare function createFactorManager(groups: GroupManagerInterface, options?: FactorManagerOptions): FactorManagerInterface;
762
+
763
+ /**
764
+ * Create a `GroupManager` — a self-owning manager over a quantitative
765
+ * definition's `groups`.
766
+ *
767
+ * @remarks
768
+ * `groups` — the initial collection (defaults to empty). `on` / `error` —
769
+ * emitter hooks (AGENTS §8 / §13). Kind-free: hand it to a
770
+ * {@link createDefinitionBuilder} `groups` slot regardless of reasoning.
771
+ *
772
+ * @param options - Optional seed collection and emitter hooks
773
+ * @returns A {@link GroupManagerInterface}
774
+ *
775
+ * @example
776
+ * ```ts
777
+ * import { createGroupManager, factorGroup } from '@src/core'
778
+ *
779
+ * const groups = createGroupManager({ groups: [factorGroup('g1', 'sum', [])] })
780
+ * groups.append(factorGroup('g2', 'sum', []))
781
+ * ```
782
+ */
783
+ export declare function createGroupManager(options?: GroupManagerOptions): GroupManagerInterface;
784
+
785
+ /**
786
+ * Create an `InferenceManager` — a self-owning manager over an inferential
787
+ * definition's `inferences`.
788
+ *
789
+ * @remarks
790
+ * `inferences` — the initial collection (defaults to empty). `on` / `error` —
791
+ * emitter hooks (AGENTS §8 / §13). Inference order is load-bearing.
792
+ *
793
+ * @param options - Optional seed collection and emitter hooks
794
+ * @returns An {@link InferenceManagerInterface}
795
+ *
796
+ * @example
797
+ * ```ts
798
+ * import { createInferenceManager, fact, inference } from '@src/core'
799
+ *
800
+ * const inferences = createInferenceManager()
801
+ * inferences.append(inference('m', [fact('p', 'human', ['?x'])], fact('c', 'mortal', ['?x'])))
802
+ * ```
803
+ */
804
+ export declare function createInferenceManager(options?: InferenceManagerOptions): InferenceManagerInterface;
805
+
806
+ /**
807
+ * Create the inferential reasoner — fact derivation with unification variables
808
+ * and proof trees.
809
+ *
810
+ * @remarks
811
+ * `id` — the reasoner's identity string (defaults to `'inferential'`).
812
+ *
813
+ * @param options - Optional `id`
814
+ * @returns A {@link ReasonerInterface} with reasoning `'inferential'`
815
+ *
816
+ * @example
817
+ * ```ts
818
+ * import { createInferentialReasoner, fact, inference, inferentialDefinition } from '@src/core'
819
+ *
820
+ * const reasoner = createInferentialReasoner()
821
+ * const definition = inferentialDefinition('mortality', 'Mortality',
822
+ * [fact('f1', 'human', ['socrates'])],
823
+ * [inference('mortal', [fact('p1', 'human', ['?x'])], fact('c1', 'mortal', ['?x']))],
824
+ * )
825
+ * reasoner.reason({}, definition) // derives mortal(socrates)
826
+ * ```
827
+ */
828
+ export declare function createInferentialReasoner(options?: InferentialReasonerOptions): ReasonerInterface;
829
+
830
+ /**
831
+ * Create the logical reasoner — rule-based deduction with forward / backward
832
+ * chaining.
833
+ *
834
+ * @remarks
835
+ * `id` — the reasoner's identity string (defaults to `'logical'`). `evaluator`
836
+ * — the injectable check evaluator (defaults to a fresh instance).
837
+ *
838
+ * @param options - Optional `id` and evaluator injection
839
+ * @returns A {@link ReasonerInterface} with reasoning `'logical'`
840
+ *
841
+ * @example
842
+ * ```ts
843
+ * import { atom, createLogicalReasoner, logicalDefinition, rule } from '@src/core'
844
+ *
845
+ * const reasoner = createLogicalReasoner()
846
+ * const definition = logicalDefinition('eligibility', 'Eligibility', [
847
+ * rule('adult', [atom('age', 'from', 18)], atom('adult', 'equals', true)),
848
+ * ])
849
+ * reasoner.reason({ age: 25 }, definition) // conclusion true
850
+ * ```
851
+ */
852
+ export declare function createLogicalReasoner(options?: LogicalReasonerOptions): ReasonerInterface;
853
+
854
+ /**
855
+ * Create the quantitative reasoner — factor-based numeric scoring.
856
+ *
857
+ * @remarks
858
+ * `id` — the reasoner's identity string (defaults to `'quantitative'`).
859
+ * `evaluator` / `transformer` / `aggregator` — injectable operators, each
860
+ * defaulting to a fresh default-constructed instance.
861
+ *
862
+ * @param options - Optional `id` and operator injections
863
+ * @returns A {@link ReasonerInterface} with reasoning `'quantitative'`
864
+ *
865
+ * @example
866
+ * ```ts
867
+ * import { createQuantitativeReasoner, fieldFactor, factorGroup, quantitativeDefinition } from '@src/core'
868
+ *
869
+ * const reasoner = createQuantitativeReasoner()
870
+ * const definition = quantitativeDefinition('risk', 'Risk', [
871
+ * factorGroup('g1', 'sum', [fieldFactor('age', 'age')]),
872
+ * ], { base: 100 })
873
+ * reasoner.reason({ age: 25 }, definition) // value 125
874
+ * ```
875
+ */
876
+ export declare function createQuantitativeReasoner(options?: QuantitativeReasonerOptions): ReasonerInterface;
877
+
878
+ /**
879
+ * Create the reasoning orchestrator.
880
+ *
881
+ * @remarks
882
+ * `reasoners` — the initial registry (a later entry of the same reasoning
883
+ * replaces an earlier one; the orchestrator ships with NO defaults). `bail` —
884
+ * `true` (the default) rethrows a reasoner throw after the `error` emit;
885
+ * `false` converts it to a failure result. `validate` — validate every
886
+ * definition before running it, throwing `INVALID` on failure (default
887
+ * `false`). `on` — initial event listeners (AGENTS §8). `error` — the
888
+ * emitter's listener-error handler (AGENTS §13).
889
+ *
890
+ * @param options - Optional registry, policies, and emitter hooks
891
+ * @returns A {@link ReasonInterface}
892
+ *
893
+ * @example
894
+ * ```ts
895
+ * import { createLogicalReasoner, createQuantitativeReasoner, createReason } from '@src/core'
896
+ *
897
+ * const reason = createReason({
898
+ * reasoners: [createQuantitativeReasoner(), createLogicalReasoner()],
899
+ * on: { reason: (result) => console.log(result.success) },
900
+ * })
901
+ * const result = reason.reason({ age: 25 }, definition)
902
+ * reason.destroy()
903
+ * ```
904
+ */
905
+ export declare function createReason(options?: ReasonOptions): ReasonInterface;
906
+
907
+ /**
908
+ * Create a `RuleManager` — a self-owning manager over a logical definition's
909
+ * `rules`.
910
+ *
911
+ * @remarks
912
+ * `rules` — the initial collection (defaults to empty). `on` / `error` —
913
+ * emitter hooks (AGENTS §8 / §13). Rule order is load-bearing.
914
+ *
915
+ * @param options - Optional seed collection and emitter hooks
916
+ * @returns A {@link RuleManagerInterface}
917
+ *
918
+ * @example
919
+ * ```ts
920
+ * import { atom, createRuleManager, rule } from '@src/core'
921
+ *
922
+ * const rules = createRuleManager()
923
+ * rules.append(rule('adult', [atom('age', 'from', 18)], atom('adult', 'equals', true)))
924
+ * ```
925
+ */
926
+ export declare function createRuleManager(options?: RuleManagerOptions): RuleManagerInterface;
927
+
928
+ /**
929
+ * Create a `SubjectBuilder` — a stateful workspace builder accumulating a
930
+ * {@link Subject}.
931
+ *
932
+ * @remarks
933
+ * `id` defaults to `seed.id` and is OPTIONAL — when neither `options.id` nor
934
+ * a string `seed.id` is present the builder is ANONYMOUS (`.id` is
935
+ * `undefined`, `build()` emits no `id` key). `on` — initial event listeners
936
+ * (AGENTS §8). `error` — the emitter's listener-error handler (AGENTS §13).
937
+ * Mutate through `set` / `remove` / `merge` / `clear`, then call `build()` to
938
+ * produce a fresh, plain {@link Subject} snapshot.
939
+ *
940
+ * @param seed - The starting subject
941
+ * @param options - Optional `id` override and emitter hooks
942
+ * @returns A {@link SubjectBuilderInterface}
943
+ *
944
+ * @example
945
+ * ```ts
946
+ * import { createSubjectBuilder } from '@src/core'
947
+ *
948
+ * const subject = createSubjectBuilder({ id: 's1', age: 30 })
949
+ * subject.set('age', 31)
950
+ * subject.build() // { id: 's1', age: 31 }
951
+ * subject.destroy()
952
+ * ```
953
+ */
954
+ export declare function createSubjectBuilder(seed: Subject, options?: SubjectBuilderOptions): SubjectBuilderInterface;
955
+
956
+ /**
957
+ * Create the symbolic reasoner — algebraic equation solving by variable
958
+ * isolation.
959
+ *
960
+ * @remarks
961
+ * `id` — the reasoner's identity string (defaults to `'symbolic'`).
962
+ *
963
+ * @param options - Optional `id`
964
+ * @returns A {@link ReasonerInterface} with reasoning `'symbolic'`
965
+ *
966
+ * @example
967
+ * ```ts
968
+ * import { constant, createSymbolicReasoner, equation, operation, symbolicDefinition, variable } from '@src/core'
969
+ *
970
+ * const reasoner = createSymbolicReasoner()
971
+ * const definition = symbolicDefinition('double', 'Double', [
972
+ * equation('e1', variable('y'), operation('multiply', variable('x'), constant(2)), 'y'),
973
+ * ])
974
+ * reasoner.reason({ x: 21 }, definition) // solutions.y === 42
975
+ * ```
976
+ */
977
+ export declare function createSymbolicReasoner(options?: SymbolicReasonerOptions): ReasonerInterface;
978
+
979
+ /**
980
+ * Create a math transformer.
981
+ *
982
+ * @remarks
983
+ * `id` — the transformer's identity string (defaults to `'transformer'`).
984
+ *
985
+ * @param options - Optional `id`
986
+ * @returns A stateless {@link TransformerInterface}
987
+ *
988
+ * @example
989
+ * ```ts
990
+ * import { createTransformer, transform } from '@src/core'
991
+ *
992
+ * const transformer = createTransformer()
993
+ * transformer.chain(100, [transform('add', 50), transform('multiply', 2)]) // 300
994
+ * ```
995
+ */
996
+ export declare function createTransformer(options?: TransformerOptions): TransformerInterface;
997
+
998
+ /**
999
+ * Create a `VariableManager` — a self-owning manager over a symbolic
1000
+ * definition's `variables` (a name-keyed record; `add` / `remove` only).
1001
+ *
1002
+ * @remarks
1003
+ * `variables` — the initial record (defaults to empty). `on` / `error` —
1004
+ * emitter hooks (AGENTS §8 / §13).
1005
+ *
1006
+ * @param options - Optional seed record and emitter hooks
1007
+ * @returns A {@link VariableManagerInterface}
1008
+ *
1009
+ * @example
1010
+ * ```ts
1011
+ * import { createVariableManager } from '@src/core'
1012
+ *
1013
+ * const variables = createVariableManager({ variables: { x: 1 } })
1014
+ * variables.add('y', 2)
1015
+ * ```
1016
+ */
1017
+ export declare function createVariableManager(options?: VariableManagerOptions): VariableManagerInterface;
1018
+
1019
+ /** Default `base` added before aggregation, at both group and definition level. */
1020
+ export declare const DEFAULT_BASE = 0;
1021
+
1022
+ /** Default `confidence` for facts, inferences, and injected subject facts. */
1023
+ export declare const DEFAULT_CONFIDENCE = 1;
1024
+
1025
+ /**
1026
+ * Default `depth` for chaining definitions — the forward-iteration /
1027
+ * backward-recursion cap of the logical and inferential reasoners.
1028
+ */
1029
+ export declare const DEFAULT_DEPTH = 10;
1030
+
1031
+ /** Default `precision` (decimal places) for quantitative values and symbolic solutions. */
1032
+ export declare const DEFAULT_PRECISION = 4;
1033
+
1034
+ /** Default factor / rule `priority` — evaluation order is ascending and stable. */
1035
+ export declare const DEFAULT_PRIORITY = 0;
1036
+
1037
+ /**
1038
+ * Default `bail` for the `Reason` orchestrator — a reasoner throw is rethrown
1039
+ * after the `error` emit.
1040
+ *
1041
+ * @remarks
1042
+ * Named with the domain qualifier so the generic `DEFAULT_BAIL` stays free for
1043
+ * other modules' bail defaults on the shared `@src/core` barrel.
1044
+ */
1045
+ export declare const DEFAULT_REASON_BAIL = true;
1046
+
1047
+ /** Default `validate` for the `Reason` orchestrator — per-call validation is skipped. */
1048
+ export declare const DEFAULT_VALIDATE = false;
1049
+
1050
+ /** Default factor `weight` at group aggregation. */
1051
+ export declare const DEFAULT_WEIGHT = 1;
1052
+
1053
+ /** Any reasoning definition, discriminated by `reasoning`. */
1054
+ export declare type Definition = QuantitativeDefinition | LogicalDefinition | SymbolicDefinition | InferentialDefinition;
1055
+
1056
+ /**
1057
+ * The `DefinitionBuilder` entity brand — a `unique symbol` key carrying
1058
+ * `readonly true` on every `DefinitionBuilderInterface` instance.
1059
+ *
1060
+ * @remarks
1061
+ * Only `isDefinitionBuilder` (`validators.ts`) reads this key, via
1062
+ * `Reflect.get`. A module-owned `unique symbol` cannot be produced by
1063
+ * `JSON.parse` or written by any consumer that does not import this constant,
1064
+ * so plain data can never forge the brand.
1065
+ */
1066
+ export declare const DEFINITION_BUILDER_BRAND: unique symbol;
1067
+
1068
+ /**
1069
+ * A stateful workspace builder accumulating a {@link Definition} through seven
1070
+ * always-present self-owning manager properties, shaped like `AgentContext`
1071
+ * (AGENTS §4.2.2): a private SCALAR ENVELOPE (reasoning / id / name plus the
1072
+ * kind's scalars) composed with each collection read from its manager.
1073
+ *
1074
+ * @remarks
1075
+ * Each manager is BRING-YOUR-OWN (a supplied one is reused) or a fresh one
1076
+ * seeded from the seed's matching collection (empty for off-kind collections).
1077
+ * Managers are KIND-FREE — an off-kind manager is simply ignored by `build()`,
1078
+ * never a `MISMATCH`. `build()` is TOTAL, deterministic, and returns a FRESH
1079
+ * plain {@link Definition} each call. `merge(incoming)` requires the SAME
1080
+ * `reasoning` (else `MISMATCH`) and distributes incoming scalars into the
1081
+ * envelope and collections into the managers via the matching `merge*` helper.
1082
+ * `clear(key)` deletes one optional field of the envelope for the instance's
1083
+ * `reasoning` (a non-clearable key throws `MISMATCH`). `destroy()` cascades to
1084
+ * all seven managers, emits `destroy`, then tears the builder emitter down LAST
1085
+ * (AGENTS §13); it is idempotent, and post-destroy mutation / build throws
1086
+ * `ReasonError('DESTROYED', …)`.
1087
+ */
1088
+ export declare class DefinitionBuilder implements DefinitionBuilderInterface {
1089
+ #private;
1090
+ readonly [DEFINITION_BUILDER_BRAND]: true;
1091
+ readonly groups: GroupManagerInterface;
1092
+ readonly factors: FactorManagerInterface;
1093
+ readonly rules: RuleManagerInterface;
1094
+ readonly equations: EquationManagerInterface;
1095
+ readonly variables: VariableManagerInterface;
1096
+ readonly facts: FactManagerInterface;
1097
+ readonly inferences: InferenceManagerInterface;
1098
+ constructor(seed: Definition, options?: DefinitionBuilderOptions);
1099
+ get id(): string;
1100
+ get reasoning(): Reasoning;
1101
+ get emitter(): EmitterInterface<DefinitionBuilderEventMap>;
1102
+ build(): Definition;
1103
+ merge(incoming: Definition): void;
1104
+ clear(key: string): void;
1105
+ destroy(): void;
1106
+ }
1107
+
1108
+ /**
1109
+ * The push observation surface of a {@link DefinitionBuilderInterface}
1110
+ * (AGENTS §13) — the builder-level lifecycle events; per-element mutation
1111
+ * events live on the individual managers' own emitters.
1112
+ *
1113
+ * @remarks
1114
+ * `merge` carries the definition's `reasoning`; `clear` carries the cleared
1115
+ * key; `destroy` fires once on teardown.
1116
+ */
1117
+ export declare type DefinitionBuilderEventMap = {
1118
+ /** The definition was reconciled with an incoming definition — carries the reasoning. */
1119
+ readonly merge: readonly [reasoning: Reasoning];
1120
+ /** An optional field was cleared — carries the field key. */
1121
+ readonly clear: readonly [key: string];
1122
+ /** The entity was destroyed. */
1123
+ readonly destroy: readonly [];
1124
+ };
1125
+
1126
+ /**
1127
+ * A stateful workspace builder accumulating a {@link Definition} through seven
1128
+ * always-present self-owning manager properties, taverna `AgentContext`-shaped
1129
+ * (AGENTS §4.2.2): a private scalar envelope plus one manager per collection.
1130
+ *
1131
+ * @remarks
1132
+ * `build()` is TOTAL, deterministic, and returns a FRESH plain
1133
+ * {@link Definition} each call (the scalar envelope composed with the kind's
1134
+ * collections, read from the relevant managers' plural accessors — off-kind
1135
+ * managers are ignored). `merge(incoming)` requires the SAME `reasoning`,
1136
+ * distributes incoming scalars into the envelope and collections into the
1137
+ * managers via the matching `merge*` helper (a cross-reasoning `incoming`
1138
+ * throws `ReasonError('MISMATCH', …)`). `clear(key)` is the uniform
1139
+ * optional-key selector (AGENTS §4.2.4) over the scalar envelope; a `key` that
1140
+ * is not a clearable optional field for the current kind throws
1141
+ * `ReasonError('MISMATCH', …, { key, reasoning })`. `destroy()` cascades to all
1142
+ * seven managers, emits `destroy`, then tears the builder emitter down LAST;
1143
+ * it is idempotent, and post-destroy mutation / build throws
1144
+ * `ReasonError('DESTROYED', …)` — only the `emitter` / manager getters and
1145
+ * `destroy` keep working.
1146
+ */
1147
+ export declare interface DefinitionBuilderInterface {
1148
+ readonly [DEFINITION_BUILDER_BRAND]: true;
1149
+ readonly id: string;
1150
+ readonly reasoning: Reasoning;
1151
+ readonly emitter: EmitterInterface<DefinitionBuilderEventMap>;
1152
+ readonly groups: GroupManagerInterface;
1153
+ readonly factors: FactorManagerInterface;
1154
+ readonly rules: RuleManagerInterface;
1155
+ readonly equations: EquationManagerInterface;
1156
+ readonly variables: VariableManagerInterface;
1157
+ readonly facts: FactManagerInterface;
1158
+ readonly inferences: InferenceManagerInterface;
1159
+ build(): Definition;
1160
+ merge(incoming: Definition): void;
1161
+ clear(key: string): void;
1162
+ destroy(): void;
1163
+ }
1164
+
1165
+ /**
1166
+ * Options for `createDefinitionBuilder` / the `DefinitionBuilder` constructor.
1167
+ *
1168
+ * @remarks
1169
+ * `id` — overrides the seed definition's `id` (defaults to `seed.id`). Each of
1170
+ * the seven manager slots is BRING-YOUR-OWN — a supplied manager is reused,
1171
+ * else one is constructed and seeded from the seed's matching collection. `on`
1172
+ * — initial event listeners (AGENTS §8). `error` — the emitter's
1173
+ * listener-error handler (AGENTS §13).
1174
+ */
1175
+ export declare interface DefinitionBuilderOptions {
1176
+ readonly id?: string;
1177
+ readonly groups?: GroupManagerInterface;
1178
+ readonly factors?: FactorManagerInterface;
1179
+ readonly rules?: RuleManagerInterface;
1180
+ readonly equations?: EquationManagerInterface;
1181
+ readonly variables?: VariableManagerInterface;
1182
+ readonly facts?: FactManagerInterface;
1183
+ readonly inferences?: InferenceManagerInterface;
1184
+ readonly on?: EmitterHooks<DefinitionBuilderEventMap>;
1185
+ readonly error?: EmitterErrorHandler;
1186
+ }
1187
+
1188
+ /**
1189
+ * The scalar-only projection of each definition kind — the {@link DefinitionBuilderInterface}
1190
+ * implementation's private envelope holds the non-collection fields; `build()` re-composes
1191
+ * the kind's collections from the managers' plural accessors.
1192
+ */
1193
+ export declare type DefinitionEnvelope = Omit<QuantitativeDefinition, 'groups'> | Omit<LogicalDefinition, 'rules'> | Omit<SymbolicDefinition, 'equations' | 'variables'> | Omit<InferentialDefinition, 'facts' | 'inferences'>;
1194
+
1195
+ /**
1196
+ * Determine whether two values are SameValueZero-equal — strict `===` with
1197
+ * `NaN` equal to itself (and, unlike `Object.is`, `+0` equal to `-0`).
1198
+ *
1199
+ * @remarks
1200
+ * This is the derivation-bookkeeping equality of the chaining reasoners: the
1201
+ * logical overlay and the inferential fact-dedupe compare with it so a
1202
+ * NaN-valued conclusion or fact term derives exactly ONCE and the fixpoint
1203
+ * converges (raw `===` would re-derive it every iteration, never converging).
1204
+ * It matches `Array.prototype.includes` semantics — the same membership test
1205
+ * the `any` / `none` comparisons use.
1206
+ *
1207
+ * @param left - The first value
1208
+ * @param right - The second value
1209
+ * @returns `true` when the values are SameValueZero-equal
1210
+ *
1211
+ * @example
1212
+ * ```ts
1213
+ * import { equalValues } from '@src/core'
1214
+ *
1215
+ * equalValues(Number.NaN, Number.NaN) // true — unlike ===
1216
+ * equalValues(0, -0) // true — unlike Object.is
1217
+ * equalValues(1, '1') // false — no coercion
1218
+ * ```
1219
+ */
1220
+ export declare function equalValues(left: unknown, right: unknown): boolean;
1221
+
1222
+ /**
1223
+ * One equation `left = right`, solved for the `target` variable.
1224
+ *
1225
+ * @remarks
1226
+ * When `target` is unbound and appears on exactly one side, it is isolated
1227
+ * algebraically through invertible operations (`add` / `subtract` / `multiply`
1228
+ * / `divide`); otherwise the right side is evaluated directly.
1229
+ */
1230
+ export declare interface Equation {
1231
+ readonly id: string;
1232
+ readonly name: string;
1233
+ readonly description?: string;
1234
+ readonly left: SymbolicExpression;
1235
+ readonly right: SymbolicExpression;
1236
+ readonly target: string;
1237
+ }
1238
+
1239
+ /**
1240
+ * Build an {@link Equation} — `left = right`, solved for `target`.
1241
+ *
1242
+ * @remarks
1243
+ * `name` defaults to the `id`; set `name` or `description` through `overrides`.
1244
+ *
1245
+ * @param id - The equation id
1246
+ * @param left - The left side
1247
+ * @param right - The right side
1248
+ * @param target - The variable name to solve for
1249
+ * @param overrides - Optional {@link Equation} fields merged over the defaults
1250
+ * @returns A fresh equation
1251
+ *
1252
+ * @example
1253
+ * ```ts
1254
+ * import { constant, equation, operation, variable } from '@src/core'
1255
+ *
1256
+ * // 2x + 3 = 11 — solved for x
1257
+ * equation('e1', operation('add', operation('multiply', constant(2), variable('x')), constant(3)), constant(11), 'x')
1258
+ * ```
1259
+ */
1260
+ export declare function equation(id: string, left: SymbolicExpression, right: SymbolicExpression, target: string, overrides?: Partial<Omit<Equation, 'id' | 'left' | 'right' | 'target'>>): Equation;
1261
+
1262
+ /**
1263
+ * The {@link EquationManagerInterface} implementation — a self-owning,
1264
+ * kind-free manager over a symbolic definition's `equations`.
1265
+ *
1266
+ * @remarks
1267
+ * OWNS its `#equations` collection as private copy-on-write state and its own
1268
+ * {@link Emitter} over {@link EquationManagerEventMap}. Equation order is
1269
+ * STRONGLY load-bearing — equations solve strictly in order and each rounded
1270
+ * solution feeds forward. The write-only `collection` setter is the owning
1271
+ * builder's silent bulk re-seat channel (used by `merge`). `destroy()` is
1272
+ * idempotent and tears the emitter down LAST; any other call after it throws
1273
+ * `ReasonError('DESTROYED', …)`.
1274
+ */
1275
+ export declare class EquationManager implements EquationManagerInterface {
1276
+ #private;
1277
+ constructor(options?: EquationManagerOptions);
1278
+ get emitter(): EmitterInterface<EquationManagerEventMap>;
1279
+ set collection(value: readonly Equation[]);
1280
+ equation(id: string): Equation | undefined;
1281
+ equations(): readonly Equation[];
1282
+ append(equation: Equation, target?: string): void;
1283
+ prepend(equation: Equation, target?: string): void;
1284
+ replace(equation: Equation): void;
1285
+ remove(id: string): void;
1286
+ destroy(): void;
1287
+ }
1288
+
1289
+ /** The push observation surface of an {@link EquationManagerInterface} (AGENTS §13). */
1290
+ export declare type EquationManagerEventMap = {
1291
+ /** An equation was appended — carries its id. */
1292
+ readonly append: readonly [id: string];
1293
+ /** An equation was prepended — carries its id. */
1294
+ readonly prepend: readonly [id: string];
1295
+ /** An equation was replaced in place — carries its id. */
1296
+ readonly replace: readonly [id: string];
1297
+ /** An equation was removed — carries its id. */
1298
+ readonly remove: readonly [id: string];
1299
+ /** The manager was destroyed. */
1300
+ readonly destroy: readonly [];
1301
+ };
1302
+
1303
+ /**
1304
+ * The {@link DefinitionBuilderInterface} manager over a symbolic definition's
1305
+ * `equations` — a self-owning, kind-free collection manager.
1306
+ *
1307
+ * @remarks
1308
+ * Equation order is strongly load-bearing — equations solve strictly in
1309
+ * order and each rounded solution feeds forward.
1310
+ */
1311
+ export declare interface EquationManagerInterface {
1312
+ readonly emitter: EmitterInterface<EquationManagerEventMap>;
1313
+ set collection(value: readonly Equation[]);
1314
+ equation(id: string): Equation | undefined;
1315
+ equations(): readonly Equation[];
1316
+ append(equation: Equation, target?: string): void;
1317
+ prepend(equation: Equation, target?: string): void;
1318
+ replace(equation: Equation): void;
1319
+ remove(id: string): void;
1320
+ destroy(): void;
1321
+ }
1322
+
1323
+ /**
1324
+ * Options for `createEquationManager` / the `EquationManager` constructor.
1325
+ *
1326
+ * @remarks
1327
+ * `equations` — the initial collection (defaults to empty). `on` — initial
1328
+ * event listeners (AGENTS §8). `error` — the emitter's listener-error handler
1329
+ * (AGENTS §13).
1330
+ */
1331
+ export declare interface EquationManagerOptions {
1332
+ readonly equations?: readonly Equation[];
1333
+ readonly on?: EmitterHooks<EquationManagerEventMap>;
1334
+ readonly error?: EmitterErrorHandler;
1335
+ }
1336
+
1337
+ /**
1338
+ * Evaluates {@link Check}s against subjects — the shared predicate engine of the
1339
+ * quantitative and logical reasoners.
1340
+ *
1341
+ * @remarks
1342
+ * TOTAL and strict: `evaluate` never throws (an unknown operator is caught and
1343
+ * surfaced as `CheckResult.error` with `met: false`) and never coerces —
1344
+ * `equals` / `not` are raw `===` / `!==`, the ordering operators demand numbers
1345
+ * on BOTH sides, `any` / `none` demand an array expected value (a non-array is
1346
+ * not met for either — `none` is NOT the raw complement of `any` on malformed
1347
+ * input), while `outside` IS the pure negation of `between` (so a malformed
1348
+ * range is `outside`). Fields resolve through the core `resolveField` — a string
1349
+ * is ONE key, an array descends. Stateless and deterministic.
1350
+ */
1351
+ export declare class Evaluator implements EvaluatorInterface {
1352
+ #private;
1353
+ constructor(options?: EvaluatorOptions);
1354
+ get id(): string;
1355
+ evaluate(check: Check, subject: Subject): CheckResult;
1356
+ batch(checks: readonly Check[], subject: Subject): readonly CheckResult[];
1357
+ }
1358
+
1359
+ /** Default `id` for an `Evaluator`. */
1360
+ export declare const EVALUATOR_ID = "evaluator";
1361
+
1362
+ /**
1363
+ * Evaluates {@link Check}s against subjects.
1364
+ *
1365
+ * @remarks
1366
+ * Total: `evaluate` never throws — an unknown operator surfaces as
1367
+ * `CheckResult.error` with `met: false`, and errors are isolated per item in
1368
+ * `batch`.
1369
+ */
1370
+ export declare interface EvaluatorInterface {
1371
+ readonly id: string;
1372
+ evaluate(check: Check, subject: Subject): CheckResult;
1373
+ batch(checks: readonly Check[], subject: Subject): readonly CheckResult[];
1374
+ }
1375
+
1376
+ /**
1377
+ * Options for `createEvaluator` / the `Evaluator` constructor.
1378
+ *
1379
+ * @remarks
1380
+ * `id` — the evaluator's identity string (defaults to `EVALUATOR_ID`).
1381
+ */
1382
+ export declare interface EvaluatorOptions {
1383
+ readonly id?: string;
1384
+ }
1385
+
1386
+ /** A boolean expression tree, discriminated by `form`. */
1387
+ export declare type Expression = Atom | Compound;
1388
+
1389
+ /**
1390
+ * Return every atom leaf of an expression tree, depth-first, left-to-right.
1391
+ *
1392
+ * @remarks
1393
+ * The shared atom-walk behind both {@link extractConclusions} and the raters'
1394
+ * conclusion merge: an `atom` yields itself; a compound flattens its operands in
1395
+ * authored order, so a later operand's atoms follow an earlier one's. The walk is
1396
+ * an ITERATIVE explicit-stack traversal (never recursive), so it stays total on
1397
+ * pathologically deep expression trees; a hole in an `operands` array is skipped,
1398
+ * matching `flatMap`'s hole-skipping behavior.
1399
+ *
1400
+ * @param expression - The expression tree to walk
1401
+ * @returns A fresh, ordered list of the atom leaves
1402
+ *
1403
+ * @example
1404
+ * ```ts
1405
+ * import { atom, compound, extractAtoms } from '@src/core'
1406
+ *
1407
+ * extractAtoms(atom('a', 'equals', 1)).length // 1
1408
+ * extractAtoms(compound('and', [atom('a', 'equals', 1), atom('b', 'equals', 2)])).length // 2
1409
+ * ```
1410
+ */
1411
+ export declare function extractAtoms(expression: Expression): readonly Atom[];
1412
+
1413
+ /**
1414
+ * Flatten a logical conclusion expression into its asserted `field = value`
1415
+ * pairs — connectives IGNORED.
1416
+ *
1417
+ * @remarks
1418
+ * The conclusion-extraction step of the logical reasoner's chaining: every
1419
+ * `atom` inside the expression asserts its `formatField(check.field) =
1420
+ * check.value` pair, and compounds are walked without regard to the connective
1421
+ * (an atom under `not` / `or` is asserted just the same). Later operands WIN on
1422
+ * a key clash (`Object.assign` order). Recursion runs through this exported
1423
+ * function itself; the derived-overlay keys are `formatField` strings (an array
1424
+ * field path flattens to its dot-joined form).
1425
+ *
1426
+ * @param expression - The conclusion expression to flatten
1427
+ * @returns A fresh record of asserted `field → value` pairs
1428
+ *
1429
+ * @example
1430
+ * ```ts
1431
+ * import { atom, compound, extractConclusions } from '@src/core'
1432
+ *
1433
+ * extractConclusions(atom('adult', 'equals', true)) // { adult: true }
1434
+ * extractConclusions(compound('and', [atom('a', 'equals', 1), atom('b', 'equals', 2)])) // { a: 1, b: 2 }
1435
+ * ```
1436
+ */
1437
+ export declare function extractConclusions(expression: Expression): Record<string, unknown>;
1438
+
1439
+ /**
1440
+ * One fact: a `predicate` over positional `terms`.
1441
+ *
1442
+ * @remarks
1443
+ * A string term starting with `?` is a unification variable (the prefix is
1444
+ * part of its name). `confidence` is `0–1` and propagates multiplicatively
1445
+ * through derivations (default `1`).
1446
+ */
1447
+ export declare interface Fact {
1448
+ readonly id: string;
1449
+ readonly predicate: string;
1450
+ readonly terms: readonly unknown[];
1451
+ readonly confidence?: number;
1452
+ }
1453
+
1454
+ /**
1455
+ * Build a {@link Fact} — a predicate over positional terms.
1456
+ *
1457
+ * @remarks
1458
+ * `confidence` defaults to `1` (the key is always set). A string term starting
1459
+ * with `?` is a unification variable.
1460
+ *
1461
+ * @param id - The fact id
1462
+ * @param predicate - The predicate name
1463
+ * @param terms - The positional terms
1464
+ * @param confidence - The fact's confidence (`0–1`, defaults to `1`)
1465
+ * @returns A fresh fact
1466
+ *
1467
+ * @example
1468
+ * ```ts
1469
+ * import { fact } from '@src/core'
1470
+ *
1471
+ * fact('f1', 'human', ['socrates']) // confidence 1
1472
+ * fact('f2', 'laysEggs', ['tweety'], 0.9) // explicit confidence
1473
+ * ```
1474
+ */
1475
+ export declare function fact(id: string, predicate: string, terms: readonly unknown[], confidence?: number): Fact;
1476
+
1477
+ /**
1478
+ * The {@link FactManagerInterface} implementation — a self-owning, kind-free
1479
+ * manager over an inferential definition's `facts`.
1480
+ *
1481
+ * @remarks
1482
+ * OWNS its `#facts` collection as private copy-on-write state and its own
1483
+ * {@link Emitter} over {@link FactManagerEventMap}. `Fact.id` is an AUTHORING
1484
+ * label — the runtime content-dedups facts by predicate+arity+terms,
1485
+ * independently of this manager's id-keyed dedup. The write-only `collection`
1486
+ * setter is the owning builder's silent bulk re-seat channel (used by `merge`).
1487
+ * `destroy()` is idempotent and tears the emitter down LAST; any other call
1488
+ * after it throws `ReasonError('DESTROYED', …)`.
1489
+ */
1490
+ export declare class FactManager implements FactManagerInterface {
1491
+ #private;
1492
+ constructor(options?: FactManagerOptions);
1493
+ get emitter(): EmitterInterface<FactManagerEventMap>;
1494
+ set collection(value: readonly Fact[]);
1495
+ fact(id: string): Fact | undefined;
1496
+ facts(): readonly Fact[];
1497
+ append(fact: Fact, target?: string): void;
1498
+ prepend(fact: Fact, target?: string): void;
1499
+ replace(fact: Fact): void;
1500
+ remove(id: string): void;
1501
+ destroy(): void;
1502
+ }
1503
+
1504
+ /** The push observation surface of a {@link FactManagerInterface} (AGENTS §13). */
1505
+ export declare type FactManagerEventMap = {
1506
+ /** A fact was appended — carries its id. */
1507
+ readonly append: readonly [id: string];
1508
+ /** A fact was prepended — carries its id. */
1509
+ readonly prepend: readonly [id: string];
1510
+ /** A fact was replaced in place — carries its id. */
1511
+ readonly replace: readonly [id: string];
1512
+ /** A fact was removed — carries its id. */
1513
+ readonly remove: readonly [id: string];
1514
+ /** The manager was destroyed. */
1515
+ readonly destroy: readonly [];
1516
+ };
1517
+
1518
+ /**
1519
+ * The {@link DefinitionBuilderInterface} manager over an inferential
1520
+ * definition's `facts` — a self-owning, kind-free collection manager.
1521
+ */
1522
+ export declare interface FactManagerInterface {
1523
+ readonly emitter: EmitterInterface<FactManagerEventMap>;
1524
+ set collection(value: readonly Fact[]);
1525
+ fact(id: string): Fact | undefined;
1526
+ facts(): readonly Fact[];
1527
+ append(fact: Fact, target?: string): void;
1528
+ prepend(fact: Fact, target?: string): void;
1529
+ replace(fact: Fact): void;
1530
+ remove(id: string): void;
1531
+ destroy(): void;
1532
+ }
1533
+
1534
+ /**
1535
+ * Options for `createFactManager` / the `FactManager` constructor.
1536
+ *
1537
+ * @remarks
1538
+ * `facts` — the initial collection (defaults to empty). `on` — initial event
1539
+ * listeners (AGENTS §8). `error` — the emitter's listener-error handler
1540
+ * (AGENTS §13).
1541
+ */
1542
+ export declare interface FactManagerOptions {
1543
+ readonly facts?: readonly Fact[];
1544
+ readonly on?: EmitterHooks<FactManagerEventMap>;
1545
+ readonly error?: EmitterErrorHandler;
1546
+ }
1547
+
1548
+ /**
1549
+ * One scored input of a quantitative group.
1550
+ *
1551
+ * @remarks
1552
+ * Evaluated as a pipeline: `checks` gate (ALL must be met) → `source` resolve
1553
+ * (`fallback` when unresolvable) → finite check → `transforms` chain →
1554
+ * `bounds` clamp → finite recheck. `weight` participates only at group
1555
+ * aggregation (default `1`); `priority` orders evaluation ascending (default
1556
+ * `0`, stable); `enabled: false` skips the factor entirely (omitted from
1557
+ * results); `required: true` promotes a gate / resolution failure to a result
1558
+ * error (making `success` false) without aborting the run.
1559
+ */
1560
+ export declare interface Factor {
1561
+ readonly id: string;
1562
+ readonly name: string;
1563
+ readonly description?: string;
1564
+ readonly source: Source;
1565
+ readonly fallback?: number;
1566
+ readonly checks?: readonly Check[];
1567
+ readonly transforms?: readonly Transform[];
1568
+ readonly bounds?: Bounds;
1569
+ readonly weight?: number;
1570
+ readonly priority?: number;
1571
+ readonly enabled?: boolean;
1572
+ readonly required?: boolean;
1573
+ }
1574
+
1575
+ /**
1576
+ * A group of factors aggregated into one value.
1577
+ *
1578
+ * @remarks
1579
+ * The group value is `base` (default `0`) plus the aggregation of its APPLIED
1580
+ * factors' values (with per-factor weights), clamped to `bounds` — never
1581
+ * rounded. `strict: true` makes the group all-or-nothing: if any evaluated
1582
+ * factor did not apply, the group contributes only its `base` and reports
1583
+ * `applied: false`. A group with zero applied factors is excluded from the
1584
+ * definition-level aggregation.
1585
+ */
1586
+ export declare interface FactorGroup {
1587
+ readonly id: string;
1588
+ readonly name: string;
1589
+ readonly description?: string;
1590
+ readonly factors: readonly Factor[];
1591
+ readonly aggregation: Aggregation;
1592
+ readonly base?: number;
1593
+ readonly bounds?: Bounds;
1594
+ readonly enabled?: boolean;
1595
+ readonly strict?: boolean;
1596
+ }
1597
+
1598
+ /**
1599
+ * Build a {@link FactorGroup}.
1600
+ *
1601
+ * @remarks
1602
+ * `name` defaults to the `id`; set `name`, `description`, `base`, `bounds`,
1603
+ * `enabled`, or `strict` through `overrides`.
1604
+ *
1605
+ * @param id - The group id
1606
+ * @param aggregation - How the applied factors' values reduce to one
1607
+ * @param factors - The group's factors
1608
+ * @param overrides - Optional {@link FactorGroup} fields merged over the defaults
1609
+ * @returns A fresh factor group
1610
+ *
1611
+ * @example
1612
+ * ```ts
1613
+ * import { factorGroup, staticFactor } from '@src/core'
1614
+ *
1615
+ * factorGroup('g1', 'sum', [staticFactor('f1', 10)], { base: 100 })
1616
+ * ```
1617
+ */
1618
+ export declare function factorGroup(id: string, aggregation: Aggregation, factors: readonly Factor[], overrides?: Partial<Omit<FactorGroup, 'id' | 'aggregation' | 'factors'>>): FactorGroup;
1619
+
1620
+ /**
1621
+ * The {@link FactorManagerInterface} implementation — the sole DIVERGENT
1622
+ * manager: factors nest inside groups, so it holds NO collection state of its
1623
+ * own and threads a required `groupId` locator.
1624
+ *
1625
+ * @remarks
1626
+ * Constructor-injected with the sibling {@link GroupManagerInterface}: each
1627
+ * write verb reads the located group (`groups.group(groupId)`), applies the
1628
+ * factor-level pure helper ({@link appendFactor} etc.), and writes the updated
1629
+ * group back via `groups.replace(…)`. A `groupId` naming no existing group
1630
+ * throws `ReasonError('TARGET', …, { groupId })`. It still owns its OWN
1631
+ * {@link Emitter} over {@link FactorManagerEventMap} (factor-id payloads).
1632
+ * `destroy()` is idempotent and tears the emitter down LAST; any other call
1633
+ * after it throws `ReasonError('DESTROYED', …)`.
1634
+ */
1635
+ export declare class FactorManager implements FactorManagerInterface {
1636
+ #private;
1637
+ constructor(groups: GroupManagerInterface, options?: FactorManagerOptions);
1638
+ get emitter(): EmitterInterface<FactorManagerEventMap>;
1639
+ factor(groupId: string, id: string): Factor | undefined;
1640
+ factors(groupId: string): readonly Factor[];
1641
+ append(groupId: string, factor: Factor, target?: string): void;
1642
+ prepend(groupId: string, factor: Factor, target?: string): void;
1643
+ replace(groupId: string, factor: Factor): void;
1644
+ remove(groupId: string, id: string): void;
1645
+ destroy(): void;
1646
+ }
1647
+
1648
+ /** The push observation surface of a {@link FactorManagerInterface} (AGENTS §13). */
1649
+ export declare type FactorManagerEventMap = {
1650
+ /** A factor was appended — carries its id. */
1651
+ readonly append: readonly [id: string];
1652
+ /** A factor was prepended — carries its id. */
1653
+ readonly prepend: readonly [id: string];
1654
+ /** A factor was replaced in place — carries its id. */
1655
+ readonly replace: readonly [id: string];
1656
+ /** A factor was removed — carries its id. */
1657
+ readonly remove: readonly [id: string];
1658
+ /** The manager was destroyed. */
1659
+ readonly destroy: readonly [];
1660
+ };
1661
+
1662
+ /**
1663
+ * The {@link DefinitionBuilderInterface} manager over a `FactorGroup`'s
1664
+ * `factors`, threaded through the required `groupId` locator (a factor lives
1665
+ * inside its group).
1666
+ *
1667
+ * @remarks
1668
+ * Divergent from the other managers: factors nest inside groups, so this
1669
+ * manager holds NO collection state of its own — it reads and writes through
1670
+ * the sibling {@link GroupManagerInterface} (`groups.group(groupId)` then
1671
+ * `groups.replace(…)`). A `groupId` naming no existing group throws
1672
+ * `ReasonError('TARGET', …, { groupId })`. `append` / `prepend` additionally
1673
+ * take an optional `target` factor id (a naming miss throws
1674
+ * `ReasonError('TARGET', …)`). It still owns its OWN emitter (factor-id
1675
+ * payloads).
1676
+ */
1677
+ export declare interface FactorManagerInterface {
1678
+ readonly emitter: EmitterInterface<FactorManagerEventMap>;
1679
+ factor(groupId: string, id: string): Factor | undefined;
1680
+ factors(groupId: string): readonly Factor[];
1681
+ append(groupId: string, factor: Factor, target?: string): void;
1682
+ prepend(groupId: string, factor: Factor, target?: string): void;
1683
+ replace(groupId: string, factor: Factor): void;
1684
+ remove(groupId: string, id: string): void;
1685
+ destroy(): void;
1686
+ }
1687
+
1688
+ /**
1689
+ * Options for `createFactorManager` / the `FactorManager` constructor.
1690
+ *
1691
+ * @remarks
1692
+ * The sibling `GroupManagerInterface` reference is a constructor argument, not
1693
+ * an option. `on` — initial event listeners (AGENTS §8). `error` — the
1694
+ * emitter's listener-error handler (AGENTS §13).
1695
+ */
1696
+ export declare interface FactorManagerOptions {
1697
+ readonly on?: EmitterHooks<FactorManagerEventMap>;
1698
+ readonly error?: EmitterErrorHandler;
1699
+ }
1700
+
1701
+ /** One band of a {@link RangeSource} — an optional inclusive bounds test and the value it yields. */
1702
+ export declare interface FactorRange {
1703
+ readonly bounds?: Bounds;
1704
+ readonly value: number;
1705
+ }
1706
+
1707
+ /**
1708
+ * One factor's evaluation outcome.
1709
+ *
1710
+ * @remarks
1711
+ * `raw` is the resolved source value before transforms / clamping (absent when
1712
+ * the source never resolved); `checks` is present only when the factor
1713
+ * declared checks and they gated it out. An unapplied factor carries
1714
+ * `value: 0`.
1715
+ */
1716
+ export declare interface FactorResult {
1717
+ readonly id: string;
1718
+ readonly applied: boolean;
1719
+ readonly value: number;
1720
+ readonly raw?: number;
1721
+ readonly checks?: readonly CheckResult[];
1722
+ }
1723
+
1724
+ /**
1725
+ * Derive a fact's predicate+arity bucket key — length-prefixed so the
1726
+ * delimiter cannot be forged.
1727
+ *
1728
+ * @remarks
1729
+ * Keys both stored facts and premise patterns (both are `Fact`-shaped) for
1730
+ * {@link indexByArity}: `matchFacts` already rejects an arity mismatch, so
1731
+ * narrowing a same-predicate bucket to same-predicate-AND-same-arity only
1732
+ * excludes candidates that could never unify anyway. Only `predicate` — the
1733
+ * one free-form, adversary-controlled part — is length-prefixed
1734
+ * (`length + ':' + predicate`), mirroring {@link factToKey}'s framing so a
1735
+ * predicate string embedding the `' '` delimiter can never be mistaken for a
1736
+ * different predicate+arity pairing; `terms.length` is always a plain
1737
+ * non-negative integer (never itself contains a space) so it needs no prefix.
1738
+ *
1739
+ * @param source - The fact (or premise pattern) to key
1740
+ * @returns The predicate+arity key string
1741
+ *
1742
+ * @example
1743
+ * ```ts
1744
+ * import { fact, factToArityKey } from '@src/core'
1745
+ *
1746
+ * factToArityKey(fact('a', 'human', ['x'])) // arity 1
1747
+ * factToArityKey(fact('b', 'human', ['x', 'y'])) // arity 2 — distinct key
1748
+ * ```
1749
+ */
1750
+ export declare function factToArityKey(source: Fact): string;
1751
+
1752
+ /**
1753
+ * Derive a fact's canonical dedup key — predicate + arity + per-term
1754
+ * SameValueZero identity (confidence is NOT part of it).
1755
+ *
1756
+ * @remarks
1757
+ * The dedup key of the inferential reasoner's forward fixpoint: two facts with
1758
+ * the same predicate, arity, and SameValueZero-equal terms share a key (so a
1759
+ * NaN-term fact derives once and ±0 collapse keeping the first), while
1760
+ * confidence never enters the key. Each part — the predicate, the stringified
1761
+ * arity, and every {@link termToKey} — is LENGTH-PREFIXED (`length + ':' + part`)
1762
+ * before joining, so the delimiter can never be forged by an adversarial string
1763
+ * term embedding it: two distinct facts always produce distinct keys, even when
1764
+ * a term string contains the delimiter (an injective framing raw joining lacked).
1765
+ *
1766
+ * @param source - The fact to key
1767
+ * @param identities - The reference-identity map threaded across the dedupe pass (see {@link termToKey})
1768
+ * @returns The fact's canonical key string
1769
+ *
1770
+ * @example
1771
+ * ```ts
1772
+ * import { fact, factToKey } from '@src/core'
1773
+ *
1774
+ * const identities = new Map<object, number>()
1775
+ * // Same predicate + terms → same key regardless of confidence:
1776
+ * factToKey(fact('a', 'p', ['x'], 1), identities) === factToKey(fact('b', 'p', ['x'], 0.5), identities)
1777
+ * ```
1778
+ */
1779
+ export declare function factToKey(source: Fact, identities: Map<object, number>): string;
1780
+
1781
+ /**
1782
+ * Build a {@link Factor} over a field {@link Source}.
1783
+ *
1784
+ * @param id - The factor id
1785
+ * @param field - The subject field to resolve as a number
1786
+ * @param overrides - Optional {@link Factor} fields merged over the defaults
1787
+ * @returns A fresh factor
1788
+ *
1789
+ * @example
1790
+ * ```ts
1791
+ * import { fieldFactor, transform } from '@src/core'
1792
+ *
1793
+ * fieldFactor('income-score', 'income', { transforms: [transform('divide', 1000)], fallback: 0 })
1794
+ * ```
1795
+ */
1796
+ export declare function fieldFactor(id: string, field: FieldPath, overrides?: Partial<Omit<Factor, 'id' | 'source'>>): Factor;
1797
+
1798
+ /**
1799
+ * A factor source reading a subject field as a number.
1800
+ *
1801
+ * @remarks
1802
+ * The field is coerced with the contracts `parseNumber` — a finite number
1803
+ * passes through, a numeric string coerces, and everything else (including
1804
+ * `NaN` / `±Infinity`) is unresolvable, falling back to the factor's
1805
+ * `fallback`.
1806
+ */
1807
+ export declare interface FieldSource {
1808
+ readonly origin: 'field';
1809
+ readonly field: FieldPath;
1810
+ }
1811
+
1812
+ /**
1813
+ * Build a field {@link Source} — a subject field read as a number.
1814
+ *
1815
+ * @param field - The subject field to resolve
1816
+ * @returns A fresh field source
1817
+ *
1818
+ * @example
1819
+ * ```ts
1820
+ * import { fieldSource } from '@src/core'
1821
+ *
1822
+ * fieldSource(['profile', 'score']) // descends into nested objects
1823
+ * ```
1824
+ */
1825
+ export declare function fieldSource(field: FieldPath): Source;
1826
+
1827
+ /**
1828
+ * Collect the ids that appear MORE THAN ONCE in an id-carrying list — each
1829
+ * duplicated id reported once, in first-occurrence order.
1830
+ *
1831
+ * @remarks
1832
+ * The shared uniqueness scan behind every reasoner's `validate()` duplicate-id
1833
+ * WARNINGS (rules, groups, factors, equations, inferences). Runtime stays
1834
+ * permissive about duplicates (first/last-wins artifacts) — this helper only
1835
+ * surfaces them.
1836
+ *
1837
+ * @param items - The id-carrying items to scan
1838
+ * @returns The duplicated ids, once each
1839
+ *
1840
+ * @example
1841
+ * ```ts
1842
+ * import { findDuplicates } from '@src/core'
1843
+ *
1844
+ * findDuplicates([{ id: 'a' }, { id: 'b' }, { id: 'a' }, { id: 'a' }]) // ['a']
1845
+ * ```
1846
+ */
1847
+ export declare function findDuplicates(items: readonly {
1848
+ readonly id: string;
1849
+ }[]): readonly string[];
1850
+
1851
+ /**
1852
+ * The `formatField`-flattened overlay keys an array-path conclusion atom
1853
+ * writes ANYWHERE among `rules` that an array-path premise atom also reads
1854
+ * ANYWHERE among `rules`.
1855
+ *
1856
+ * @remarks
1857
+ * The cross-rule authoring-time footgun probe behind
1858
+ * `LogicalReasoner.validate`'s overlay-key-mismatch warning: a logical
1859
+ * conclusion's derived overlay is a FLAT record keyed by
1860
+ * `formatField(check.field)` — an array `FieldPath` dot-joins into one string
1861
+ * key. A premise that reads the same field via a DOTTED-STRING path resolves
1862
+ * that flat key correctly, but a premise that reads it via an ARRAY path
1863
+ * calls `resolveField`, which descends key-by-key into nesting the flat
1864
+ * overlay never created, so the chain silently fails to connect. Collects the
1865
+ * flattened keys of every array-path conclusion atom across `rules` (once
1866
+ * each, authored order), then returns the ones that also appear as the
1867
+ * flattened key of some array-path premise atom anywhere in `rules` — a
1868
+ * single pass over every rule's conclusion and premise atoms, so the cost is
1869
+ * linear in total atom count, never quadratic.
1870
+ *
1871
+ * @param rules - The rules to scan for the array-path write/read overlap
1872
+ * @returns The mismatched overlay keys, once each, authored order
1873
+ *
1874
+ * @example
1875
+ * ```ts
1876
+ * import { atom, findOverlayMismatches, rule } from '@src/core'
1877
+ *
1878
+ * findOverlayMismatches([
1879
+ * rule('a', [], atom(['address', 'city'], 'equals', 'NYC')),
1880
+ * rule('b', [atom(['address', 'city'], 'equals', 'NYC')], atom('eligible', 'equals', true)),
1881
+ * ]) // ['address.city']
1882
+ * ```
1883
+ */
1884
+ export declare function findOverlayMismatches(rules: readonly Rule[]): readonly string[];
1885
+
1886
+ /**
1887
+ * The `'?'`-prefixed variables an inference's conclusion introduces that no
1888
+ * premise binds.
1889
+ *
1890
+ * @remarks
1891
+ * The authoring-time footgun probe behind `InferentialReasoner.validate`'s
1892
+ * unbound-variable warning: backward proving establishes each premise
1893
+ * independently with no cross-premise binding consistency, so a conclusion
1894
+ * term that no premise's `terms` ever names stays uninstantiated in the
1895
+ * derived fact. Gathers the `?`-prefixed string terms of `conclusion.terms`,
1896
+ * subtracts every `?`-prefixed string term appearing in any premise's
1897
+ * `terms`, and returns the remainder once each, in the conclusion's authored
1898
+ * order.
1899
+ *
1900
+ * @param source - The inference whose conclusion is checked against its premises
1901
+ * @returns The unbound conclusion variable names, once each, authored order
1902
+ *
1903
+ * @example
1904
+ * ```ts
1905
+ * import { fact, findUnboundVariables, inference } from '@src/core'
1906
+ *
1907
+ * findUnboundVariables(
1908
+ * inference('i', 'I', [fact('p', 'human', ['?x'])], fact('c', 'mortal', ['?x', '?y'])),
1909
+ * ) // ['?y'] — '?x' is bound by the premise, '?y' is not
1910
+ * ```
1911
+ */
1912
+ export declare function findUnboundVariables(source: Inference): readonly string[];
1913
+
1914
+ /**
1915
+ * Format a {@link FieldPath} for display — the single string key itself, or the
1916
+ * array segments joined with `.`.
1917
+ *
1918
+ * @remarks
1919
+ * Display-only: the joined form is how a field appears in traces and derived
1920
+ * overlays; it is NOT re-parsed into a path (a string stays ONE key).
1921
+ *
1922
+ * @param field - The field path to format
1923
+ * @returns The display string
1924
+ *
1925
+ * @example
1926
+ * ```ts
1927
+ * formatField('age') // 'age'
1928
+ * formatField(['address', 'city']) // 'address.city'
1929
+ * ```
1930
+ */
1931
+ export declare function formatField(field: FieldPath): string;
1932
+
1933
+ /**
1934
+ * The {@link GroupManagerInterface} implementation — a self-owning, kind-free
1935
+ * manager over a quantitative definition's `groups`.
1936
+ *
1937
+ * @remarks
1938
+ * OWNS its `#groups` collection as private copy-on-write state and its own
1939
+ * {@link Emitter} over {@link GroupManagerEventMap}. Every write verb delegates
1940
+ * to the matching collection-level pure helper ({@link appendById} etc.),
1941
+ * reassigns the fresh array, then emits (the affected group id) AFTER the
1942
+ * mutation. The write-only `collection` setter is the owning builder's silent
1943
+ * bulk re-seat channel (used by `merge`). `destroy()` is idempotent and tears
1944
+ * the emitter down LAST; any other call after it throws
1945
+ * `ReasonError('DESTROYED', …)`.
1946
+ */
1947
+ export declare class GroupManager implements GroupManagerInterface {
1948
+ #private;
1949
+ constructor(options?: GroupManagerOptions);
1950
+ get emitter(): EmitterInterface<GroupManagerEventMap>;
1951
+ set collection(value: readonly FactorGroup[]);
1952
+ group(id: string): FactorGroup | undefined;
1953
+ groups(): readonly FactorGroup[];
1954
+ append(group: FactorGroup, target?: string): void;
1955
+ prepend(group: FactorGroup, target?: string): void;
1956
+ replace(group: FactorGroup): void;
1957
+ remove(id: string): void;
1958
+ destroy(): void;
1959
+ }
1960
+
1961
+ /** The push observation surface of a {@link GroupManagerInterface} (AGENTS §13). */
1962
+ export declare type GroupManagerEventMap = {
1963
+ /** A group was appended — carries its id. */
1964
+ readonly append: readonly [id: string];
1965
+ /** A group was prepended — carries its id. */
1966
+ readonly prepend: readonly [id: string];
1967
+ /** A group was replaced in place — carries its id. */
1968
+ readonly replace: readonly [id: string];
1969
+ /** A group was removed — carries its id. */
1970
+ readonly remove: readonly [id: string];
1971
+ /** The manager was destroyed. */
1972
+ readonly destroy: readonly [];
1973
+ };
1974
+
1975
+ /**
1976
+ * The {@link DefinitionBuilderInterface} manager over a quantitative
1977
+ * definition's `groups` — a self-owning, kind-free collection manager.
1978
+ *
1979
+ * @remarks
1980
+ * `append` / `prepend` place a group relative to an optional `target` id (a
1981
+ * naming miss throws `ReasonError('TARGET', …)`); `replace` swaps a same-id
1982
+ * group in place; `remove` filters a group out (no-op when absent).
1983
+ */
1984
+ export declare interface GroupManagerInterface {
1985
+ readonly emitter: EmitterInterface<GroupManagerEventMap>;
1986
+ set collection(value: readonly FactorGroup[]);
1987
+ group(id: string): FactorGroup | undefined;
1988
+ groups(): readonly FactorGroup[];
1989
+ append(group: FactorGroup, target?: string): void;
1990
+ prepend(group: FactorGroup, target?: string): void;
1991
+ replace(group: FactorGroup): void;
1992
+ remove(id: string): void;
1993
+ destroy(): void;
1994
+ }
1995
+
1996
+ /**
1997
+ * Options for `createGroupManager` / the `GroupManager` constructor.
1998
+ *
1999
+ * @remarks
2000
+ * `groups` — the initial collection (defaults to empty). `on` — initial event
2001
+ * listeners (AGENTS §8). `error` — the emitter's listener-error handler
2002
+ * (AGENTS §13).
2003
+ */
2004
+ export declare interface GroupManagerOptions {
2005
+ readonly groups?: readonly FactorGroup[];
2006
+ readonly on?: EmitterHooks<GroupManagerEventMap>;
2007
+ readonly error?: EmitterErrorHandler;
2008
+ }
2009
+
2010
+ /**
2011
+ * One group's evaluation outcome — its clamped value and the per-factor
2012
+ * results (disabled factors omitted entirely).
2013
+ *
2014
+ * @remarks
2015
+ * An UNAPPLIED group's `value` may be non-finite (a `minimum` / `maximum`
2016
+ * aggregation over zero applied factors is `base + NaN`) — it is excluded from
2017
+ * the definition-level aggregation, so only an APPLIED non-finite value reaches
2018
+ * the definition-level finite check.
2019
+ */
2020
+ export declare interface GroupResult {
2021
+ readonly id: string;
2022
+ readonly applied: boolean;
2023
+ readonly value: number;
2024
+ readonly factors: readonly FactorResult[];
2025
+ }
2026
+
2027
+ /**
2028
+ * Bucket facts by predicate+arity, preserving append order within each bucket.
2029
+ *
2030
+ * @remarks
2031
+ * The index behind the inferential reasoner's same-predicate-and-arity join
2032
+ * scans (`#findAllBindings` / `#calculatePremiseConfidence`): `matchFacts`
2033
+ * already rejects a predicate OR arity mismatch, so restricting a premise's
2034
+ * search to its own predicate+arity bucket changes nothing but the cost — the
2035
+ * surviving matches and their append order are identical to a predicate-only
2036
+ * index. Append order within a bucket is preserved, so a "first match wins"
2037
+ * scan finds the same fact a full linear pass would.
2038
+ *
2039
+ * @param facts - The facts to index
2040
+ * @returns A fresh `Map` from {@link factToArityKey} to its facts, in append order
2041
+ *
2042
+ * @example
2043
+ * ```ts
2044
+ * import { fact, indexByArity } from '@src/core'
2045
+ *
2046
+ * const index = indexByArity([fact('a', 'human', ['x']), fact('b', 'human', ['y'])])
2047
+ * index.get(factToArityKey(fact('c', 'human', ['z'])))?.length // 2
2048
+ * ```
2049
+ */
2050
+ export declare function indexByArity(facts: readonly Fact[]): Map<string, Fact[]>;
2051
+
2052
+ /**
2053
+ * One inference rule: when every premise pattern unifies against known facts
2054
+ * (with consistent variable bindings), the instantiated `conclusion` is
2055
+ * derived.
2056
+ *
2057
+ * @remarks
2058
+ * A derived fact's confidence is the product of its matched premise facts'
2059
+ * confidences times the inference's own `confidence` (default `1`), rounded to
2060
+ * four decimal places. `enabled: false` skips the inference silently.
2061
+ */
2062
+ export declare interface Inference {
2063
+ readonly id: string;
2064
+ readonly name: string;
2065
+ readonly description?: string;
2066
+ readonly premises: readonly Fact[];
2067
+ readonly conclusion: Fact;
2068
+ readonly confidence?: number;
2069
+ readonly enabled?: boolean;
2070
+ }
2071
+
2072
+ /**
2073
+ * Build an {@link Inference} — premise patterns and a conclusion pattern.
2074
+ *
2075
+ * @remarks
2076
+ * `name` defaults to the `id`; set `name`, `description`, `confidence`, or
2077
+ * `enabled` through `overrides`.
2078
+ *
2079
+ * @param id - The inference id
2080
+ * @param premises - The fact patterns that must ALL unify
2081
+ * @param conclusion - The fact pattern derived when they do
2082
+ * @param overrides - Optional {@link Inference} fields merged over the defaults
2083
+ * @returns A fresh inference
2084
+ *
2085
+ * @example
2086
+ * ```ts
2087
+ * import { fact, inference } from '@src/core'
2088
+ *
2089
+ * inference('mortal', [fact('p1', 'human', ['?x'])], fact('c1', 'mortal', ['?x']), { confidence: 0.8 })
2090
+ * ```
2091
+ */
2092
+ export declare function inference(id: string, premises: readonly Fact[], conclusion: Fact, overrides?: Partial<Omit<Inference, 'id' | 'premises' | 'conclusion'>>): Inference;
2093
+
2094
+ /**
2095
+ * The {@link InferenceManagerInterface} implementation — a self-owning,
2096
+ * kind-free manager over an inferential definition's `inferences`.
2097
+ *
2098
+ * @remarks
2099
+ * OWNS its `#inferences` collection as private copy-on-write state and its own
2100
+ * {@link Emitter} over {@link InferenceManagerEventMap}. Inference order is
2101
+ * LOAD-BEARING — backward proving iterates in declaration order and returns on
2102
+ * first success. The write-only `collection` setter is the owning builder's
2103
+ * silent bulk re-seat channel (used by `merge`). `destroy()` is idempotent and
2104
+ * tears the emitter down LAST; any other call after it throws
2105
+ * `ReasonError('DESTROYED', …)`.
2106
+ */
2107
+ export declare class InferenceManager implements InferenceManagerInterface {
2108
+ #private;
2109
+ constructor(options?: InferenceManagerOptions);
2110
+ get emitter(): EmitterInterface<InferenceManagerEventMap>;
2111
+ set collection(value: readonly Inference[]);
2112
+ inference(id: string): Inference | undefined;
2113
+ inferences(): readonly Inference[];
2114
+ append(inference: Inference, target?: string): void;
2115
+ prepend(inference: Inference, target?: string): void;
2116
+ replace(inference: Inference): void;
2117
+ remove(id: string): void;
2118
+ destroy(): void;
2119
+ }
2120
+
2121
+ /** The push observation surface of an {@link InferenceManagerInterface} (AGENTS §13). */
2122
+ export declare type InferenceManagerEventMap = {
2123
+ /** An inference was appended — carries its id. */
2124
+ readonly append: readonly [id: string];
2125
+ /** An inference was prepended — carries its id. */
2126
+ readonly prepend: readonly [id: string];
2127
+ /** An inference was replaced in place — carries its id. */
2128
+ readonly replace: readonly [id: string];
2129
+ /** An inference was removed — carries its id. */
2130
+ readonly remove: readonly [id: string];
2131
+ /** The manager was destroyed. */
2132
+ readonly destroy: readonly [];
2133
+ };
2134
+
2135
+ /**
2136
+ * The {@link DefinitionBuilderInterface} manager over an inferential
2137
+ * definition's `inferences` — a self-owning, kind-free collection manager.
2138
+ *
2139
+ * @remarks
2140
+ * Inference order is load-bearing — backward proving iterates in declaration
2141
+ * order and returns on first success.
2142
+ */
2143
+ export declare interface InferenceManagerInterface {
2144
+ readonly emitter: EmitterInterface<InferenceManagerEventMap>;
2145
+ set collection(value: readonly Inference[]);
2146
+ inference(id: string): Inference | undefined;
2147
+ inferences(): readonly Inference[];
2148
+ append(inference: Inference, target?: string): void;
2149
+ prepend(inference: Inference, target?: string): void;
2150
+ replace(inference: Inference): void;
2151
+ remove(id: string): void;
2152
+ destroy(): void;
2153
+ }
2154
+
2155
+ /**
2156
+ * Options for `createInferenceManager` / the `InferenceManager` constructor.
2157
+ *
2158
+ * @remarks
2159
+ * `inferences` — the initial collection (defaults to empty). `on` — initial
2160
+ * event listeners (AGENTS §8). `error` — the emitter's listener-error handler
2161
+ * (AGENTS §13).
2162
+ */
2163
+ export declare interface InferenceManagerOptions {
2164
+ readonly inferences?: readonly Inference[];
2165
+ readonly on?: EmitterHooks<InferenceManagerEventMap>;
2166
+ readonly error?: EmitterErrorHandler;
2167
+ }
2168
+
2169
+ /** Default `id` for an `InferentialReasoner`. */
2170
+ export declare const INFERENTIAL_ID = "inferential";
2171
+
2172
+ /**
2173
+ * An inferential (fact-derivation) definition.
2174
+ *
2175
+ * @remarks
2176
+ * `facts` is the base knowledge; scalar subject fields are additionally
2177
+ * injected as `has(key, value)` facts. `strategy` picks a forward fixpoint
2178
+ * (derive everything) or backward proving (first provable conclusion wins,
2179
+ * returning a proof tree); `depth` caps iterations / recursion (default `10`).
2180
+ */
2181
+ export declare interface InferentialDefinition {
2182
+ readonly reasoning: 'inferential';
2183
+ readonly id: string;
2184
+ readonly name: string;
2185
+ readonly description?: string;
2186
+ readonly inferences: readonly Inference[];
2187
+ readonly facts: readonly Fact[];
2188
+ readonly strategy: ChainingStrategy;
2189
+ readonly depth?: number;
2190
+ }
2191
+
2192
+ /**
2193
+ * Build an {@link InferentialDefinition}.
2194
+ *
2195
+ * @remarks
2196
+ * `strategy` defaults to `'forward'`; set `strategy`, `description`, or `depth`
2197
+ * through `overrides`.
2198
+ *
2199
+ * @param id - The definition id
2200
+ * @param name - The display name
2201
+ * @param facts - The base knowledge
2202
+ * @param inferences - The inference rules
2203
+ * @param overrides - Optional {@link InferentialDefinition} fields merged over the defaults
2204
+ * @returns A fresh inferential definition
2205
+ *
2206
+ * @example
2207
+ * ```ts
2208
+ * import { fact, inference, inferentialDefinition } from '@src/core'
2209
+ *
2210
+ * inferentialDefinition('mortality', 'Mortality', [fact('f1', 'human', ['socrates'])], [
2211
+ * inference('mortal', [fact('p1', 'human', ['?x'])], fact('c1', 'mortal', ['?x'])),
2212
+ * ])
2213
+ * ```
2214
+ */
2215
+ export declare function inferentialDefinition(id: string, name: string, facts: readonly Fact[], inferences: readonly Inference[], overrides?: Partial<Omit<InferentialDefinition, 'reasoning' | 'id' | 'name' | 'facts' | 'inferences'>>): InferentialDefinition;
2216
+
2217
+ /**
2218
+ * The inferential reasoner — fact derivation with unification variables and
2219
+ * proof trees.
2220
+ *
2221
+ * @remarks
2222
+ * A string term starting with `?` is a unification variable — matching is
2223
+ * positional and BIDIRECTIONAL (variables may sit in facts as well as
2224
+ * patterns), with binding consistency enforced within one match and across
2225
+ * premises through pre-instantiation. Scalar subject fields (except `id`;
2226
+ * `null` / `undefined` / objects / arrays skipped) inject as
2227
+ * `has(key, value)` facts. Forward chaining is a naive fixpoint capped at
2228
+ * `depth` iterations: every consistent premise unification derives the
2229
+ * instantiated conclusion, with confidence = Π matched premise-fact confidences
2230
+ * × the inference's own `confidence`, rounded to four decimal places, and
2231
+ * duplicate facts (same predicate, arity, and SameValueZero-equal terms — a
2232
+ * NaN term derives once and converges) are never re-derived. Backward chaining
2233
+ * proves each inference's conclusion in
2234
+ * declaration order and RETURNS ON THE FIRST SUCCESS with one derived fact
2235
+ * (confidence = the inference's own — premise confidences are NOT propagated)
2236
+ * plus its {@link ProofNode} tree; recursion is guarded only by the depth cap.
2237
+ * Deriving nothing is still success. Nothing mutates its inputs; fully
2238
+ * deterministic (AGENTS §11).
2239
+ */
2240
+ export declare class InferentialReasoner implements ReasonerInterface {
2241
+ #private;
2242
+ constructor(options?: InferentialReasonerOptions);
2243
+ get id(): string;
2244
+ get reasoning(): Reasoning;
2245
+ supports(definition: Definition): boolean;
2246
+ validate(definition: Definition): ReasonValidationResult;
2247
+ reason(subject: Subject, definition: Definition): ReasonResult;
2248
+ }
2249
+
2250
+ /**
2251
+ * Options for `createInferentialReasoner` / the `InferentialReasoner`
2252
+ * constructor.
2253
+ *
2254
+ * @remarks
2255
+ * `id` — the reasoner's identity string (defaults to `INFERENTIAL_ID`).
2256
+ */
2257
+ export declare interface InferentialReasonerOptions {
2258
+ readonly id?: string;
2259
+ }
2260
+
2261
+ /**
2262
+ * The outcome of inferential reasoning.
2263
+ *
2264
+ * @remarks
2265
+ * `derived` lists the newly derived facts (deriving nothing is still success);
2266
+ * `proof` is produced only by the backward strategy, and only when a
2267
+ * conclusion was proved.
2268
+ */
2269
+ export declare interface InferentialResult {
2270
+ readonly reasoning: 'inferential';
2271
+ readonly derived: readonly Fact[];
2272
+ readonly proof?: ProofNode;
2273
+ readonly success: boolean;
2274
+ readonly trace: readonly string[];
2275
+ readonly errors: readonly string[];
2276
+ }
2277
+
2278
+ /**
2279
+ * Substitute a fact's bound `'?'`-variables with their values — a fresh fact
2280
+ * with unbound terms passed through unchanged.
2281
+ *
2282
+ * @remarks
2283
+ * The pattern-instantiation step of the inferential reasoner: a `'?'`-prefixed
2284
+ * string term that is present in `bindings` is replaced by its bound value;
2285
+ * every other term (constants and UNBOUND variables alike) is kept verbatim. The
2286
+ * returned fact is a fresh copy (`{ ...fact, terms }`) — the input is never
2287
+ * mutated (AGENTS §11).
2288
+ *
2289
+ * @param source - The fact (or pattern) to instantiate
2290
+ * @param bindings - The variable bindings to apply
2291
+ * @returns A fresh fact with bound variables substituted
2292
+ *
2293
+ * @example
2294
+ * ```ts
2295
+ * import { fact, instantiateFact } from '@src/core'
2296
+ *
2297
+ * instantiateFact(fact('c', 'mortal', ['?x']), { '?x': 'socrates' }).terms // ['socrates']
2298
+ * ```
2299
+ */
2300
+ export declare function instantiateFact(source: Fact, bindings: Record<string, unknown>): Fact;
2301
+
2302
+ /**
2303
+ * The math operations the symbolic reasoner can invert while isolating a
2304
+ * target variable — anything else (a `power`, an `abs`) fails the equation
2305
+ * with a non-invertible error.
2306
+ */
2307
+ export declare const INVERTIBLE_OPERATIONS: ReadonlySet<MathOperation>;
2308
+
2309
+ /**
2310
+ * Invert a `x op right = value` step, solving for the LEFT operand `x`.
2311
+ *
2312
+ * @remarks
2313
+ * The left-operand inverse of the symbolic reasoner's isolation: `add` inverts
2314
+ * to subtraction, `subtract` to addition, `multiply` to division, `divide` to
2315
+ * multiplication. Inversion by zero yields `NaN` (never a throw) — a `multiply`
2316
+ * with a zero `right` has no unique solution, and `x / 0 = value` has none
2317
+ * either, so both surface `NaN` for the non-finite check to report rather than a
2318
+ * bogus value. A non-invertible operator throws (caught per equation upstream).
2319
+ *
2320
+ * @param operator - The math operation to invert
2321
+ * @param value - The known result of `x op right`
2322
+ * @param rightValue - The known right operand
2323
+ * @returns The isolated left operand (`NaN` on a zero-division inverse)
2324
+ *
2325
+ * @example
2326
+ * ```ts
2327
+ * import { invertLeft } from '@src/core'
2328
+ *
2329
+ * invertLeft('add', 10, 3) // 7 — x + 3 = 10
2330
+ * invertLeft('multiply', 10, 0) // NaN — x * 0 = 10 has no solution
2331
+ * ```
2332
+ */
2333
+ export declare function invertLeft(operator: MathOperation, value: number, rightValue: number): number;
2334
+
2335
+ /**
2336
+ * Invert a `left op x = value` step, solving for the RIGHT operand `x`.
2337
+ *
2338
+ * @remarks
2339
+ * The right-operand inverse of the symbolic reasoner's isolation: `add` inverts
2340
+ * to `value - left`, `subtract` to `left - value`, `multiply` to `value / left`
2341
+ * (with a zero `left` yielding `NaN`), `divide` to `left / value` (with a zero
2342
+ * `value` yielding `NaN`). Inversion by zero yields `NaN`, never a throw; a
2343
+ * non-invertible operator throws (caught per equation upstream).
2344
+ *
2345
+ * @param operator - The math operation to invert
2346
+ * @param value - The known result of `left op x`
2347
+ * @param leftValue - The known left operand
2348
+ * @returns The isolated right operand (`NaN` on a zero-division inverse)
2349
+ *
2350
+ * @example
2351
+ * ```ts
2352
+ * import { invertRight } from '@src/core'
2353
+ *
2354
+ * invertRight('subtract', 4, 10) // 6 — 10 - x = 4
2355
+ * invertRight('divide', 0, 10) // NaN — 10 / x = 0 has no finite solution
2356
+ * ```
2357
+ */
2358
+ export declare function invertRight(operator: MathOperation, value: number, leftValue: number): number;
2359
+
2360
+ /**
2361
+ * Determine whether a value is an {@link Aggregation} literal.
2362
+ *
2363
+ * @param value - The value to test
2364
+ * @returns `true` when `value` is one of the five aggregations
2365
+ *
2366
+ * @example
2367
+ * ```ts
2368
+ * import { isAggregation } from '@src/core'
2369
+ *
2370
+ * isAggregation('sum') // true
2371
+ * isAggregation('median') // false
2372
+ * ```
2373
+ */
2374
+ export declare const isAggregation: Guard<Aggregation>;
2375
+
2376
+ /**
2377
+ * Determine whether a value is a {@link Bounds} — an inclusive numeric clamp.
2378
+ *
2379
+ * @param value - The value to test
2380
+ * @returns `true` when `value` is a well-formed bounds record (both sides optional)
2381
+ *
2382
+ * @example
2383
+ * ```ts
2384
+ * import { isBounds } from '@src/core'
2385
+ *
2386
+ * isBounds({ minimum: 0, maximum: 100 }) // true
2387
+ * isBounds({}) // true — unbounded
2388
+ * isBounds({ minimum: NaN }) // false — non-finite
2389
+ * ```
2390
+ */
2391
+ export declare function isBounds(value: unknown): value is Bounds;
2392
+
2393
+ /**
2394
+ * Determine whether a value is a {@link ChainingStrategy} literal.
2395
+ *
2396
+ * @param value - The value to test
2397
+ * @returns `true` when `value` is `'forward'` or `'backward'`
2398
+ *
2399
+ * @example
2400
+ * ```ts
2401
+ * import { isChainingStrategy } from '@src/core'
2402
+ *
2403
+ * isChainingStrategy('forward') // true
2404
+ * isChainingStrategy('upward') // false
2405
+ * ```
2406
+ */
2407
+ export declare const isChainingStrategy: Guard<ChainingStrategy>;
2408
+
2409
+ /**
2410
+ * Determine whether a value is a {@link Check} — a field / operator / value
2411
+ * predicate.
2412
+ *
2413
+ * @remarks
2414
+ * `value` may be ANYTHING (including `null` / `undefined`) but the key must be
2415
+ * PRESENT — exact-record semantics reject a check that lost its `value` key.
2416
+ *
2417
+ * @param value - The value to test
2418
+ * @returns `true` when `value` is a well-formed check
2419
+ *
2420
+ * @example
2421
+ * ```ts
2422
+ * import { isCheck } from '@src/core'
2423
+ *
2424
+ * isCheck({ field: 'age', operator: 'above', value: 18 }) // true
2425
+ * isCheck({ field: 'age', operator: 'over', value: 18 }) // false — unknown operator
2426
+ * ```
2427
+ */
2428
+ export declare function isCheck(value: unknown): value is Check;
2429
+
2430
+ /**
2431
+ * Determine whether a value is a {@link Comparison} literal.
2432
+ *
2433
+ * @param value - The value to test
2434
+ * @returns `true` when `value` is one of the ten comparison operators
2435
+ *
2436
+ * @example
2437
+ * ```ts
2438
+ * import { isComparison } from '@src/core'
2439
+ *
2440
+ * isComparison('between') // true
2441
+ * isComparison('greaterThan') // false — the operator vocabulary is single-word
2442
+ * ```
2443
+ */
2444
+ export declare const isComparison: Guard<Comparison>;
2445
+
2446
+ /**
2447
+ * Determine whether a value is a {@link Definition} — any of the four
2448
+ * definition shapes, discriminated by `reasoning`.
2449
+ *
2450
+ * @param value - The value to test
2451
+ * @returns `true` when `value` is a well-formed definition of any reasoning
2452
+ *
2453
+ * @example
2454
+ * ```ts
2455
+ * import { isDefinition, logicalDefinition } from '@src/core'
2456
+ *
2457
+ * isDefinition(logicalDefinition('eligibility', 'Eligibility', [])) // true
2458
+ * isDefinition({ reasoning: 'quantum' }) // false
2459
+ * ```
2460
+ */
2461
+ export declare function isDefinition(value: unknown): value is Definition;
2462
+
2463
+ /**
2464
+ * Determine whether a value is a `DefinitionBuilder` ENTITY — the brand-guarded
2465
+ * stateful workspace, not the plain {@link Definition} data union.
2466
+ *
2467
+ * @remarks
2468
+ * A `unique symbol` brand check (`Reflect.get`, AGENTS §14): a plain subject
2469
+ * is an open record whose values may legally be functions, so a
2470
+ * method-presence check (`typeof value.build === 'function'`) is FORGEABLE —
2471
+ * this guard is not. A module-owned `unique symbol` cannot be produced by
2472
+ * `JSON.parse` or written by any consumer that does not import
2473
+ * `DEFINITION_BUILDER_BRAND`, so plain data can never forge it. Total: a
2474
+ * non-object, a missing brand, or a hostile prototype all return `false`,
2475
+ * never throw.
2476
+ *
2477
+ * @param value - The value to test
2478
+ * @returns `true` when `value` carries the `DefinitionBuilder` entity brand
2479
+ *
2480
+ * @example
2481
+ * ```ts
2482
+ * import { createDefinitionBuilder, isDefinitionBuilder, quantitativeDefinition } from '@src/core'
2483
+ *
2484
+ * const definition = createDefinitionBuilder(quantitativeDefinition('risk', 'Risk', []))
2485
+ * isDefinitionBuilder(definition) // true
2486
+ * isDefinitionBuilder({ build: () => undefined }) // false — forged build field
2487
+ * isDefinitionBuilder(quantitativeDefinition('r', 'R', [])) // false — plain data, not the entity
2488
+ * ```
2489
+ */
2490
+ export declare function isDefinitionBuilder(value: unknown): value is DefinitionBuilderInterface;
2491
+
2492
+ /**
2493
+ * Determine whether a value is an {@link Equation} — `left = right`, solved for
2494
+ * `target`.
2495
+ *
2496
+ * @param value - The value to test
2497
+ * @returns `true` when `value` is a well-formed equation
2498
+ *
2499
+ * @example
2500
+ * ```ts
2501
+ * import { constant, equation, isEquation, variable } from '@src/core'
2502
+ *
2503
+ * isEquation(equation('e1', variable('x'), constant(42), 'x')) // true
2504
+ * isEquation({ id: 'e1', target: 'x' }) // false — sides missing
2505
+ * ```
2506
+ */
2507
+ export declare function isEquation(value: unknown): value is Equation;
2508
+
2509
+ /**
2510
+ * Determine whether a value is an {@link Expression} — a boolean expression
2511
+ * tree of atoms and compounds, discriminated by `form`.
2512
+ *
2513
+ * @remarks
2514
+ * Recursive through `lazyOf` (AGENTS §14) — recursion is STACK-BOUNDED, not
2515
+ * unbounded: nesting beyond the engine's stack budget (roughly 1000 levels)
2516
+ * and cyclic input are CONTAINED as `false`, never a throw. Input past that
2517
+ * bound is rejected, not validated.
2518
+ *
2519
+ * @param value - The value to test
2520
+ * @returns `true` when `value` is a well-formed expression tree
2521
+ *
2522
+ * @example
2523
+ * ```ts
2524
+ * import { atom, compound, isExpression } from '@src/core'
2525
+ *
2526
+ * isExpression(atom('age', 'from', 18)) // true
2527
+ * isExpression(compound('and', [atom('age', 'from', 18)])) // true
2528
+ * isExpression({ form: 'compound', operator: 'and' }) // false — operands missing
2529
+ * ```
2530
+ */
2531
+ export declare function isExpression(value: unknown): value is Expression;
2532
+
2533
+ /**
2534
+ * Determine whether a value is a {@link Fact} — a predicate over positional
2535
+ * terms.
2536
+ *
2537
+ * @remarks
2538
+ * `terms` elements are unconstrained (`unknown`) — a `'?'`-prefixed string term
2539
+ * is a unification variable, anything else a constant.
2540
+ *
2541
+ * @param value - The value to test
2542
+ * @returns `true` when `value` is a well-formed fact
2543
+ *
2544
+ * @example
2545
+ * ```ts
2546
+ * import { isFact } from '@src/core'
2547
+ *
2548
+ * isFact({ id: 'f1', predicate: 'human', terms: ['socrates'] }) // true
2549
+ * isFact({ id: 'f1', predicate: 'human' }) // false — terms missing
2550
+ * ```
2551
+ */
2552
+ export declare function isFact(value: unknown): value is Fact;
2553
+
2554
+ /**
2555
+ * Determine whether a value is a {@link Factor} — one scored input of a
2556
+ * quantitative group.
2557
+ *
2558
+ * @param value - The value to test
2559
+ * @returns `true` when `value` is a well-formed factor
2560
+ *
2561
+ * @example
2562
+ * ```ts
2563
+ * import { isFactor } from '@src/core'
2564
+ *
2565
+ * isFactor({ id: 'age', name: 'Age', source: { origin: 'field', field: 'age' } }) // true
2566
+ * isFactor({ id: 'age', name: 'Age' }) // false — no source
2567
+ * ```
2568
+ */
2569
+ export declare function isFactor(value: unknown): value is Factor;
2570
+
2571
+ /**
2572
+ * Determine whether a value is a {@link FactorGroup} — a group of factors
2573
+ * aggregated into one value.
2574
+ *
2575
+ * @param value - The value to test
2576
+ * @returns `true` when `value` is a well-formed factor group
2577
+ *
2578
+ * @example
2579
+ * ```ts
2580
+ * import { isFactorGroup, staticFactor } from '@src/core'
2581
+ *
2582
+ * isFactorGroup({ id: 'g1', name: 'g1', aggregation: 'sum', factors: [staticFactor('f1', 10)] }) // true
2583
+ * isFactorGroup({ id: 'g1', name: 'g1', aggregation: 'median', factors: [] }) // false
2584
+ * ```
2585
+ */
2586
+ export declare function isFactorGroup(value: unknown): value is FactorGroup;
2587
+
2588
+ /**
2589
+ * Determine whether a value is a {@link FactorRange} — one band of a range
2590
+ * source.
2591
+ *
2592
+ * @param value - The value to test
2593
+ * @returns `true` when `value` is a well-formed factor range
2594
+ *
2595
+ * @example
2596
+ * ```ts
2597
+ * import { isFactorRange } from '@src/core'
2598
+ *
2599
+ * isFactorRange({ bounds: { maximum: 25 }, value: 1.5 }) // true
2600
+ * isFactorRange({ value: 42 }) // true — a catch-all band
2601
+ * ```
2602
+ */
2603
+ export declare function isFactorRange(value: unknown): value is FactorRange;
2604
+
2605
+ /**
2606
+ * Determine whether a value is a {@link FieldPath} — a single string key or an
2607
+ * array of keys descending into nested objects.
2608
+ *
2609
+ * @param value - The value to test
2610
+ * @returns `true` when `value` is a string or an array of strings
2611
+ *
2612
+ * @example
2613
+ * ```ts
2614
+ * import { isFieldPath } from '@src/core'
2615
+ *
2616
+ * isFieldPath('age') // true — ONE key (never dot-split)
2617
+ * isFieldPath(['address', 'city']) // true — descends
2618
+ * isFieldPath(42) // false
2619
+ * ```
2620
+ */
2621
+ export declare const isFieldPath: Guard<FieldPath>;
2622
+
2623
+ /**
2624
+ * Determine whether a value is an {@link Inference} — premise patterns and a
2625
+ * conclusion pattern.
2626
+ *
2627
+ * @param value - The value to test
2628
+ * @returns `true` when `value` is a well-formed inference
2629
+ *
2630
+ * @example
2631
+ * ```ts
2632
+ * import { fact, inference, isInference } from '@src/core'
2633
+ *
2634
+ * isInference(inference('mortal', [fact('p1', 'human', ['?x'])], fact('c1', 'mortal', ['?x']))) // true
2635
+ * isInference({ id: 'mortal' }) // false
2636
+ * ```
2637
+ */
2638
+ export declare function isInference(value: unknown): value is Inference;
2639
+
2640
+ /**
2641
+ * Determine whether a value is an {@link InferentialDefinition}.
2642
+ *
2643
+ * @param value - The value to test
2644
+ * @returns `true` when `value` is a well-formed inferential definition
2645
+ *
2646
+ * @example
2647
+ * ```ts
2648
+ * import { inferentialDefinition, isInferentialDefinition } from '@src/core'
2649
+ *
2650
+ * isInferentialDefinition(inferentialDefinition('birds', 'Birds', [], [])) // true
2651
+ * isInferentialDefinition({ reasoning: 'inferential', id: 'birds' }) // false
2652
+ * ```
2653
+ */
2654
+ export declare function isInferentialDefinition(value: unknown): value is InferentialDefinition;
2655
+
2656
+ /**
2657
+ * Determine whether a value is a {@link LogicalDefinition}.
2658
+ *
2659
+ * @param value - The value to test
2660
+ * @returns `true` when `value` is a well-formed logical definition
2661
+ *
2662
+ * @example
2663
+ * ```ts
2664
+ * import { isLogicalDefinition, logicalDefinition } from '@src/core'
2665
+ *
2666
+ * isLogicalDefinition(logicalDefinition('eligibility', 'Eligibility', [])) // true
2667
+ * isLogicalDefinition({ reasoning: 'logical', id: 'eligibility' }) // false
2668
+ * ```
2669
+ */
2670
+ export declare function isLogicalDefinition(value: unknown): value is LogicalDefinition;
2671
+
2672
+ /**
2673
+ * Determine whether a value is a {@link LogicalOperator} literal.
2674
+ *
2675
+ * @param value - The value to test
2676
+ * @returns `true` when `value` is one of the five logical connectives
2677
+ *
2678
+ * @example
2679
+ * ```ts
2680
+ * import { isLogicalOperator } from '@src/core'
2681
+ *
2682
+ * isLogicalOperator('implies') // true
2683
+ * isLogicalOperator('nand') // false
2684
+ * ```
2685
+ */
2686
+ export declare const isLogicalOperator: Guard<LogicalOperator>;
2687
+
2688
+ /**
2689
+ * Determine whether a value is a {@link MathOperation} literal.
2690
+ *
2691
+ * @param value - The value to test
2692
+ * @returns `true` when `value` is one of the thirteen math operations
2693
+ *
2694
+ * @example
2695
+ * ```ts
2696
+ * import { isMathOperation } from '@src/core'
2697
+ *
2698
+ * isMathOperation('multiply') // true
2699
+ * isMathOperation('modulo') // false
2700
+ * ```
2701
+ */
2702
+ export declare const isMathOperation: Guard<MathOperation>;
2703
+
2704
+ /**
2705
+ * Determine whether a value is a record whose every value is a finite number —
2706
+ * the shape of a `LookupSource.table` and a `SymbolicDefinition.variables`.
2707
+ *
2708
+ * @param value - The value to test
2709
+ * @returns `true` when `value` is a plain record of finite numbers
2710
+ *
2711
+ * @example
2712
+ * ```ts
2713
+ * import { isNumberRecord } from '@src/core'
2714
+ *
2715
+ * isNumberRecord({ CA: 1.2, NY: 0.8 }) // true
2716
+ * isNumberRecord({ CA: '1.2' }) // false — strings do not coerce here
2717
+ * ```
2718
+ */
2719
+ export declare const isNumberRecord: Guard<Readonly<Record<string, number>>>;
2720
+
2721
+ /**
2722
+ * Determine whether a value is a {@link QuantitativeDefinition}.
2723
+ *
2724
+ * @param value - The value to test
2725
+ * @returns `true` when `value` is a well-formed quantitative definition
2726
+ *
2727
+ * @example
2728
+ * ```ts
2729
+ * import { isQuantitativeDefinition, quantitativeDefinition } from '@src/core'
2730
+ *
2731
+ * isQuantitativeDefinition(quantitativeDefinition('risk', 'Risk', [])) // true
2732
+ * isQuantitativeDefinition({ reasoning: 'quantitative', id: 'risk' }) // false
2733
+ * ```
2734
+ */
2735
+ export declare function isQuantitativeDefinition(value: unknown): value is QuantitativeDefinition;
2736
+
2737
+ /**
2738
+ * Narrow an unknown caught value to a {@link ReasonError}.
2739
+ *
2740
+ * @param value - The value to test (typically a `catch` binding)
2741
+ * @returns `true` when `value` is a {@link ReasonError}
2742
+ *
2743
+ * @example
2744
+ * ```ts
2745
+ * try {
2746
+ * reason.reason(subject, definition)
2747
+ * } catch (error) {
2748
+ * if (isReasonError(error) && error.code === 'MISSING') registerFallback()
2749
+ * }
2750
+ * ```
2751
+ */
2752
+ export declare function isReasonError(value: unknown): value is ReasonError;
2753
+
2754
+ /**
2755
+ * Determine whether a value is a {@link Reasoning} literal.
2756
+ *
2757
+ * @param value - The value to test
2758
+ * @returns `true` when `value` is one of the four reasoning strategies
2759
+ *
2760
+ * @example
2761
+ * ```ts
2762
+ * import { isReasoning } from '@src/core'
2763
+ *
2764
+ * isReasoning('logical') // true
2765
+ * isReasoning('fuzzy') // false
2766
+ * ```
2767
+ */
2768
+ export declare const isReasoning: Guard<Reasoning>;
2769
+
2770
+ /**
2771
+ * Determine whether a value is a {@link Rule} — premises and a conclusion.
2772
+ *
2773
+ * @param value - The value to test
2774
+ * @returns `true` when `value` is a well-formed rule
2775
+ *
2776
+ * @example
2777
+ * ```ts
2778
+ * import { atom, isRule, rule } from '@src/core'
2779
+ *
2780
+ * isRule(rule('adult', [atom('age', 'from', 18)], atom('adult', 'equals', true))) // true
2781
+ * isRule({ id: 'adult' }) // false
2782
+ * ```
2783
+ */
2784
+ export declare function isRule(value: unknown): value is Rule;
2785
+
2786
+ /**
2787
+ * Determine whether a value is a {@link Source} — any of the four factor
2788
+ * sources, discriminated by `origin`.
2789
+ *
2790
+ * @param value - The value to test
2791
+ * @returns `true` when `value` is a well-formed static / field / lookup / range source
2792
+ *
2793
+ * @example
2794
+ * ```ts
2795
+ * import { isSource } from '@src/core'
2796
+ *
2797
+ * isSource({ origin: 'static', value: 42 }) // true
2798
+ * isSource({ origin: 'lookup', field: 'state', table: { CA: 5 } }) // true
2799
+ * isSource({ origin: 'random' }) // false
2800
+ * ```
2801
+ */
2802
+ export declare function isSource(value: unknown): value is Source;
2803
+
2804
+ /**
2805
+ * Determine whether a value is a `Subject` — a plain record of fields to reason
2806
+ * about.
2807
+ *
2808
+ * @param value - The value to test
2809
+ * @returns `true` when `value` is a plain record (arrays and class instances fail)
2810
+ *
2811
+ * @example
2812
+ * ```ts
2813
+ * import { isSubject } from '@src/core'
2814
+ *
2815
+ * isSubject({ age: 30 }) // true
2816
+ * isSubject([1, 2, 3]) // false — an array is not a subject
2817
+ * ```
2818
+ */
2819
+ export declare const isSubject: Guard<Readonly<Record<string, unknown>>>;
2820
+
2821
+ /**
2822
+ * Determine whether a value is a `SubjectBuilder` ENTITY — the brand-guarded
2823
+ * stateful workspace, not the plain {@link Subject} data record.
2824
+ *
2825
+ * @remarks
2826
+ * A `unique symbol` brand check (`Reflect.get`, AGENTS §14), distinct from
2827
+ * {@link isDefinitionBuilder} — the two entities can never match each other's
2828
+ * guard. Total: a non-object, a missing brand, or a hostile prototype all
2829
+ * return `false`, never throw.
2830
+ *
2831
+ * @param value - The value to test
2832
+ * @returns `true` when `value` carries the `SubjectBuilder` entity brand
2833
+ *
2834
+ * @example
2835
+ * ```ts
2836
+ * import { createSubjectBuilder, isSubjectBuilder } from '@src/core'
2837
+ *
2838
+ * const subject = createSubjectBuilder({ id: 's1', age: 30 })
2839
+ * isSubjectBuilder(subject) // true
2840
+ * isSubjectBuilder({ build: () => ({}) }) // false — forged build field
2841
+ * isSubjectBuilder({ id: 's1', age: 30 }) // false — plain data, not the entity
2842
+ * ```
2843
+ */
2844
+ export declare function isSubjectBuilder(value: unknown): value is SubjectBuilderInterface;
2845
+
2846
+ /**
2847
+ * Determine whether a value is a {@link SymbolicDefinition}.
2848
+ *
2849
+ * @param value - The value to test
2850
+ * @returns `true` when `value` is a well-formed symbolic definition
2851
+ *
2852
+ * @example
2853
+ * ```ts
2854
+ * import { isSymbolicDefinition, symbolicDefinition } from '@src/core'
2855
+ *
2856
+ * isSymbolicDefinition(symbolicDefinition('rate', 'Rate', [])) // true
2857
+ * isSymbolicDefinition({ reasoning: 'symbolic', id: 'rate' }) // false
2858
+ * ```
2859
+ */
2860
+ export declare function isSymbolicDefinition(value: unknown): value is SymbolicDefinition;
2861
+
2862
+ /**
2863
+ * Determine whether a value is a {@link SymbolicExpression} — an algebraic
2864
+ * expression tree of variables, constants, and operations, discriminated by
2865
+ * `form`.
2866
+ *
2867
+ * @remarks
2868
+ * Recursive through `lazyOf` (AGENTS §14) — recursion is STACK-BOUNDED, not
2869
+ * unbounded: nesting beyond the engine's stack budget (roughly 1000 levels)
2870
+ * and cyclic input are CONTAINED as `false`, never a throw. Input past that
2871
+ * bound is rejected, not validated.
2872
+ *
2873
+ * @param value - The value to test
2874
+ * @returns `true` when `value` is a well-formed symbolic expression tree
2875
+ *
2876
+ * @example
2877
+ * ```ts
2878
+ * import { constant, isSymbolicExpression, operation, variable } from '@src/core'
2879
+ *
2880
+ * isSymbolicExpression(operation('add', variable('x'), constant(1))) // true
2881
+ * isSymbolicExpression({ form: 'variable' }) // false — name missing
2882
+ * ```
2883
+ */
2884
+ export declare function isSymbolicExpression(value: unknown): value is SymbolicExpression;
2885
+
2886
+ /**
2887
+ * Determine whether a value is a {@link Transform} — one math step.
2888
+ *
2889
+ * @param value - The value to test
2890
+ * @returns `true` when `value` is a well-formed transform
2891
+ *
2892
+ * @example
2893
+ * ```ts
2894
+ * import { isTransform } from '@src/core'
2895
+ *
2896
+ * isTransform({ operation: 'multiply', operand: 2 }) // true
2897
+ * isTransform({ operation: 'round' }) // true — operand is optional
2898
+ * isTransform({ operation: 'multiply', by: 2 }) // false — extra key
2899
+ * ```
2900
+ */
2901
+ export declare function isTransform(value: unknown): value is Transform;
2902
+
2903
+ /** Default `id` for a `LogicalReasoner`. */
2904
+ export declare const LOGICAL_ID = "logical";
2905
+
2906
+ /**
2907
+ * A logical (rule-based deduction) definition.
2908
+ *
2909
+ * @remarks
2910
+ * `strategy` picks forward fixpoint chaining or backward goal-driven proving;
2911
+ * `depth` caps forward iterations / backward recursion (default `10`).
2912
+ */
2913
+ export declare interface LogicalDefinition {
2914
+ readonly reasoning: 'logical';
2915
+ readonly id: string;
2916
+ readonly name: string;
2917
+ readonly description?: string;
2918
+ readonly rules: readonly Rule[];
2919
+ readonly strategy: ChainingStrategy;
2920
+ readonly depth?: number;
2921
+ }
2922
+
2923
+ /**
2924
+ * Build a {@link LogicalDefinition}.
2925
+ *
2926
+ * @remarks
2927
+ * `strategy` defaults to `'forward'`; set `strategy`, `description`, or `depth`
2928
+ * through `overrides`.
2929
+ *
2930
+ * @param id - The definition id
2931
+ * @param name - The display name
2932
+ * @param rules - The deduction rules
2933
+ * @param overrides - Optional {@link LogicalDefinition} fields merged over the defaults
2934
+ * @returns A fresh logical definition
2935
+ *
2936
+ * @example
2937
+ * ```ts
2938
+ * import { atom, logicalDefinition, rule } from '@src/core'
2939
+ *
2940
+ * logicalDefinition('eligibility', 'Eligibility', [
2941
+ * rule('adult', [atom('age', 'from', 18)], atom('adult', 'equals', true)),
2942
+ * ])
2943
+ * ```
2944
+ */
2945
+ export declare function logicalDefinition(id: string, name: string, rules: readonly Rule[], overrides?: Partial<Omit<LogicalDefinition, 'reasoning' | 'id' | 'name' | 'rules'>>): LogicalDefinition;
2946
+
2947
+ /**
2948
+ * A logical connective inside a compound {@link Expression}.
2949
+ *
2950
+ * @remarks
2951
+ * `not` reads only its first operand (empty operands are vacuously true);
2952
+ * `implies` and `xor` read their first two (`implies` is vacuously true below
2953
+ * two operands, `xor` is false).
2954
+ */
2955
+ export declare type LogicalOperator = 'and' | 'or' | 'not' | 'implies' | 'xor';
2956
+
2957
+ /**
2958
+ * The logical reasoner — rule-based boolean deduction with forward or backward
2959
+ * chaining.
2960
+ *
2961
+ * @remarks
2962
+ * Forward chaining is a naive fixpoint capped at `depth` iterations: rules run
2963
+ * in ascending `priority` order each pass, and a firing rule's conclusion atoms
2964
+ * become a derived overlay that SHADOWS same-named subject fields on later
2965
+ * passes (derived keys are `formatField(check.field)` strings). Convergence —
2966
+ * one full pass with no new derivation — appends a trace containing
2967
+ * `converged`. Final rule results re-evaluate against the settled overlay in
2968
+ * ORIGINAL rule order (forward) / priority-sorted order (backward), and the
2969
+ * overall `conclusion` is the LAST result's conclusion. Backward chaining
2970
+ * proves EVERY rule goal-first: an unmet premise triggers sub-goal search
2971
+ * through rules whose conclusion atoms assert the needed `field = value` pair,
2972
+ * guarded by a visited-rule set (cycle-safe) plus the depth cap; `not` succeeds
2973
+ * when its operand cannot be established (negation-as-failure) and `implies` is
2974
+ * vacuously true on an unprovable antecedent. Expression evaluation is EAGER
2975
+ * (no short-circuit); conclusion extraction IGNORES connectives — every atom
2976
+ * inside a conclusion is asserted, even under `not` / `or`. Overlay bookkeeping
2977
+ * compares with SameValueZero (`equalValues`), so a NaN-valued conclusion
2978
+ * derives once and the fixpoint converges. Nothing mutates its inputs; fully
2979
+ * deterministic (AGENTS §11).
2980
+ */
2981
+ export declare class LogicalReasoner implements ReasonerInterface {
2982
+ #private;
2983
+ constructor(options?: LogicalReasonerOptions);
2984
+ get id(): string;
2985
+ get reasoning(): Reasoning;
2986
+ supports(definition: Definition): boolean;
2987
+ validate(definition: Definition): ReasonValidationResult;
2988
+ reason(subject: Subject, definition: Definition): ReasonResult;
2989
+ }
2990
+
2991
+ /**
2992
+ * Options for `createLogicalReasoner` / the `LogicalReasoner` constructor.
2993
+ *
2994
+ * @remarks
2995
+ * `id` — the reasoner's identity string (defaults to `LOGICAL_ID`).
2996
+ * `evaluator` — the injectable check evaluator (defaults to a fresh
2997
+ * default-constructed instance).
2998
+ */
2999
+ export declare interface LogicalReasonerOptions {
3000
+ readonly id?: string;
3001
+ readonly evaluator?: EvaluatorInterface;
3002
+ }
3003
+
3004
+ /**
3005
+ * The outcome of logical reasoning.
3006
+ *
3007
+ * @remarks
3008
+ * `conclusion` is the LAST evaluated rule's conclusion (`false` when no rule
3009
+ * was evaluated); `count` tallies the applied rules; disabled rules are
3010
+ * omitted from `rules` entirely.
3011
+ */
3012
+ export declare interface LogicalResult {
3013
+ readonly reasoning: 'logical';
3014
+ readonly conclusion: boolean;
3015
+ readonly rules: readonly RuleResult[];
3016
+ readonly count: number;
3017
+ readonly success: boolean;
3018
+ readonly trace: readonly string[];
3019
+ readonly errors: readonly string[];
3020
+ }
3021
+
3022
+ /**
3023
+ * Build a {@link Factor} over a lookup {@link Source}.
3024
+ *
3025
+ * @param id - The factor id
3026
+ * @param field - The subject field to resolve (stringified into a table key)
3027
+ * @param table - The lookup table
3028
+ * @param overrides - Optional {@link Factor} fields merged over the defaults
3029
+ * @returns A fresh factor
3030
+ *
3031
+ * @example
3032
+ * ```ts
3033
+ * import { lookupFactor } from '@src/core'
3034
+ *
3035
+ * lookupFactor('state-score', 'state', { CA: 5, NY: 8 }, { fallback: 1 })
3036
+ * ```
3037
+ */
3038
+ export declare function lookupFactor(id: string, field: FieldPath, table: Readonly<Record<string, number>>, overrides?: Partial<Omit<Factor, 'id' | 'source'>>): Factor;
3039
+
3040
+ /**
3041
+ * A factor source mapping a subject field through a lookup table.
3042
+ *
3043
+ * @remarks
3044
+ * A missing or `null` field takes the factor's `fallback` directly (never the
3045
+ * `''` table key); a PRESENT value is stringified into a `table` key (a numeric
3046
+ * `42` finds the key `'42'`, a real `''` value may hit a `''` key). Only OWN
3047
+ * table keys hit — an absent or inherited key falls back.
3048
+ */
3049
+ export declare interface LookupSource {
3050
+ readonly origin: 'lookup';
3051
+ readonly field: FieldPath;
3052
+ readonly table: Readonly<Record<string, number>>;
3053
+ }
3054
+
3055
+ /**
3056
+ * Build a lookup {@link Source} — a subject field mapped through a table.
3057
+ *
3058
+ * @param field - The subject field to resolve (stringified into a table key)
3059
+ * @param table - The lookup table
3060
+ * @returns A fresh lookup source
3061
+ *
3062
+ * @example
3063
+ * ```ts
3064
+ * import { lookupSource } from '@src/core'
3065
+ *
3066
+ * lookupSource('state', { CA: 5, NY: 8, TX: 2 })
3067
+ * ```
3068
+ */
3069
+ export declare function lookupSource(field: FieldPath, table: Readonly<Record<string, number>>): Source;
3070
+
3071
+ /**
3072
+ * Positionally unify a pattern fact against a candidate fact — returning the
3073
+ * variable bindings on success, `undefined` on mismatch.
3074
+ *
3075
+ * @remarks
3076
+ * The bidirectional unification of the inferential reasoner: a `'?'`-prefixed
3077
+ * string term on EITHER side (pattern or candidate) is a variable that binds to
3078
+ * the opposite term (the `'?'` prefix is kept in the binding key), while
3079
+ * consistency is enforced within the match — a variable seen twice must bind the
3080
+ * SAME value (raw `!==`) or the whole match fails. A predicate mismatch or an
3081
+ * arity (term-count) mismatch fails immediately; non-variable terms must be
3082
+ * strictly (`===`) equal.
3083
+ *
3084
+ * @param pattern - The pattern fact (may carry `'?'` variables)
3085
+ * @param candidate - The candidate fact to unify against (may also carry `'?'` variables)
3086
+ * @returns A fresh bindings record, or `undefined` when they do not unify
3087
+ *
3088
+ * @example
3089
+ * ```ts
3090
+ * import { fact, matchFacts } from '@src/core'
3091
+ *
3092
+ * matchFacts(fact('p', 'parent', ['?x', 'bob']), fact('f', 'parent', ['alice', 'bob'])) // { '?x': 'alice' }
3093
+ * matchFacts(fact('p', 'parent', ['?x']), fact('f', 'human', ['x'])) // undefined — predicate
3094
+ * ```
3095
+ */
3096
+ export declare function matchFacts(pattern: Fact, candidate: Fact): Record<string, unknown> | undefined;
3097
+
3098
+ /**
3099
+ * A math operation applied by the {@link TransformerInterface} and inside
3100
+ * {@link SymbolicExpression} trees.
3101
+ *
3102
+ * @remarks
3103
+ * `round` / `ceil` / `floor` / `abs` are unary — they ignore the operand /
3104
+ * right side. All others are binary.
3105
+ */
3106
+ export declare type MathOperation = 'add' | 'subtract' | 'multiply' | 'divide' | 'percentage' | 'minimum' | 'maximum' | 'average' | 'power' | 'round' | 'ceil' | 'floor' | 'abs';
3107
+
3108
+ /**
3109
+ * Reconcile two id-keyed collections — an incoming-order upsert with
3110
+ * base-only survivors appended after.
3111
+ *
3112
+ * @remarks
3113
+ * The Strategic-Merge-Patch-style id-keyed upsert of PROPOSAL.md §6-§7:
3114
+ * the result is ordered by `incoming`'s id order FIRST (each element resolved
3115
+ * through `resolve` when its id also exists in `base`, defaulting to
3116
+ * incoming-wins-wholesale), THEN the `base`-only survivors in `base`'s own
3117
+ * order (retained, never deleted — merge is additive). Same-id twins within
3118
+ * EITHER input are deduped to their first occurrence.
3119
+ *
3120
+ * @typeParam T - An id-carrying element type
3121
+ * @param base - The base collection
3122
+ * @param incoming - The incoming collection (its order and matches take priority)
3123
+ * @param resolve - How to reconcile a matched (same-id) pair; defaults to keeping the incoming element wholesale
3124
+ * @returns A fresh, deduped, incoming-ordered-then-base-survivors array
3125
+ *
3126
+ * @example
3127
+ * ```ts
3128
+ * import { mergeById } from '@src/core'
3129
+ *
3130
+ * mergeById([{ id: 'a', v: 1 }, { id: 'b', v: 2 }], [{ id: 'a', v: 9 }])
3131
+ * // [{ id: 'a', v: 9 }, { id: 'b', v: 2 }] — incoming order first, base-only survivor after
3132
+ * ```
3133
+ */
3134
+ export declare function mergeById<T extends {
3135
+ readonly id: string;
3136
+ }>(base: readonly T[], incoming: readonly T[], resolve?: (base: T, incoming: T) => T): readonly T[];
3137
+
3138
+ /**
3139
+ * Reconcile two {@link InferentialDefinition}s onto `base`'s id.
3140
+ *
3141
+ * @remarks
3142
+ * `inferences` and `facts` each merge via {@link mergeById}
3143
+ * (incoming-wins-wholesale on a matched id). Every other scalar field is
3144
+ * incoming-wins-when-present, else base kept.
3145
+ *
3146
+ * @param base - The definition merge targets (its `id` is preserved)
3147
+ * @param incoming - The definition merged in (its order and matches take priority)
3148
+ * @returns A fresh, reconciled definition
3149
+ *
3150
+ * @example
3151
+ * ```ts
3152
+ * import { fact, inferentialDefinition, mergeInferentialDefinition } from '@src/core'
3153
+ *
3154
+ * const base = inferentialDefinition('m', 'M', [fact('f1', 'human', ['a'])], [])
3155
+ * const incoming = inferentialDefinition('m', 'M2', [fact('f2', 'human', ['b'])], [])
3156
+ * mergeInferentialDefinition(base, incoming).facts.map((f) => f.id) // ['f2', 'f1']
3157
+ * ```
3158
+ */
3159
+ export declare function mergeInferentialDefinition(base: InferentialDefinition, incoming: InferentialDefinition): InferentialDefinition;
3160
+
3161
+ /**
3162
+ * Reconcile two {@link LogicalDefinition}s onto `base`'s id.
3163
+ *
3164
+ * @remarks
3165
+ * `rules` merges via {@link mergeById} (incoming-wins-wholesale on a matched
3166
+ * id). Every other scalar field is incoming-wins-when-present, else base kept.
3167
+ *
3168
+ * @param base - The definition merge targets (its `id` is preserved)
3169
+ * @param incoming - The definition merged in (its order and matches take priority)
3170
+ * @returns A fresh, reconciled definition
3171
+ *
3172
+ * @example
3173
+ * ```ts
3174
+ * import { atom, logicalDefinition, mergeLogicalDefinition, rule } from '@src/core'
3175
+ *
3176
+ * const base = logicalDefinition('e', 'E', [rule('r1', [], atom('a', 'equals', true))])
3177
+ * const incoming = logicalDefinition('e', 'E2', [rule('r2', [], atom('b', 'equals', true))])
3178
+ * mergeLogicalDefinition(base, incoming).rules.map((r) => r.id) // ['r2', 'r1']
3179
+ * ```
3180
+ */
3181
+ export declare function mergeLogicalDefinition(base: LogicalDefinition, incoming: LogicalDefinition): LogicalDefinition;
3182
+
3183
+ /**
3184
+ * Reconcile two {@link QuantitativeDefinition}s onto `base`'s id.
3185
+ *
3186
+ * @remarks
3187
+ * `groups` merges via {@link mergeById}; a matched (same-id) PAIR of groups
3188
+ * recurses one level deeper — their `factors` also merge via `mergeById` — the
3189
+ * one exception to incoming-wins-wholesale (PROPOSAL.md §9). Every other
3190
+ * scalar / value-object field is incoming-wins-when-present, else base kept.
3191
+ *
3192
+ * @param base - The definition merge targets (its `id` is preserved)
3193
+ * @param incoming - The definition merged in (its order and matches take priority)
3194
+ * @returns A fresh, reconciled definition
3195
+ *
3196
+ * @example
3197
+ * ```ts
3198
+ * import { factorGroup, mergeQuantitativeDefinition, quantitativeDefinition } from '@src/core'
3199
+ *
3200
+ * const base = quantitativeDefinition('risk', 'Risk', [factorGroup('g1', 'sum', [])])
3201
+ * const incoming = quantitativeDefinition('risk', 'Risk v2', [factorGroup('g2', 'sum', [])])
3202
+ * mergeQuantitativeDefinition(base, incoming).groups.map((g) => g.id) // ['g2', 'g1']
3203
+ * ```
3204
+ */
3205
+ export declare function mergeQuantitativeDefinition(base: QuantitativeDefinition, incoming: QuantitativeDefinition): QuantitativeDefinition;
3206
+
3207
+ /**
3208
+ * Reconcile two {@link Subject}s — incoming-wins spread, with the base `id`
3209
+ * preserved when present.
3210
+ *
3211
+ * @remarks
3212
+ * Mirrors the definition merge's base-id-wins rule: `{ ...base, ...incoming }`
3213
+ * with `base.id` restored afterward when `base` carries an own `id`.
3214
+ *
3215
+ * @param base - The subject merge targets (its `id` is preserved when present)
3216
+ * @param incoming - The subject merged in (its fields take priority)
3217
+ * @returns A fresh, reconciled subject
3218
+ *
3219
+ * @example
3220
+ * ```ts
3221
+ * import { mergeSubjects } from '@src/core'
3222
+ *
3223
+ * mergeSubjects({ id: 's1', age: 30 }, { age: 31, name: 'Alice' })
3224
+ * // { id: 's1', age: 31, name: 'Alice' }
3225
+ * ```
3226
+ */
3227
+ export declare function mergeSubjects(base: Subject, incoming: Subject): Subject;
3228
+
3229
+ /**
3230
+ * Reconcile two {@link SymbolicDefinition}s onto `base`'s id.
3231
+ *
3232
+ * @remarks
3233
+ * `equations` merges via {@link mergeById} (incoming-wins-wholesale on a
3234
+ * matched id); `variables` is a plain incoming-wins spread
3235
+ * (`{ ...base.variables, ...incoming.variables }`). Every other scalar field
3236
+ * is incoming-wins-when-present, else base kept.
3237
+ *
3238
+ * @param base - The definition merge targets (its `id` is preserved)
3239
+ * @param incoming - The definition merged in (its order, matches, and variables take priority)
3240
+ * @returns A fresh, reconciled definition
3241
+ *
3242
+ * @example
3243
+ * ```ts
3244
+ * import { constant, equation, mergeSymbolicDefinition, symbolicDefinition, variable } from '@src/core'
3245
+ *
3246
+ * const base = symbolicDefinition('e', 'E', [], { variables: { x: 1 } })
3247
+ * const incoming = symbolicDefinition('e', 'E2', [equation('e1', variable('x'), constant(2), 'x')], {
3248
+ * variables: { y: 2 },
3249
+ * })
3250
+ * mergeSymbolicDefinition(base, incoming).variables // { x: 1, y: 2 }
3251
+ * ```
3252
+ */
3253
+ export declare function mergeSymbolicDefinition(base: SymbolicDefinition, incoming: SymbolicDefinition): SymbolicDefinition;
3254
+
3255
+ /**
3256
+ * A symbolic operation node.
3257
+ *
3258
+ * @remarks
3259
+ * `right` is absent for unary operators (`round` / `ceil` / `floor` / `abs`)
3260
+ * and treated as the constant `0` when absent on a binary operator.
3261
+ */
3262
+ export declare interface Operation {
3263
+ readonly form: 'operation';
3264
+ readonly operator: MathOperation;
3265
+ readonly left: SymbolicExpression;
3266
+ readonly right?: SymbolicExpression;
3267
+ }
3268
+
3269
+ /**
3270
+ * Build an operation {@link SymbolicExpression} node.
3271
+ *
3272
+ * @remarks
3273
+ * The `right` key is OMITTED when absent — correct for the unary operations
3274
+ * (`round` / `ceil` / `floor` / `abs`); a binary operation with no `right`
3275
+ * treats it as the constant `0`.
3276
+ *
3277
+ * @param operator - The math operation
3278
+ * @param left - The left operand
3279
+ * @param right - The right operand (omit for unary operations)
3280
+ * @returns A fresh operation node
3281
+ *
3282
+ * @example
3283
+ * ```ts
3284
+ * import { constant, operation, variable } from '@src/core'
3285
+ *
3286
+ * operation('add', variable('x'), constant(1))
3287
+ * operation('abs', variable('x')) // unary — no right operand
3288
+ * ```
3289
+ */
3290
+ export declare const operation: (operator: MathOperation, left: SymbolicExpression, right?: SymbolicExpression) => SymbolicExpression;
3291
+
3292
+ /**
3293
+ * Parse a JSON string into a {@link Definition}, failing safe to `undefined`.
3294
+ *
3295
+ * @remarks
3296
+ * The safe inverse of the builders: `parseJSONAs` composed with the data guard
3297
+ * {@link isDefinition}. A built definition body IS the durable JSON payload —
3298
+ * `JSON.stringify(definition)` round-trips through `parseDefinition`. Two
3299
+ * authoring hazards: a required `Check.value: undefined` drops its key on
3300
+ * `JSON.stringify` (author `null` instead), and a `Fact.terms` element of
3301
+ * `undefined` serializes to `null` (terms must be JSON-safe scalars/strings).
3302
+ *
3303
+ * @param json - The JSON text to parse
3304
+ * @returns A {@link Definition} of any reasoning, or `undefined` when malformed
3305
+ *
3306
+ * @example
3307
+ * ```ts
3308
+ * import { logicalDefinition, parseDefinition } from '@src/core'
3309
+ *
3310
+ * const text = JSON.stringify(logicalDefinition('e', 'E', []))
3311
+ * parseDefinition(text) // the definition, restored
3312
+ * parseDefinition('{}') // undefined — fails safe
3313
+ * ```
3314
+ */
3315
+ export declare function parseDefinition(json: string): Definition | undefined;
3316
+
3317
+ /**
3318
+ * Insert `item` into an id-keyed collection, deduping any existing element
3319
+ * sharing its id, then placing it at the START (or immediately BEFORE `target`).
3320
+ *
3321
+ * @remarks
3322
+ * Mirrors {@link appendById}'s dedup-then-insert semantics exactly, only the
3323
+ * placement differs: no `target` lands `item` at the start; a `target` lands
3324
+ * it immediately before the element whose `id === target` (searched in the
3325
+ * deduped array). A `target` naming no element throws {@link ReasonError}
3326
+ * (`'TARGET'`).
3327
+ *
3328
+ * @typeParam T - An id-carrying element type
3329
+ * @param items - The collection to insert into
3330
+ * @param item - The element to insert
3331
+ * @param target - Optional id to insert immediately before; prepends at the start when absent
3332
+ * @returns A fresh array with `item` inserted
3333
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no element in `items`
3334
+ *
3335
+ * @example
3336
+ * ```ts
3337
+ * import { prependById } from '@src/core'
3338
+ *
3339
+ * prependById([{ id: 'a' }, { id: 'b' }], { id: 'c' }) // [c, a, b]
3340
+ * prependById([{ id: 'a' }, { id: 'b' }], { id: 'c' }, 'b') // [a, c, b]
3341
+ * ```
3342
+ */
3343
+ export declare function prependById<T extends {
3344
+ readonly id: string;
3345
+ }>(items: readonly T[], item: T, target?: string): readonly T[];
3346
+
3347
+ /**
3348
+ * Insert `equation` into a {@link SymbolicDefinition}'s `equations` — dedup-
3349
+ * then-insert at the start, or immediately before `target`.
3350
+ *
3351
+ * @param definition - The definition to insert into
3352
+ * @param source - The equation to insert
3353
+ * @param target - Optional equation id to insert immediately before
3354
+ * @returns A fresh definition with `equation` inserted
3355
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing equation
3356
+ *
3357
+ * @example
3358
+ * ```ts
3359
+ * import { constant, equation, prependEquation, symbolicDefinition, variable } from '@src/core'
3360
+ *
3361
+ * prependEquation(symbolicDefinition('e', 'E', []), equation('e1', variable('x'), constant(1), 'x'))
3362
+ * ```
3363
+ */
3364
+ export declare function prependEquation(definition: SymbolicDefinition, source: Equation, target?: string): SymbolicDefinition;
3365
+
3366
+ /**
3367
+ * Insert `fact` into an {@link InferentialDefinition}'s `facts` — dedup-then-
3368
+ * insert at the start, or immediately before `target`.
3369
+ *
3370
+ * @param definition - The definition to insert into
3371
+ * @param source - The fact to insert
3372
+ * @param target - Optional fact id to insert immediately before
3373
+ * @returns A fresh definition with `fact` inserted
3374
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing fact
3375
+ *
3376
+ * @example
3377
+ * ```ts
3378
+ * import { fact, inferentialDefinition, prependFact } from '@src/core'
3379
+ *
3380
+ * prependFact(inferentialDefinition('m', 'M', [], []), fact('f1', 'human', ['socrates']))
3381
+ * ```
3382
+ */
3383
+ export declare function prependFact(definition: InferentialDefinition, source: Fact, target?: string): InferentialDefinition;
3384
+
3385
+ /**
3386
+ * Insert `factor` into a {@link FactorGroup}'s `factors` — dedup-then-insert
3387
+ * at the start, or immediately before `target`.
3388
+ *
3389
+ * @param group - The group to insert into
3390
+ * @param factor - The factor to insert
3391
+ * @param target - Optional factor id to insert immediately before
3392
+ * @returns A fresh group with `factor` inserted
3393
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing factor
3394
+ *
3395
+ * @example
3396
+ * ```ts
3397
+ * import { factorGroup, prependFactor, staticFactor } from '@src/core'
3398
+ *
3399
+ * prependFactor(factorGroup('g1', 'sum', []), staticFactor('f1', 10))
3400
+ * ```
3401
+ */
3402
+ export declare function prependFactor(group: FactorGroup, factor: Factor, target?: string): FactorGroup;
3403
+
3404
+ /**
3405
+ * Insert `group` into a {@link QuantitativeDefinition}'s `groups` — dedup-then-
3406
+ * insert at the start, or immediately before `target`.
3407
+ *
3408
+ * @param definition - The definition to insert into
3409
+ * @param group - The group to insert
3410
+ * @param target - Optional group id to insert immediately before
3411
+ * @returns A fresh definition with `group` inserted
3412
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing group
3413
+ *
3414
+ * @example
3415
+ * ```ts
3416
+ * import { factorGroup, prependGroup, quantitativeDefinition } from '@src/core'
3417
+ *
3418
+ * prependGroup(quantitativeDefinition('risk', 'Risk', []), factorGroup('g1', 'sum', []))
3419
+ * ```
3420
+ */
3421
+ export declare function prependGroup(definition: QuantitativeDefinition, group: FactorGroup, target?: string): QuantitativeDefinition;
3422
+
3423
+ /**
3424
+ * Insert `inference` into an {@link InferentialDefinition}'s `inferences` —
3425
+ * dedup-then-insert at the start, or immediately before `target`.
3426
+ *
3427
+ * @param definition - The definition to insert into
3428
+ * @param source - The inference to insert
3429
+ * @param target - Optional inference id to insert immediately before
3430
+ * @returns A fresh definition with `inference` inserted
3431
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing inference
3432
+ *
3433
+ * @example
3434
+ * ```ts
3435
+ * import { fact, inference, inferentialDefinition, prependInference } from '@src/core'
3436
+ *
3437
+ * prependInference(
3438
+ * inferentialDefinition('m', 'M', [], []),
3439
+ * inference('i1', [fact('p', 'human', ['?x'])], fact('c', 'mortal', ['?x'])),
3440
+ * )
3441
+ * ```
3442
+ */
3443
+ export declare function prependInference(definition: InferentialDefinition, source: Inference, target?: string): InferentialDefinition;
3444
+
3445
+ /**
3446
+ * Insert `rule` into a {@link LogicalDefinition}'s `rules` — dedup-then-insert
3447
+ * at the start, or immediately before `target`.
3448
+ *
3449
+ * @param definition - The definition to insert into
3450
+ * @param source - The rule to insert
3451
+ * @param target - Optional rule id to insert immediately before
3452
+ * @returns A fresh definition with `rule` inserted
3453
+ * @throws {@link ReasonError} `'TARGET'` when `target` names no existing rule
3454
+ *
3455
+ * @example
3456
+ * ```ts
3457
+ * import { atom, logicalDefinition, prependRule, rule } from '@src/core'
3458
+ *
3459
+ * prependRule(logicalDefinition('e', 'E', []), rule('r1', [], atom('a', 'equals', true)))
3460
+ * ```
3461
+ */
3462
+ export declare function prependRule(definition: LogicalDefinition, source: Rule, target?: string): LogicalDefinition;
3463
+
3464
+ /**
3465
+ * One node of a backward-chaining proof tree.
3466
+ *
3467
+ * @remarks
3468
+ * `fact` is the proved fact's / goal's id; `inference` is set when the node was
3469
+ * derived through an inference (absent on a base-fact leaf); `children` are the
3470
+ * sub-proofs of that inference's premises; `depth` is the recursion depth the
3471
+ * node was proved at.
3472
+ */
3473
+ export declare interface ProofNode {
3474
+ readonly fact: string;
3475
+ readonly inference?: string;
3476
+ readonly children?: readonly ProofNode[];
3477
+ readonly depth: number;
3478
+ }
3479
+
3480
+ /** Default `id` for a `QuantitativeReasoner`. */
3481
+ export declare const QUANTITATIVE_ID = "quantitative";
3482
+
3483
+ /**
3484
+ * A quantitative (factor-based numeric scoring) definition.
3485
+ *
3486
+ * @remarks
3487
+ * The final value is `base` (default `0`) plus the aggregation of the applied
3488
+ * groups' values (NO weights at this level), clamped to `bounds`, then rounded
3489
+ * to `precision` decimal places (default `4`).
3490
+ */
3491
+ export declare interface QuantitativeDefinition {
3492
+ readonly reasoning: 'quantitative';
3493
+ readonly id: string;
3494
+ readonly name: string;
3495
+ readonly description?: string;
3496
+ readonly groups: readonly FactorGroup[];
3497
+ readonly aggregation: Aggregation;
3498
+ readonly base?: number;
3499
+ readonly bounds?: Bounds;
3500
+ readonly precision?: number;
3501
+ }
3502
+
3503
+ /**
3504
+ * Build a {@link QuantitativeDefinition}.
3505
+ *
3506
+ * @remarks
3507
+ * `aggregation` defaults to `'sum'`; set `aggregation`, `description`, `base`,
3508
+ * `bounds`, or `precision` through `overrides`.
3509
+ *
3510
+ * @param id - The definition id
3511
+ * @param name - The display name
3512
+ * @param groups - The factor groups
3513
+ * @param overrides - Optional {@link QuantitativeDefinition} fields merged over the defaults
3514
+ * @returns A fresh quantitative definition
3515
+ *
3516
+ * @example
3517
+ * ```ts
3518
+ * import { factorGroup, fieldFactor, quantitativeDefinition } from '@src/core'
3519
+ *
3520
+ * quantitativeDefinition('risk', 'Risk Score', [factorGroup('g1', 'sum', [fieldFactor('age', 'age')])], {
3521
+ * base: 100,
3522
+ * })
3523
+ * ```
3524
+ */
3525
+ export declare function quantitativeDefinition(id: string, name: string, groups: readonly FactorGroup[], overrides?: Partial<Omit<QuantitativeDefinition, 'reasoning' | 'id' | 'name' | 'groups'>>): QuantitativeDefinition;
3526
+
3527
+ /**
3528
+ * The quantitative reasoner — factor-based numeric scoring.
3529
+ *
3530
+ * @remarks
3531
+ * Each factor runs a fixed pipeline: checks gate (ALL met) → source resolve
3532
+ * (`fallback` when unresolvable) → finite check → transforms chain → bounds
3533
+ * clamp → finite recheck. Factors evaluate in stable ascending `priority`
3534
+ * order; a `strict` group is all-or-nothing; a group's value is its `base` plus
3535
+ * the weighted aggregation of its APPLIED factors, clamped (never rounded); the
3536
+ * definition's value is its `base` plus the unweighted aggregation of the
3537
+ * APPLIED groups' values, clamped, then rounded to `precision`. A
3538
+ * required-factor failure or non-finite value appends an error (`success:
3539
+ * false`) without aborting — the numeric `value` is always computed. The
3540
+ * definition-level value is finite-checked AFTER rounding: a non-finite
3541
+ * aggregate (a `minimum` / `maximum` over zero applied groups) appends an error
3542
+ * while the `NaN` stays visible in `value`. Field sources coerce through the
3543
+ * contracts `parseNumberField`: a non-finite subject number or a non-numeric
3544
+ * string is unresolvable and takes the fallback path. Lookup sources read only
3545
+ * OWN table keys, and a missing / `null` field falls back directly. Nothing
3546
+ * mutates its inputs; fully deterministic (AGENTS §11).
3547
+ */
3548
+ export declare class QuantitativeReasoner implements ReasonerInterface {
3549
+ #private;
3550
+ constructor(options?: QuantitativeReasonerOptions);
3551
+ get id(): string;
3552
+ get reasoning(): Reasoning;
3553
+ supports(definition: Definition): boolean;
3554
+ validate(definition: Definition): ReasonValidationResult;
3555
+ reason(subject: Subject, definition: Definition): ReasonResult;
3556
+ }
3557
+
3558
+ /**
3559
+ * Options for `createQuantitativeReasoner` / the `QuantitativeReasoner`
3560
+ * constructor.
3561
+ *
3562
+ * @remarks
3563
+ * `id` — the reasoner's identity string (defaults to `QUANTITATIVE_ID`).
3564
+ * `evaluator` / `transformer` / `aggregator` — injectable operators (each
3565
+ * defaults to a fresh default-constructed instance).
3566
+ */
3567
+ export declare interface QuantitativeReasonerOptions {
3568
+ readonly id?: string;
3569
+ readonly evaluator?: EvaluatorInterface;
3570
+ readonly transformer?: TransformerInterface;
3571
+ readonly aggregator?: AggregatorInterface;
3572
+ }
3573
+
3574
+ /**
3575
+ * The outcome of quantitative reasoning.
3576
+ *
3577
+ * @remarks
3578
+ * `count` tallies the applied groups. `success` is `false` whenever any error
3579
+ * accumulated (a required-factor failure, a non-finite value) — the numeric
3580
+ * `value` is still computed.
3581
+ */
3582
+ export declare interface QuantitativeResult {
3583
+ readonly reasoning: 'quantitative';
3584
+ readonly value: number;
3585
+ readonly groups: readonly GroupResult[];
3586
+ readonly count: number;
3587
+ readonly success: boolean;
3588
+ readonly trace: readonly string[];
3589
+ readonly errors: readonly string[];
3590
+ }
3591
+
3592
+ /**
3593
+ * Build a {@link Factor} over a range {@link Source}.
3594
+ *
3595
+ * @param id - The factor id
3596
+ * @param field - The subject field to resolve as a number
3597
+ * @param ranges - The bands, scanned in order (first match wins)
3598
+ * @param overrides - Optional {@link Factor} fields merged over the defaults
3599
+ * @returns A fresh factor
3600
+ *
3601
+ * @example
3602
+ * ```ts
3603
+ * import { bounds, rangeFactor } from '@src/core'
3604
+ *
3605
+ * rangeFactor('age-band', 'age', [{ bounds: bounds(undefined, 24), value: 30 }])
3606
+ * ```
3607
+ */
3608
+ export declare function rangeFactor(id: string, field: FieldPath, ranges: readonly FactorRange[], overrides?: Partial<Omit<Factor, 'id' | 'source'>>): Factor;
3609
+
3610
+ /**
3611
+ * A factor source banding a numeric subject field through ordered ranges.
3612
+ *
3613
+ * @remarks
3614
+ * Ranges are scanned in order and the FIRST match wins. A range without
3615
+ * `bounds` matches anything (a catch-all); an absent bound side is open. No
3616
+ * match falls back to the factor's `fallback`.
3617
+ */
3618
+ export declare interface RangeSource {
3619
+ readonly origin: 'range';
3620
+ readonly field: FieldPath;
3621
+ readonly ranges: readonly FactorRange[];
3622
+ }
3623
+
3624
+ /**
3625
+ * Build a range {@link Source} — a numeric subject field banded through ordered
3626
+ * ranges (first match wins).
3627
+ *
3628
+ * @param field - The subject field to resolve as a number
3629
+ * @param ranges - The bands, scanned in order
3630
+ * @returns A fresh range source
3631
+ *
3632
+ * @example
3633
+ * ```ts
3634
+ * import { bounds, rangeSource } from '@src/core'
3635
+ *
3636
+ * rangeSource('age', [
3637
+ * { bounds: bounds(undefined, 24), value: 30 },
3638
+ * { bounds: bounds(25, 64), value: 15 },
3639
+ * { bounds: bounds(65), value: 10 },
3640
+ * ])
3641
+ * ```
3642
+ */
3643
+ export declare function rangeSource(field: FieldPath, ranges: readonly FactorRange[]): Source;
3644
+
3645
+ /**
3646
+ * The reasoning orchestrator — a thin router over registered
3647
+ * {@link ReasonerInterface}s.
3648
+ *
3649
+ * @remarks
3650
+ * Holds NO strategy-specific logic: dispatch is purely a registry lookup by
3651
+ * `definition.reasoning` (one reasoner per reasoning; re-registration
3652
+ * replaces). A missing reasoner throws `MISSING` and a pre-run validation
3653
+ * failure (when the `validate` option is on) throws `INVALID` — both BYPASS
3654
+ * `bail` and emit nothing. A reasoner throw emits `error` with the raw thrown
3655
+ * value, then rethrows under `bail: true` (the default) or converts to a
3656
+ * type-shaped failure result under `bail: false`; only SUCCESSFUL results emit
3657
+ * `reason` (synchronously, before returning). The batch overload maps subjects
3658
+ * in order (validation, when on, repeats per subject). `destroy()` clears the
3659
+ * registry, emits `destroy`, then destroys the emitter LAST (AGENTS §13) and is
3660
+ * idempotent; every other method afterwards throws `DESTROYED` — only the
3661
+ * {@link emitter} getter keeps working.
3662
+ */
3663
+ export declare class Reason implements ReasonInterface {
3664
+ #private;
3665
+ constructor(options?: ReasonOptions);
3666
+ get emitter(): EmitterInterface<ReasonEventMap>;
3667
+ reason(subjects: readonly Subject[], definition: Definition): readonly ReasonResult[];
3668
+ reason(subject: Subject, definition: Definition): ReasonResult;
3669
+ register(reasoner: ReasonerInterface): void;
3670
+ reasoner(reasoning: Reasoning): ReasonerInterface | undefined;
3671
+ reasoners(): readonly ReasonerInterface[];
3672
+ supports(reasoning: Reasoning): boolean;
3673
+ validate(definition: Definition): ReasonValidationResult;
3674
+ destroy(): void;
3675
+ }
3676
+
3677
+ /**
3678
+ * A reasoning strategy adapter — one per {@link Reasoning}.
3679
+ *
3680
+ * @remarks
3681
+ * `reason` throws a `ReasonError` (`MISMATCH`) when handed a definition of a
3682
+ * different reasoning; every other malformation yields a failure RESULT, not a
3683
+ * throw — the runtime never assumes `validate` ran. `supports` / `validate` /
3684
+ * `reason` each take plain data only — a {@link DefinitionBuilderInterface} /
3685
+ * {@link SubjectBuilderInterface}'s `build()` output is passed instead, by the
3686
+ * caller.
3687
+ */
3688
+ export declare interface ReasonerInterface {
3689
+ readonly id: string;
3690
+ readonly reasoning: Reasoning;
3691
+ supports(definition: Definition): boolean;
3692
+ validate(definition: Definition): ReasonValidationResult;
3693
+ reason(subject: Subject, definition: Definition): ReasonResult;
3694
+ }
3695
+
3696
+ /**
3697
+ * An error thrown by the reasons layer.
3698
+ *
3699
+ * @remarks
3700
+ * Thrown for: dispatching a definition no registered reasoner handles
3701
+ * (`MISSING`), a pre-run validation failure when the orchestrator's `validate`
3702
+ * option is on (`INVALID`), handing a reasoner a definition of a different
3703
+ * reasoning (`MISMATCH`), any use of a destroyed orchestrator (`DESTROYED`),
3704
+ * and an `appendById` / `prependById` (or per-kind `append*` / `prepend*`)
3705
+ * `target` id naming no existing element (`TARGET`). `context`, when present,
3706
+ * carries the definition id and the reasoning involved (or, for `TARGET`, the
3707
+ * offending `id` / `target`).
3708
+ */
3709
+ export declare class ReasonError extends Error {
3710
+ readonly code: ReasonErrorCode;
3711
+ readonly context?: Readonly<Record<string, unknown>>;
3712
+ constructor(code: ReasonErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
3713
+ }
3714
+
3715
+ /**
3716
+ * A machine-readable `ReasonError` code.
3717
+ *
3718
+ * @remarks
3719
+ * `MISSING` — no reasoner registered for the definition's reasoning.
3720
+ * `INVALID` — pre-run validation failed (`validate: true`). `MISMATCH` — a
3721
+ * reasoner was handed a definition of a different reasoning. `DESTROYED` — the
3722
+ * orchestrator was used after `destroy()`. `TARGET` — a locator id names no
3723
+ * element that exists in the collection it addresses: an optional `target` id
3724
+ * passed to `appendById` / `prependById` (and the per-kind `append*` /
3725
+ * `prepend*` helpers built on them) that names no existing element.
3726
+ */
3727
+ export declare type ReasonErrorCode = 'MISSING' | 'INVALID' | 'MISMATCH' | 'DESTROYED' | 'TARGET';
3728
+
3729
+ /**
3730
+ * The push observation surface of a {@link ReasonInterface} (AGENTS §13).
3731
+ *
3732
+ * @remarks
3733
+ * `register` fires when a reasoner is registered (carrying its reasoning);
3734
+ * `reason` fires once per SUCCESSFUL result, synchronously before it returns
3735
+ * (bail-suppressed failure results do not fire it); `error` fires with the raw
3736
+ * thrown value when a reasoner throws (regardless of `bail`); `destroy` fires
3737
+ * once on teardown. Listener isolation is the emitter's own — a throwing
3738
+ * listener routes to the `error` OPTION handler, never onto this map.
3739
+ */
3740
+ export declare type ReasonEventMap = {
3741
+ /** A reasoner was registered — carries its reasoning. */
3742
+ readonly register: readonly [reasoning: Reasoning];
3743
+ /** A reasoning run succeeded — carries the produced result. */
3744
+ readonly reason: readonly [result: ReasonResult];
3745
+ /** A reasoner threw — carries the raw thrown value. */
3746
+ readonly error: readonly [error: unknown];
3747
+ /** The orchestrator was destroyed. */
3748
+ readonly destroy: readonly [];
3749
+ };
3750
+
3751
+ /**
3752
+ * The four reasoning strategies — the axis a {@link Definition} /
3753
+ * {@link ReasonResult} discriminates on.
3754
+ *
3755
+ * @remarks
3756
+ * `quantitative` — factor-based numeric scoring. `logical` — rule-based boolean
3757
+ * deduction with forward / backward chaining. `symbolic` — algebraic equation
3758
+ * solving by variable isolation. `inferential` — fact derivation with
3759
+ * unification variables and proof trees.
3760
+ */
3761
+ export declare type Reasoning = 'quantitative' | 'logical' | 'symbolic' | 'inferential';
3762
+
3763
+ /**
3764
+ * The reasoning orchestrator — a thin router over registered
3765
+ * {@link ReasonerInterface}s.
3766
+ *
3767
+ * @remarks
3768
+ * Dispatch is purely by `definition.reasoning` registry lookup; a missing
3769
+ * reasoner throws `MISSING` (never subject to `bail`, no `error` emit). The
3770
+ * batch `reason` overload maps subjects in order to an equal-length result
3771
+ * array. After `destroy()` every method except the `emitter` getter and
3772
+ * `destroy` itself throws `DESTROYED`. `reason` and `validate` each take
3773
+ * plain data only — a {@link DefinitionBuilderInterface} /
3774
+ * {@link SubjectBuilderInterface}'s `build()` output is passed instead, by
3775
+ * the caller.
3776
+ */
3777
+ export declare interface ReasonInterface {
3778
+ readonly emitter: EmitterInterface<ReasonEventMap>;
3779
+ reason(subjects: readonly Subject[], definition: Definition): readonly ReasonResult[];
3780
+ reason(subject: Subject, definition: Definition): ReasonResult;
3781
+ register(reasoner: ReasonerInterface): void;
3782
+ reasoner(reasoning: Reasoning): ReasonerInterface | undefined;
3783
+ reasoners(): readonly ReasonerInterface[];
3784
+ supports(reasoning: Reasoning): boolean;
3785
+ validate(definition: Definition): ReasonValidationResult;
3786
+ destroy(): void;
3787
+ }
3788
+
3789
+ /**
3790
+ * Options for `createReason` / the `Reason` constructor.
3791
+ *
3792
+ * @remarks
3793
+ * `reasoners` — the initial registry (a later entry of the same reasoning
3794
+ * replaces an earlier one). `bail` — when `true` (the default) a reasoner
3795
+ * throw is rethrown after the `error` emit; when `false` it becomes a failure
3796
+ * result. `validate` — when `true`, every `reason` call validates the
3797
+ * definition first and throws `INVALID` on failure (default `false`). `on` —
3798
+ * initial event listeners (AGENTS §8). `error` — the emitter's listener-error
3799
+ * handler (AGENTS §13).
3800
+ */
3801
+ export declare interface ReasonOptions {
3802
+ readonly reasoners?: readonly ReasonerInterface[];
3803
+ readonly bail?: boolean;
3804
+ readonly validate?: boolean;
3805
+ readonly on?: EmitterHooks<ReasonEventMap>;
3806
+ readonly error?: EmitterErrorHandler;
3807
+ }
3808
+
3809
+ /** Any reasoning result, discriminated by `reasoning`. */
3810
+ export declare type ReasonResult = QuantitativeResult | LogicalResult | SymbolicResult | InferentialResult;
3811
+
3812
+ /**
3813
+ * The outcome of validating a definition — hard `errors` (definition unusable)
3814
+ * and soft `warnings` (suspicious but runnable). `valid` is `true` exactly when
3815
+ * `errors` is empty.
3816
+ *
3817
+ * @remarks
3818
+ * Warnings cover empty collections, duplicate ids (`Duplicate <noun> id`),
3819
+ * inferential confidences outside `[0, 1]`, a logical conclusion's array-path
3820
+ * overlay key also read via an array-path premise elsewhere (the flat overlay
3821
+ * key will not resolve), and an inferential conclusion carrying a `?variable`
3822
+ * unbound by all of its inference's premises — the runtime stays permissive
3823
+ * about all of them.
3824
+ */
3825
+ export declare interface ReasonValidationResult {
3826
+ readonly valid: boolean;
3827
+ readonly errors: readonly string[];
3828
+ readonly warnings: readonly string[];
3829
+ }
3830
+
3831
+ /**
3832
+ * Filter every element sharing `id` out of an id-keyed collection.
3833
+ *
3834
+ * @remarks
3835
+ * An absent `id` yields a same-length fresh copy — a no-op, never a throw.
3836
+ *
3837
+ * @typeParam T - An id-carrying element type
3838
+ * @param items - The collection to remove from
3839
+ * @param id - The id to remove every occurrence of
3840
+ * @returns A fresh array with every `id`-matching element removed
3841
+ *
3842
+ * @example
3843
+ * ```ts
3844
+ * import { removeById } from '@src/core'
3845
+ *
3846
+ * removeById([{ id: 'a' }, { id: 'b' }], 'a') // [{ id: 'b' }]
3847
+ * removeById([{ id: 'a' }], 'z') // [{ id: 'a' }] — no-op
3848
+ * ```
3849
+ */
3850
+ export declare function removeById<T extends {
3851
+ readonly id: string;
3852
+ }>(items: readonly T[], id: string): readonly T[];
3853
+
3854
+ /**
3855
+ * Remove every equation sharing `id` from a {@link SymbolicDefinition} (no-op
3856
+ * when absent).
3857
+ *
3858
+ * @param definition - The definition to update
3859
+ * @param id - The equation id to remove
3860
+ * @returns A fresh definition with the equation removed
3861
+ *
3862
+ * @example
3863
+ * ```ts
3864
+ * import { constant, equation, removeEquation, symbolicDefinition, variable } from '@src/core'
3865
+ *
3866
+ * const definition = symbolicDefinition('e', 'E', [equation('e1', variable('x'), constant(1), 'x')])
3867
+ * removeEquation(definition, 'e1').equations // []
3868
+ * ```
3869
+ */
3870
+ export declare function removeEquation(definition: SymbolicDefinition, id: string): SymbolicDefinition;
3871
+
3872
+ /**
3873
+ * Remove every fact sharing `id` from an {@link InferentialDefinition} (no-op
3874
+ * when absent).
3875
+ *
3876
+ * @param definition - The definition to update
3877
+ * @param id - The fact id to remove
3878
+ * @returns A fresh definition with the fact removed
3879
+ *
3880
+ * @example
3881
+ * ```ts
3882
+ * import { fact, inferentialDefinition, removeFact } from '@src/core'
3883
+ *
3884
+ * const definition = inferentialDefinition('m', 'M', [fact('f1', 'human', ['socrates'])], [])
3885
+ * removeFact(definition, 'f1').facts // []
3886
+ * ```
3887
+ */
3888
+ export declare function removeFact(definition: InferentialDefinition, id: string): InferentialDefinition;
3889
+
3890
+ /**
3891
+ * Remove every factor sharing `id` from a {@link FactorGroup} (no-op when
3892
+ * absent).
3893
+ *
3894
+ * @param group - The group to update
3895
+ * @param id - The factor id to remove
3896
+ * @returns A fresh group with the factor removed
3897
+ *
3898
+ * @example
3899
+ * ```ts
3900
+ * import { factorGroup, removeFactor, staticFactor } from '@src/core'
3901
+ *
3902
+ * removeFactor(factorGroup('g1', 'sum', [staticFactor('f1', 10)]), 'f1').factors // []
3903
+ * ```
3904
+ */
3905
+ export declare function removeFactor(group: FactorGroup, id: string): FactorGroup;
3906
+
3907
+ /**
3908
+ * Delete one field of a {@link Subject} — destructure-rest omit.
3909
+ *
3910
+ * @remarks
3911
+ * The key is DELETED entirely (never set to `undefined`), keeping the result
3912
+ * exact-record valid. A no-op (fresh copy) when `key` is absent.
3913
+ *
3914
+ * @param subject - The subject to update
3915
+ * @param key - The field to delete
3916
+ * @returns A fresh subject with `key` omitted
3917
+ *
3918
+ * @example
3919
+ * ```ts
3920
+ * import { removeField } from '@src/core'
3921
+ *
3922
+ * removeField({ id: 's1', age: 30 }, 'age') // { id: 's1' }
3923
+ * ```
3924
+ */
3925
+ export declare function removeField(subject: Subject, key: string): Subject;
3926
+
3927
+ /**
3928
+ * Remove every group sharing `id` from a {@link QuantitativeDefinition}
3929
+ * (no-op when absent).
3930
+ *
3931
+ * @param definition - The definition to update
3932
+ * @param id - The group id to remove
3933
+ * @returns A fresh definition with the group removed
3934
+ *
3935
+ * @example
3936
+ * ```ts
3937
+ * import { factorGroup, quantitativeDefinition, removeGroup } from '@src/core'
3938
+ *
3939
+ * const definition = quantitativeDefinition('risk', 'Risk', [factorGroup('g1', 'sum', [])])
3940
+ * removeGroup(definition, 'g1').groups // []
3941
+ * ```
3942
+ */
3943
+ export declare function removeGroup(definition: QuantitativeDefinition, id: string): QuantitativeDefinition;
3944
+
3945
+ /**
3946
+ * Remove every inference sharing `id` from an {@link InferentialDefinition}
3947
+ * (no-op when absent).
3948
+ *
3949
+ * @param definition - The definition to update
3950
+ * @param id - The inference id to remove
3951
+ * @returns A fresh definition with the inference removed
3952
+ *
3953
+ * @example
3954
+ * ```ts
3955
+ * import { fact, inference, inferentialDefinition, removeInference } from '@src/core'
3956
+ *
3957
+ * const original = inference('i1', [fact('p', 'human', ['?x'])], fact('c', 'mortal', ['?x']))
3958
+ * removeInference(inferentialDefinition('m', 'M', [], [original]), 'i1').inferences // []
3959
+ * ```
3960
+ */
3961
+ export declare function removeInference(definition: InferentialDefinition, id: string): InferentialDefinition;
3962
+
3963
+ /**
3964
+ * Remove every rule sharing `id` from a {@link LogicalDefinition} (no-op when
3965
+ * absent).
3966
+ *
3967
+ * @param definition - The definition to update
3968
+ * @param id - The rule id to remove
3969
+ * @returns A fresh definition with the rule removed
3970
+ *
3971
+ * @example
3972
+ * ```ts
3973
+ * import { atom, logicalDefinition, removeRule, rule } from '@src/core'
3974
+ *
3975
+ * const definition = logicalDefinition('e', 'E', [rule('r1', [], atom('a', 'equals', true))])
3976
+ * removeRule(definition, 'r1').rules // []
3977
+ * ```
3978
+ */
3979
+ export declare function removeRule(definition: LogicalDefinition, id: string): LogicalDefinition;
3980
+
3981
+ /**
3982
+ * Remove one entry of a {@link SymbolicDefinition}'s `variables`.
3983
+ *
3984
+ * @remarks
3985
+ * The destructure-rest form OMITS the key entirely (never sets it to
3986
+ * `undefined`), keeping the result exact-record valid. A no-op (fresh copy)
3987
+ * when `name` is absent.
3988
+ *
3989
+ * @param definition - The definition to update
3990
+ * @param name - The variable name to remove
3991
+ * @returns A fresh definition with the variable removed
3992
+ *
3993
+ * @example
3994
+ * ```ts
3995
+ * import { removeVariable, symbolicDefinition } from '@src/core'
3996
+ *
3997
+ * removeVariable(symbolicDefinition('e', 'E', [], { variables: { x: 5 } }), 'x').variables // {}
3998
+ * ```
3999
+ */
4000
+ export declare function removeVariable(definition: SymbolicDefinition, name: string): SymbolicDefinition;
4001
+
4002
+ /**
4003
+ * Produce `count` deterministic clones of a {@link Subject}.
4004
+ *
4005
+ * @remarks
4006
+ * When `subject.id` is a string, each clone's id is minted
4007
+ * `` `${baseId}-${index}` `` (index from `0`); with no string `id`, the clones
4008
+ * pass through unchanged (still fresh copies). Pure and deterministic — the
4009
+ * same input always produces the same output (run-twice equality) — and does
4010
+ * NOT emit. `count <= 0` yields an empty array.
4011
+ *
4012
+ * @param subject - The subject to clone
4013
+ * @param count - How many clones to produce
4014
+ * @returns The `count`-long array of clones
4015
+ *
4016
+ * @example
4017
+ * ```ts
4018
+ * import { repeatSubject } from '@src/core'
4019
+ *
4020
+ * repeatSubject({ id: 's1', age: 30 }, 2) // [{ id: 's1-0', age: 30 }, { id: 's1-1', age: 30 }]
4021
+ * repeatSubject({ age: 30 }, 2) // [{ age: 30 }, { age: 30 }] — no id to mint from
4022
+ * ```
4023
+ */
4024
+ export declare function repeatSubject(subject: Subject, count: number): readonly Subject[];
4025
+
4026
+ /**
4027
+ * Swap the element sharing `item.id` IN PLACE, preserving its position.
4028
+ *
4029
+ * @remarks
4030
+ * The position-preserving update primitive — unlike {@link appendById}, which
4031
+ * repositions a re-inserted id to the end/target. Appends `item` at the end
4032
+ * when no same-id element exists (never throws).
4033
+ *
4034
+ * @typeParam T - An id-carrying element type
4035
+ * @param items - The collection to update
4036
+ * @param item - The replacement element
4037
+ * @returns A fresh array with the same-id element replaced (or `item` appended)
4038
+ *
4039
+ * @example
4040
+ * ```ts
4041
+ * import { replaceById } from '@src/core'
4042
+ *
4043
+ * replaceById([{ id: 'a', v: 1 }, { id: 'b', v: 2 }], { id: 'a', v: 9 }) // [{a,9}, {b,2}]
4044
+ * replaceById([{ id: 'a' }], { id: 'z' }) // [{a}, {z}] — appended
4045
+ * ```
4046
+ */
4047
+ export declare function replaceById<T extends {
4048
+ readonly id: string;
4049
+ }>(items: readonly T[], item: T): readonly T[];
4050
+
4051
+ /**
4052
+ * Swap the equation sharing `equation.id` in a {@link SymbolicDefinition} IN
4053
+ * PLACE, preserving its position (appends when absent).
4054
+ *
4055
+ * @param definition - The definition to update
4056
+ * @param source - The replacement equation
4057
+ * @returns A fresh definition with the equation replaced
4058
+ *
4059
+ * @example
4060
+ * ```ts
4061
+ * import { constant, equation, replaceEquation, symbolicDefinition, variable } from '@src/core'
4062
+ *
4063
+ * const definition = symbolicDefinition('e', 'E', [equation('e1', variable('x'), constant(1), 'x')])
4064
+ * replaceEquation(definition, equation('e1', variable('x'), constant(2), 'x'))
4065
+ * ```
4066
+ */
4067
+ export declare function replaceEquation(definition: SymbolicDefinition, source: Equation): SymbolicDefinition;
4068
+
4069
+ /**
4070
+ * Swap the fact sharing `fact.id` in an {@link InferentialDefinition} IN
4071
+ * PLACE, preserving its position (appends when absent).
4072
+ *
4073
+ * @param definition - The definition to update
4074
+ * @param source - The replacement fact
4075
+ * @returns A fresh definition with the fact replaced
4076
+ *
4077
+ * @example
4078
+ * ```ts
4079
+ * import { fact, inferentialDefinition, replaceFact } from '@src/core'
4080
+ *
4081
+ * const definition = inferentialDefinition('m', 'M', [fact('f1', 'human', ['socrates'])], [])
4082
+ * replaceFact(definition, fact('f1', 'human', ['plato']))
4083
+ * ```
4084
+ */
4085
+ export declare function replaceFact(definition: InferentialDefinition, source: Fact): InferentialDefinition;
4086
+
4087
+ /**
4088
+ * Swap the factor sharing `factor.id` in a {@link FactorGroup} IN PLACE,
4089
+ * preserving its position (appends when absent).
4090
+ *
4091
+ * @param group - The group to update
4092
+ * @param factor - The replacement factor
4093
+ * @returns A fresh group with the factor replaced
4094
+ *
4095
+ * @example
4096
+ * ```ts
4097
+ * import { factorGroup, replaceFactor, staticFactor } from '@src/core'
4098
+ *
4099
+ * const group = factorGroup('g1', 'sum', [staticFactor('f1', 10)])
4100
+ * replaceFactor(group, staticFactor('f1', 20))
4101
+ * ```
4102
+ */
4103
+ export declare function replaceFactor(group: FactorGroup, factor: Factor): FactorGroup;
4104
+
4105
+ /**
4106
+ * Swap the group sharing `group.id` in a {@link QuantitativeDefinition} IN
4107
+ * PLACE, preserving its position (appends when absent).
4108
+ *
4109
+ * @param definition - The definition to update
4110
+ * @param group - The replacement group
4111
+ * @returns A fresh definition with the group replaced
4112
+ *
4113
+ * @example
4114
+ * ```ts
4115
+ * import { factorGroup, quantitativeDefinition, replaceGroup } from '@src/core'
4116
+ *
4117
+ * const definition = quantitativeDefinition('risk', 'Risk', [factorGroup('g1', 'sum', [])])
4118
+ * replaceGroup(definition, factorGroup('g1', 'product', []))
4119
+ * ```
4120
+ */
4121
+ export declare function replaceGroup(definition: QuantitativeDefinition, group: FactorGroup): QuantitativeDefinition;
4122
+
4123
+ /**
4124
+ * Swap the inference sharing `inference.id` in an {@link InferentialDefinition}
4125
+ * IN PLACE, preserving its position (appends when absent).
4126
+ *
4127
+ * @param definition - The definition to update
4128
+ * @param source - The replacement inference
4129
+ * @returns A fresh definition with the inference replaced
4130
+ *
4131
+ * @example
4132
+ * ```ts
4133
+ * import { fact, inference, inferentialDefinition, replaceInference } from '@src/core'
4134
+ *
4135
+ * const original = inference('i1', [fact('p', 'human', ['?x'])], fact('c', 'mortal', ['?x']))
4136
+ * const definition = inferentialDefinition('m', 'M', [], [original])
4137
+ * replaceInference(definition, inference('i1', [], fact('c', 'mortal', ['?x'])))
4138
+ * ```
4139
+ */
4140
+ export declare function replaceInference(definition: InferentialDefinition, source: Inference): InferentialDefinition;
4141
+
4142
+ /**
4143
+ * Swap the rule sharing `rule.id` in a {@link LogicalDefinition} IN PLACE,
4144
+ * preserving its position (appends when absent).
4145
+ *
4146
+ * @param definition - The definition to update
4147
+ * @param source - The replacement rule
4148
+ * @returns A fresh definition with the rule replaced
4149
+ *
4150
+ * @example
4151
+ * ```ts
4152
+ * import { atom, logicalDefinition, replaceRule, rule } from '@src/core'
4153
+ *
4154
+ * const definition = logicalDefinition('e', 'E', [rule('r1', [], atom('a', 'equals', true))])
4155
+ * replaceRule(definition, rule('r1', [], atom('a', 'equals', false)))
4156
+ * ```
4157
+ */
4158
+ export declare function replaceRule(definition: LogicalDefinition, source: Rule): LogicalDefinition;
4159
+
4160
+ /**
4161
+ * Round a number to a fixed count of decimal places.
4162
+ *
4163
+ * @remarks
4164
+ * `Math.round` semantics — halves round toward `+∞` (`2.5` → `3`, `-2.5` → `-2`).
4165
+ * A negative precision rounds at whole-number scales (`-1` → tens, `-2` →
4166
+ * hundreds). An EXTREME precision whose scale factor overflows the double range
4167
+ * (`10^p` → `Infinity` at roughly `p > 308`, `0` at roughly `p < -323`) returns
4168
+ * the value UNCHANGED — passthrough, never `NaN`.
4169
+ *
4170
+ * @param value - The number to round
4171
+ * @param precision - Decimal places to keep (defaults to `0`)
4172
+ * @returns The rounded number
4173
+ *
4174
+ * @example
4175
+ * ```ts
4176
+ * import { roundTo } from '@src/core'
4177
+ *
4178
+ * roundTo(3.14159, 2) // 3.14
4179
+ * roundTo(2.5) // 3
4180
+ * roundTo(1250, -2) // 1300 — tens/hundreds scales
4181
+ * roundTo(1.5, 400) // 1.5 — overflow passthrough
4182
+ * ```
4183
+ */
4184
+ export declare function roundTo(value: number, precision?: number): number;
4185
+
4186
+ /**
4187
+ * One deduction rule: when ALL `premises` hold, the `conclusion`'s atoms are
4188
+ * asserted as derived facts.
4189
+ *
4190
+ * @remarks
4191
+ * `priority` orders evaluation ascending (default `0`, lower runs first);
4192
+ * `enabled: false` skips the rule (omitted from results). Conclusion extraction
4193
+ * ignores connectives — EVERY atom inside the conclusion is asserted as a
4194
+ * `field = value` fact, even under `not` / `or`.
4195
+ */
4196
+ export declare interface Rule {
4197
+ readonly id: string;
4198
+ readonly name: string;
4199
+ readonly description?: string;
4200
+ readonly premises: readonly Expression[];
4201
+ readonly conclusion: Expression;
4202
+ readonly priority?: number;
4203
+ readonly enabled?: boolean;
4204
+ }
4205
+
4206
+ /**
4207
+ * Build a {@link Rule} — premises and a conclusion.
4208
+ *
4209
+ * @remarks
4210
+ * `name` defaults to the `id`; set `name`, `description`, `priority`, or
4211
+ * `enabled` through `overrides`.
4212
+ *
4213
+ * @param id - The rule id
4214
+ * @param premises - The expressions that must ALL hold
4215
+ * @param conclusion - The expression whose atoms are asserted when they do
4216
+ * @param overrides - Optional {@link Rule} fields merged over the defaults
4217
+ * @returns A fresh rule
4218
+ *
4219
+ * @example
4220
+ * ```ts
4221
+ * import { atom, rule } from '@src/core'
4222
+ *
4223
+ * rule('adult', [atom('age', 'from', 18)], atom('adult', 'equals', true), { priority: 1 })
4224
+ * ```
4225
+ */
4226
+ export declare function rule(id: string, premises: readonly Expression[], conclusion: Expression, overrides?: Partial<Omit<Rule, 'id' | 'premises' | 'conclusion'>>): Rule;
4227
+
4228
+ /**
4229
+ * The {@link RuleManagerInterface} implementation — a self-owning, kind-free
4230
+ * manager over a logical definition's `rules`.
4231
+ *
4232
+ * @remarks
4233
+ * OWNS its `#rules` collection as private copy-on-write state and its own
4234
+ * {@link Emitter} over {@link RuleManagerEventMap}. Rule order is LOAD-BEARING —
4235
+ * the forward conclusion is the LAST declared non-disabled rule, so `append`
4236
+ * without a `target` makes the new rule the conclusion. The write-only
4237
+ * `collection` setter is the owning builder's silent bulk re-seat channel
4238
+ * (used by `merge`). `destroy()` is idempotent and tears the emitter down LAST;
4239
+ * any other call after it throws `ReasonError('DESTROYED', …)`.
4240
+ */
4241
+ export declare class RuleManager implements RuleManagerInterface {
4242
+ #private;
4243
+ constructor(options?: RuleManagerOptions);
4244
+ get emitter(): EmitterInterface<RuleManagerEventMap>;
4245
+ set collection(value: readonly Rule[]);
4246
+ rule(id: string): Rule | undefined;
4247
+ rules(): readonly Rule[];
4248
+ append(rule: Rule, target?: string): void;
4249
+ prepend(rule: Rule, target?: string): void;
4250
+ replace(rule: Rule): void;
4251
+ remove(id: string): void;
4252
+ destroy(): void;
4253
+ }
4254
+
4255
+ /** The push observation surface of a {@link RuleManagerInterface} (AGENTS §13). */
4256
+ export declare type RuleManagerEventMap = {
4257
+ /** A rule was appended — carries its id. */
4258
+ readonly append: readonly [id: string];
4259
+ /** A rule was prepended — carries its id. */
4260
+ readonly prepend: readonly [id: string];
4261
+ /** A rule was replaced in place — carries its id. */
4262
+ readonly replace: readonly [id: string];
4263
+ /** A rule was removed — carries its id. */
4264
+ readonly remove: readonly [id: string];
4265
+ /** The manager was destroyed. */
4266
+ readonly destroy: readonly [];
4267
+ };
4268
+
4269
+ /**
4270
+ * The {@link DefinitionBuilderInterface} manager over a logical definition's
4271
+ * `rules` — a self-owning, kind-free collection manager.
4272
+ *
4273
+ * @remarks
4274
+ * Rule order is load-bearing — the forward conclusion is the LAST declared
4275
+ * non-disabled rule, so `append` without a `target` makes a new rule the
4276
+ * conclusion.
4277
+ */
4278
+ export declare interface RuleManagerInterface {
4279
+ readonly emitter: EmitterInterface<RuleManagerEventMap>;
4280
+ set collection(value: readonly Rule[]);
4281
+ rule(id: string): Rule | undefined;
4282
+ rules(): readonly Rule[];
4283
+ append(rule: Rule, target?: string): void;
4284
+ prepend(rule: Rule, target?: string): void;
4285
+ replace(rule: Rule): void;
4286
+ remove(id: string): void;
4287
+ destroy(): void;
4288
+ }
4289
+
4290
+ /**
4291
+ * Options for `createRuleManager` / the `RuleManager` constructor.
4292
+ *
4293
+ * @remarks
4294
+ * `rules` — the initial collection (defaults to empty). `on` — initial event
4295
+ * listeners (AGENTS §8). `error` — the emitter's listener-error handler
4296
+ * (AGENTS §13).
4297
+ */
4298
+ export declare interface RuleManagerOptions {
4299
+ readonly rules?: readonly Rule[];
4300
+ readonly on?: EmitterHooks<RuleManagerEventMap>;
4301
+ readonly error?: EmitterErrorHandler;
4302
+ }
4303
+
4304
+ /**
4305
+ * One rule's evaluation outcome.
4306
+ *
4307
+ * @remarks
4308
+ * `applied` and `conclusion` are always equal — both mean "all premises held".
4309
+ * `premises` carries the per-premise truth values.
4310
+ */
4311
+ export declare interface RuleResult {
4312
+ readonly id: string;
4313
+ readonly applied: boolean;
4314
+ readonly premises: readonly boolean[];
4315
+ readonly conclusion: boolean;
4316
+ }
4317
+
4318
+ /**
4319
+ * Sort items ascending by `priority ?? DEFAULT_PRIORITY` — a stable copy sort.
4320
+ *
4321
+ * @remarks
4322
+ * The shared evaluation-order helper of the quantitative (factors) and logical
4323
+ * (rules) reasoners: lower priorities run first, an absent `priority` defaults
4324
+ * to `0`, equal priorities keep DECLARATION order (stable), and the input array
4325
+ * is never mutated (AGENTS §11). An array hole, `null`, or other non-record
4326
+ * entry is dropped rather than sorted — the output may be shorter than the
4327
+ * input.
4328
+ *
4329
+ * @param items - The priority-carrying items to order
4330
+ * @returns A fresh array, sorted ascending by priority
4331
+ *
4332
+ * @example
4333
+ * ```ts
4334
+ * import { sortByPriority } from '@src/core'
4335
+ *
4336
+ * sortByPriority([{ priority: 5 }, {}, { priority: -1 }])
4337
+ * // [{ priority: -1 }, {}, { priority: 5 }] — default 0 sits between
4338
+ * ```
4339
+ */
4340
+ export declare function sortByPriority<T extends {
4341
+ readonly priority?: number;
4342
+ }>(items: readonly T[]): readonly T[];
4343
+
4344
+ /** The four factor sources, discriminated by `origin`. */
4345
+ export declare type Source = StaticSource | FieldSource | LookupSource | RangeSource;
4346
+
4347
+ /**
4348
+ * Build a {@link Factor} over a static {@link Source}.
4349
+ *
4350
+ * @remarks
4351
+ * `name` defaults to the `id`; every other {@link Factor} field (checks,
4352
+ * transforms, bounds, weight, priority, enabled, required, fallback) comes
4353
+ * through `overrides`.
4354
+ *
4355
+ * @param id - The factor id
4356
+ * @param value - The fixed source value
4357
+ * @param overrides - Optional {@link Factor} fields merged over the defaults
4358
+ * @returns A fresh factor
4359
+ *
4360
+ * @example
4361
+ * ```ts
4362
+ * import { staticFactor } from '@src/core'
4363
+ *
4364
+ * staticFactor('base-rate', 10, { weight: 2 })
4365
+ * ```
4366
+ */
4367
+ export declare function staticFactor(id: string, value: number, overrides?: Partial<Omit<Factor, 'id' | 'source'>>): Factor;
4368
+
4369
+ /** A factor source yielding a fixed number. */
4370
+ export declare interface StaticSource {
4371
+ readonly origin: 'static';
4372
+ readonly value: number;
4373
+ }
4374
+
4375
+ /**
4376
+ * Build a static {@link Source} — a fixed number.
4377
+ *
4378
+ * @param value - The fixed value
4379
+ * @returns A fresh static source
4380
+ *
4381
+ * @example
4382
+ * ```ts
4383
+ * import { staticSource } from '@src/core'
4384
+ *
4385
+ * staticSource(42) // { origin: 'static', value: 42 }
4386
+ * ```
4387
+ */
4388
+ export declare function staticSource(value: number): Source;
4389
+
4390
+ /**
4391
+ * The data record being reasoned about — a plain readonly bag of fields, read
4392
+ * by {@link FieldPath}.
4393
+ */
4394
+ export declare type Subject = Readonly<Record<string, unknown>>;
4395
+
4396
+ /**
4397
+ * The `SubjectBuilder` entity brand — a `unique symbol` key carrying
4398
+ * `readonly true` on every `SubjectBuilderInterface` instance.
4399
+ *
4400
+ * @remarks
4401
+ * Only `isSubjectBuilder` (`validators.ts`) reads this key, via `Reflect.get`.
4402
+ * Distinct from {@link DEFINITION_BUILDER_BRAND}, so the two entities can never
4403
+ * match each other's guard.
4404
+ */
4405
+ export declare const SUBJECT_BUILDER_BRAND: unique symbol;
4406
+
4407
+ /**
4408
+ * A stateful workspace builder accumulating a {@link Subject}, taverna
4409
+ * `Workspace`-shaped (AGENTS §4.2.2): a single flat collection, no managers —
4410
+ * a flat sibling of `Reason.ts`.
4411
+ *
4412
+ * @remarks
4413
+ * `id` is OPTIONAL (`options?.id ?? seed.id`). When present, the builder is
4414
+ * id-ful and behaves as before. When absent, the builder is ANONYMOUS —
4415
+ * `.id` is `undefined` and the accumulated subject carries no `id` key.
4416
+ * `field(key)` / `fields()` are the AGENTS §9.1 accessor pair over TOP-LEVEL
4417
+ * keys only. `set(key, value)` delegates to `assignField`; `set('id', …)`
4418
+ * throws `ReasonError('MISMATCH', …)` — id is immutable via the entity,
4419
+ * id-ful or anonymous alike. `remove` is the AGENTS §9.2 batch overload
4420
+ * (array form declared first); removing `'id'` throws the same `MISMATCH`
4421
+ * for the same reason. `merge(incoming)` delegates to `mergeSubjects`
4422
+ * (incoming-wins, base `id` preserved — plain {@link Subject} data only).
4423
+ * `clear()` removes every non-id field, restoring `{ id }` when id-ful or
4424
+ * an empty record when anonymous. `repeat(count)` returns `count`
4425
+ * deterministic minted-id clones as PLAIN payloads — a pure read that does
4426
+ * NOT emit. `build(): Subject` is total, deterministic, and returns a fresh
4427
+ * durable payload each call. Post-destroy mutation throws
4428
+ * `ReasonError('DESTROYED', …)` — only the `emitter` getter and `destroy`
4429
+ * itself keep working, mirroring `Reason`. `destroy()` is idempotent and
4430
+ * tears the emitter down LAST (AGENTS §13).
4431
+ */
4432
+ export declare class SubjectBuilder implements SubjectBuilderInterface {
4433
+ #private;
4434
+ readonly [SUBJECT_BUILDER_BRAND]: true;
4435
+ constructor(seed: Subject, options?: SubjectBuilderOptions);
4436
+ get id(): string | undefined;
4437
+ get emitter(): EmitterInterface<SubjectBuilderEventMap>;
4438
+ field(key: string): unknown;
4439
+ fields(): Subject;
4440
+ set(key: string, value: unknown): void;
4441
+ remove(keys: readonly string[]): boolean;
4442
+ remove(key: string): boolean;
4443
+ merge(incoming: Subject): void;
4444
+ clear(): void;
4445
+ repeat(count: number): readonly Subject[];
4446
+ build(): Subject;
4447
+ destroy(): void;
4448
+ }
4449
+
4450
+ /**
4451
+ * The push observation surface of a {@link SubjectBuilderInterface} (AGENTS
4452
+ * §13) — five verb-named events, no generic `change` / `status`.
4453
+ */
4454
+ export declare type SubjectBuilderEventMap = {
4455
+ /** A field was upserted — carries its key and new value. */
4456
+ readonly set: readonly [key: string, value: unknown];
4457
+ /** A field was removed — carries its key. */
4458
+ readonly remove: readonly [key: string];
4459
+ /** The subject was reconciled with an incoming subject — carries the incoming record. */
4460
+ readonly merge: readonly [incoming: Subject];
4461
+ /** Every non-id field was removed. */
4462
+ readonly clear: readonly [];
4463
+ /** The entity was destroyed. */
4464
+ readonly destroy: readonly [];
4465
+ };
4466
+
4467
+ /**
4468
+ * A stateful workspace builder accumulating a {@link Subject}, taverna
4469
+ * `Workspace`-shaped (AGENTS §4.2.2): a single flat collection, no managers.
4470
+ *
4471
+ * @remarks
4472
+ * `id` is OPTIONAL on the entity (`options?.id ?? seed.id`). When present,
4473
+ * the builder is id-ful — `build()`'s output carries that `id` and `clear()`
4474
+ * restores it. When absent, the builder is ANONYMOUS — `.id` is `undefined`,
4475
+ * `build()`'s output carries NO `id` key, and `clear()` empties the record
4476
+ * entirely. `field` / `fields` are the AGENTS §9.1 accessor pair over
4477
+ * TOP-LEVEL keys only. `set(key, value)` delegates to `assignField`;
4478
+ * `set('id', …)` throws — id is immutable via the entity, id-ful or
4479
+ * anonymous alike. `remove` is the AGENTS §9.2 batch overload, array form
4480
+ * declared FIRST. `merge(incoming)` delegates to `mergeSubjects`
4481
+ * (incoming-wins, base `id` preserved — plain {@link Subject} data only).
4482
+ * `clear()` removes every non-id field. `repeat(count)` returns `count`
4483
+ * deterministic minted-id clones as PLAIN payloads — a pure read that does
4484
+ * NOT emit. `build(): Subject` is total, deterministic, and returns a fresh
4485
+ * durable payload each call — distinct from `fields()` (a live inspection
4486
+ * read) even though both currently return the whole record. Post-destroy
4487
+ * mutation throws `ReasonError('DESTROYED', …)`; `destroy()` is idempotent
4488
+ * and tears the emitter down LAST.
4489
+ */
4490
+ export declare interface SubjectBuilderInterface {
4491
+ readonly [SUBJECT_BUILDER_BRAND]: true;
4492
+ readonly id: string | undefined;
4493
+ readonly emitter: EmitterInterface<SubjectBuilderEventMap>;
4494
+ field(key: string): unknown;
4495
+ fields(): Subject;
4496
+ set(key: string, value: unknown): void;
4497
+ remove(keys: readonly string[]): boolean;
4498
+ remove(key: string): boolean;
4499
+ merge(incoming: Subject): void;
4500
+ clear(): void;
4501
+ repeat(count: number): readonly Subject[];
4502
+ build(): Subject;
4503
+ destroy(): void;
4504
+ }
4505
+
4506
+ /**
4507
+ * Options for `createSubjectBuilder` / the `SubjectBuilder` constructor.
4508
+ *
4509
+ * @remarks
4510
+ * `id` — overrides the seed subject's `id` (defaults to `seed.id`); OPTIONAL
4511
+ * — when neither `options.id` nor a string `seed.id` is present the builder
4512
+ * is ANONYMOUS (`.id` is `undefined`, `build()` emits no `id` key). `on` —
4513
+ * initial event listeners (AGENTS §8). `error` — the emitter's listener-error
4514
+ * handler (AGENTS §13).
4515
+ */
4516
+ export declare interface SubjectBuilderOptions {
4517
+ readonly id?: string;
4518
+ readonly on?: EmitterHooks<SubjectBuilderEventMap>;
4519
+ readonly error?: EmitterErrorHandler;
4520
+ }
4521
+
4522
+ /**
4523
+ * Project a subject's scalar fields into `has(key, value)` base facts — the
4524
+ * inferential reasoner's subject-injection step.
4525
+ *
4526
+ * @remarks
4527
+ * Every own subject field EXCEPT `id` becomes a `has(key, value)` fact at full
4528
+ * `DEFAULT_CONFIDENCE`; `null` / `undefined` and any `object` (including arrays)
4529
+ * value is skipped. Each injection appends a line to `trace` (mutated), plus a
4530
+ * final count when at least one fact was produced. The injected fact ids are
4531
+ * `subject:<key>`.
4532
+ *
4533
+ * @param subject - The subject to project
4534
+ * @param trace - The trace accumulator to append to (mutated)
4535
+ * @returns The fresh `has(...)` facts (in `Object.keys` order)
4536
+ *
4537
+ * @example
4538
+ * ```ts
4539
+ * import { subjectToFacts } from '@src/core'
4540
+ *
4541
+ * const trace: string[] = []
4542
+ * subjectToFacts({ id: 'p1', age: 42, tags: ['a'] }, trace) // one fact: has('age', 42) — tags skipped
4543
+ * ```
4544
+ */
4545
+ export declare function subjectToFacts(subject: Subject, trace: string[]): Fact[];
4546
+
4547
+ /** Default `id` for a `SymbolicReasoner`. */
4548
+ export declare const SYMBOLIC_ID = "symbolic";
4549
+
4550
+ /**
4551
+ * A symbolic (equation-solving) definition.
4552
+ *
4553
+ * @remarks
4554
+ * `variables` seeds the bindings; numeric subject fields OVERRIDE same-named
4555
+ * variables. Equations solve strictly in order, each solution rounded to
4556
+ * `precision` decimal places (default `4`) BEFORE feeding forward into later
4557
+ * equations.
4558
+ */
4559
+ export declare interface SymbolicDefinition {
4560
+ readonly reasoning: 'symbolic';
4561
+ readonly id: string;
4562
+ readonly name: string;
4563
+ readonly description?: string;
4564
+ readonly equations: readonly Equation[];
4565
+ readonly variables: Readonly<Record<string, number>>;
4566
+ readonly precision?: number;
4567
+ }
4568
+
4569
+ /**
4570
+ * Build a {@link SymbolicDefinition}.
4571
+ *
4572
+ * @remarks
4573
+ * `variables` defaults to `{}`; set `variables`, `description`, or `precision`
4574
+ * through `overrides`.
4575
+ *
4576
+ * @param id - The definition id
4577
+ * @param name - The display name
4578
+ * @param equations - The equations, solved in order
4579
+ * @param overrides - Optional {@link SymbolicDefinition} fields merged over the defaults
4580
+ * @returns A fresh symbolic definition
4581
+ *
4582
+ * @example
4583
+ * ```ts
4584
+ * import { constant, equation, symbolicDefinition, variable } from '@src/core'
4585
+ *
4586
+ * symbolicDefinition('rate', 'Rate', [equation('e1', variable('x'), constant(42), 'x')], {
4587
+ * precision: 2,
4588
+ * })
4589
+ * ```
4590
+ */
4591
+ export declare function symbolicDefinition(id: string, name: string, equations: readonly Equation[], overrides?: Partial<Omit<SymbolicDefinition, 'reasoning' | 'id' | 'name' | 'equations'>>): SymbolicDefinition;
4592
+
4593
+ /** An algebraic expression tree, discriminated by `form`. */
4594
+ export declare type SymbolicExpression = Variable | Constant | Operation;
4595
+
4596
+ /**
4597
+ * The symbolic reasoner — algebraic equation solving by variable isolation.
4598
+ *
4599
+ * @remarks
4600
+ * Bindings seed from `definition.variables`, then numeric subject fields (a
4601
+ * finite number or a numeric string, coerced through the contracts
4602
+ * `parseNumber`) OVERRIDE same-named variables — the `id` field is skipped.
4603
+ * Equations solve strictly in order: when the `target` is unbound and appears
4604
+ * on exactly ONE side, it is isolated by peeling invertible operations (`add` /
4605
+ * `subtract` / `multiply` / `divide`); a non-invertible operation, a target on
4606
+ * both sides of an operation, or an unbound variable throws internally — the
4607
+ * throw is caught PER EQUATION and surfaced as a result error (`Equation
4608
+ * "<id>": <message>` plus a `FAILED` trace) while later equations still run.
4609
+ * Inversion or division by zero yields `NaN`, caught by the non-finite check.
4610
+ * A solved value is rounded to `precision` BEFORE binding, so later equations
4611
+ * see the rounded value; `solutions` reads FINAL bindings keyed by each
4612
+ * equation's target (a failed equation's target still appears when bound
4613
+ * elsewhere). Nothing mutates its inputs; fully deterministic (AGENTS §11).
4614
+ */
4615
+ export declare class SymbolicReasoner implements ReasonerInterface {
4616
+ #private;
4617
+ constructor(options?: SymbolicReasonerOptions);
4618
+ get id(): string;
4619
+ get reasoning(): Reasoning;
4620
+ supports(definition: Definition): boolean;
4621
+ validate(definition: Definition): ReasonValidationResult;
4622
+ reason(subject: Subject, definition: Definition): ReasonResult;
4623
+ }
4624
+
4625
+ /**
4626
+ * Options for `createSymbolicReasoner` / the `SymbolicReasoner` constructor.
4627
+ *
4628
+ * @remarks
4629
+ * `id` — the reasoner's identity string (defaults to `SYMBOLIC_ID`).
4630
+ */
4631
+ export declare interface SymbolicReasonerOptions {
4632
+ readonly id?: string;
4633
+ }
4634
+
4635
+ /**
4636
+ * The outcome of symbolic reasoning — final bindings keyed by each equation's
4637
+ * `target` (a failed equation's target still appears when bound elsewhere).
4638
+ */
4639
+ export declare interface SymbolicResult {
4640
+ readonly reasoning: 'symbolic';
4641
+ readonly solutions: Readonly<Record<string, number>>;
4642
+ readonly success: boolean;
4643
+ readonly trace: readonly string[];
4644
+ readonly errors: readonly string[];
4645
+ }
4646
+
4647
+ /**
4648
+ * Derive one fact term's contribution to a dedup key — reference identity for
4649
+ * non-null objects / functions, a SameValueZero value string for primitives.
4650
+ *
4651
+ * @remarks
4652
+ * The per-term half of {@link factToKey}, used by the inferential reasoner's
4653
+ * forward-chaining dedupe. Primitives (and `null`) key by value, typeof-prefixed
4654
+ * so `1` (`number:1`) never collides with `'1'` (`string:1`); `-0` folds to `+0`
4655
+ * (both `number:0`) and `NaN` is self-consistent (`number:NaN`), matching
4656
+ * SameValueZero. Objects and functions key by REFERENCE through `identities` — a
4657
+ * first sighting is assigned the map's current size as its id, so distinct
4658
+ * objects never collide and the SAME reference always reproduces its key.
4659
+ *
4660
+ * @param term - The term to key
4661
+ * @param identities - The reference-identity map, threaded across a dedupe pass (mutated: a new object/function is registered)
4662
+ * @returns The term's key string
4663
+ *
4664
+ * @example
4665
+ * ```ts
4666
+ * import { termToKey } from '@src/core'
4667
+ *
4668
+ * const identities = new Map<object, number>()
4669
+ * termToKey(1, identities) // 'number:1'
4670
+ * termToKey('1', identities) // 'string:1' — never collides with the number
4671
+ * ```
4672
+ */
4673
+ export declare function termToKey(term: unknown, identities: Map<object, number>): string;
4674
+
4675
+ /**
4676
+ * One math step applied to a number by the {@link TransformerInterface}.
4677
+ *
4678
+ * @remarks
4679
+ * The absent-`operand` default is operation-specific: `1` for `multiply` /
4680
+ * `divide` / `power` (identity-preserving), `0` for every other binary
4681
+ * operation; unary operations ignore it.
4682
+ */
4683
+ export declare interface Transform {
4684
+ readonly operation: MathOperation;
4685
+ readonly operand?: number;
4686
+ }
4687
+
4688
+ /**
4689
+ * Build a {@link Transform} — one math step.
4690
+ *
4691
+ * @remarks
4692
+ * The `operand` key is OMITTED when absent (never set to `undefined`), so the
4693
+ * transform stays exact-record valid; the transformer then applies its
4694
+ * per-operation default (`1` for `multiply` / `divide` / `power`, `0` otherwise).
4695
+ *
4696
+ * @param operation - The math operation to apply
4697
+ * @param operand - The operand (ignored by the unary operations)
4698
+ * @returns A fresh transform
4699
+ *
4700
+ * @example
4701
+ * ```ts
4702
+ * import { transform } from '@src/core'
4703
+ *
4704
+ * transform('multiply', 2) // { operation: 'multiply', operand: 2 }
4705
+ * transform('round') // { operation: 'round' }
4706
+ * ```
4707
+ */
4708
+ export declare function transform(operation: MathOperation, operand?: number): Transform;
4709
+
4710
+ /**
4711
+ * Applies math {@link Transform}s to numbers — the quantitative reasoner's
4712
+ * per-factor pipeline stage.
4713
+ *
4714
+ * @remarks
4715
+ * TOTAL: never throws. Absent-`operand` defaults are operation-specific —
4716
+ * identity-preserving `1` for `multiply` / `divide` / `power`, `0` for every
4717
+ * other binary operation; `round` / `ceil` / `floor` / `abs` are unary and
4718
+ * ignore the operand. `divide` by zero yields `NaN` (deliberately not JS's
4719
+ * `Infinity`), an unknown operation returns the value unchanged, and `chain` is
4720
+ * a strict left fold — `NaN` flows through untouched. Stateless and
4721
+ * deterministic.
4722
+ */
4723
+ export declare class Transformer implements TransformerInterface {
4724
+ #private;
4725
+ constructor(options?: TransformerOptions);
4726
+ get id(): string;
4727
+ apply(value: number, transform: Transform): number;
4728
+ chain(value: number, transforms: readonly Transform[]): number;
4729
+ }
4730
+
4731
+ /** Default `id` for a `Transformer`. */
4732
+ export declare const TRANSFORMER_ID = "transformer";
4733
+
4734
+ /**
4735
+ * Applies math {@link Transform}s to numbers.
4736
+ *
4737
+ * @remarks
4738
+ * Total: an unknown operation returns the value unchanged, and `divide` by
4739
+ * zero yields `NaN` rather than throwing. `chain` is a strict left fold —
4740
+ * `NaN` flows through.
4741
+ */
4742
+ export declare interface TransformerInterface {
4743
+ readonly id: string;
4744
+ apply(value: number, transform: Transform): number;
4745
+ chain(value: number, transforms: readonly Transform[]): number;
4746
+ }
4747
+
4748
+ /**
4749
+ * Options for `createTransformer` / the `Transformer` constructor.
4750
+ *
4751
+ * @remarks
4752
+ * `id` — the transformer's identity string (defaults to `TRANSFORMER_ID`).
4753
+ */
4754
+ export declare interface TransformerOptions {
4755
+ readonly id?: string;
4756
+ }
4757
+
4758
+ /** A symbolic expression leaf naming a variable. */
4759
+ export declare interface Variable {
4760
+ readonly form: 'variable';
4761
+ readonly name: string;
4762
+ }
4763
+
4764
+ /**
4765
+ * Build a variable {@link SymbolicExpression} leaf.
4766
+ *
4767
+ * @param name - The variable name
4768
+ * @returns A fresh variable node
4769
+ *
4770
+ * @example
4771
+ * ```ts
4772
+ * import { variable } from '@src/core'
4773
+ *
4774
+ * variable('x') // { form: 'variable', name: 'x' }
4775
+ * ```
4776
+ */
4777
+ export declare function variable(name: string): SymbolicExpression;
4778
+
4779
+ /**
4780
+ * The {@link VariableManagerInterface} implementation — a self-owning,
4781
+ * kind-free manager over a symbolic definition's `variables`, a name-keyed
4782
+ * unordered record.
4783
+ *
4784
+ * @remarks
4785
+ * OWNS its `#variables` record as private copy-on-write state and its own
4786
+ * {@link Emitter} over {@link VariableManagerEventMap}. The record has no
4787
+ * placement, so only `add` / `remove` exist (no `append` / `prepend`): `add`
4788
+ * upserts and emits `add(name)`, `remove` omits the key entirely (never sets
4789
+ * `undefined`) and emits `remove(name)`. The write-only `collection` setter is
4790
+ * the owning builder's silent bulk re-seat channel (used by `merge`).
4791
+ * `destroy()` is idempotent and tears the emitter down LAST; any other call
4792
+ * after it throws `ReasonError('DESTROYED', …)`.
4793
+ */
4794
+ export declare class VariableManager implements VariableManagerInterface {
4795
+ #private;
4796
+ constructor(options?: VariableManagerOptions);
4797
+ get emitter(): EmitterInterface<VariableManagerEventMap>;
4798
+ set collection(value: Readonly<Record<string, number>>);
4799
+ variable(name: string): number | undefined;
4800
+ variables(): Readonly<Record<string, number>>;
4801
+ add(name: string, value: number): void;
4802
+ remove(name: string): void;
4803
+ destroy(): void;
4804
+ }
4805
+
4806
+ /**
4807
+ * The push observation surface of a {@link VariableManagerInterface}
4808
+ * (AGENTS §13).
4809
+ *
4810
+ * @remarks
4811
+ * `variables` is a name-keyed record with no placement, so the honest verbs
4812
+ * are `add` / `remove` — each carries the variable NAME.
4813
+ */
4814
+ export declare type VariableManagerEventMap = {
4815
+ /** A variable was upserted — carries its name. */
4816
+ readonly add: readonly [name: string];
4817
+ /** A variable was removed — carries its name. */
4818
+ readonly remove: readonly [name: string];
4819
+ /** The manager was destroyed. */
4820
+ readonly destroy: readonly [];
4821
+ };
4822
+
4823
+ /**
4824
+ * The {@link DefinitionBuilderInterface} manager over a symbolic definition's
4825
+ * `variables` — a name-keyed unordered record, so `add` / `remove` are the
4826
+ * only write verbs (no placement). A self-owning, kind-free manager.
4827
+ */
4828
+ export declare interface VariableManagerInterface {
4829
+ readonly emitter: EmitterInterface<VariableManagerEventMap>;
4830
+ set collection(value: Readonly<Record<string, number>>);
4831
+ variable(name: string): number | undefined;
4832
+ variables(): Readonly<Record<string, number>>;
4833
+ add(name: string, value: number): void;
4834
+ remove(name: string): void;
4835
+ destroy(): void;
4836
+ }
4837
+
4838
+ /**
4839
+ * Options for `createVariableManager` / the `VariableManager` constructor.
4840
+ *
4841
+ * @remarks
4842
+ * `variables` — the initial record (defaults to empty). `on` — initial event
4843
+ * listeners (AGENTS §8). `error` — the emitter's listener-error handler
4844
+ * (AGENTS §13).
4845
+ */
4846
+ export declare interface VariableManagerOptions {
4847
+ readonly variables?: Readonly<Record<string, number>>;
4848
+ readonly on?: EmitterHooks<VariableManagerEventMap>;
4849
+ readonly error?: EmitterErrorHandler;
4850
+ }
4851
+
4852
+ export { }