@orkestrel/reason 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -19
- package/dist/src/core/index.cjs +243 -218
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +610 -281
- package/dist/src/core/index.d.ts +610 -281
- package/dist/src/core/index.js +243 -218
- package/dist/src/core/index.js.map +1 -1
- package/package.json +9 -10
package/dist/src/core/index.cjs
CHANGED
|
@@ -48,7 +48,7 @@ var DEFAULT_PRIORITY = 0;
|
|
|
48
48
|
* inferential chaining.
|
|
49
49
|
*
|
|
50
50
|
* @remarks
|
|
51
|
-
* Fixed — unlike {@link DEFAULT_PRECISION} it is
|
|
51
|
+
* Fixed — unlike {@link DEFAULT_PRECISION} it is not overridable per
|
|
52
52
|
* definition, so confidence products stay comparable across derivations.
|
|
53
53
|
*/
|
|
54
54
|
var CONFIDENCE_PRECISION = 4;
|
|
@@ -94,8 +94,8 @@ var DEFINITION_BUILDER_BRAND = Symbol("reasons.definitionBuilder");
|
|
|
94
94
|
*
|
|
95
95
|
* @remarks
|
|
96
96
|
* Only `isSubjectBuilder` (`validators.ts`) reads this key, through `Reflect.get`.
|
|
97
|
-
* Distinct from {@link DEFINITION_BUILDER_BRAND}, so
|
|
98
|
-
* match
|
|
97
|
+
* Distinct from {@link DEFINITION_BUILDER_BRAND}, so neither entity can ever
|
|
98
|
+
* match the other's guard.
|
|
99
99
|
*/
|
|
100
100
|
var SUBJECT_BUILDER_BRAND = Symbol("reasons.subjectBuilder");
|
|
101
101
|
//#endregion
|
|
@@ -152,7 +152,7 @@ function isReasonError(value) {
|
|
|
152
152
|
* Determines whether a value is a {@link Reasoning} literal.
|
|
153
153
|
*
|
|
154
154
|
* @param value - The value to test
|
|
155
|
-
* @returns True if `value`
|
|
155
|
+
* @returns True if `value` names a reasoning strategy; false otherwise
|
|
156
156
|
*
|
|
157
157
|
* @example
|
|
158
158
|
* ```ts
|
|
@@ -197,7 +197,7 @@ var isMathOperation = (0, _orkestrel_contract.literalOf)("add", "subtract", "mul
|
|
|
197
197
|
* Determines whether a value is an {@link Aggregation} literal.
|
|
198
198
|
*
|
|
199
199
|
* @param value - The value to test
|
|
200
|
-
* @returns True if `value`
|
|
200
|
+
* @returns True if `value` names an aggregation; false otherwise
|
|
201
201
|
*
|
|
202
202
|
* @example
|
|
203
203
|
* ```ts
|
|
@@ -212,7 +212,7 @@ var isAggregation = (0, _orkestrel_contract.literalOf)("sum", "product", "averag
|
|
|
212
212
|
* Determines whether a value is a {@link Comparison} literal.
|
|
213
213
|
*
|
|
214
214
|
* @param value - The value to test
|
|
215
|
-
* @returns True if `value`
|
|
215
|
+
* @returns True if `value` names a comparison operator; false otherwise
|
|
216
216
|
*
|
|
217
217
|
* @example
|
|
218
218
|
* ```ts
|
|
@@ -227,7 +227,7 @@ var isComparison = (0, _orkestrel_contract.literalOf)("equals", "not", "above",
|
|
|
227
227
|
* Determines whether a value is a {@link LogicalOperator} literal.
|
|
228
228
|
*
|
|
229
229
|
* @param value - The value to test
|
|
230
|
-
* @returns True if `value`
|
|
230
|
+
* @returns True if `value` names a logical connective; false otherwise
|
|
231
231
|
*
|
|
232
232
|
* @example
|
|
233
233
|
* ```ts
|
|
@@ -249,7 +249,7 @@ var isLogicalOperator = (0, _orkestrel_contract.literalOf)("and", "or", "not", "
|
|
|
249
249
|
* ```ts
|
|
250
250
|
* import { isFieldPath } from '@src/core'
|
|
251
251
|
*
|
|
252
|
-
* isFieldPath('age') // true —
|
|
252
|
+
* isFieldPath('age') // true — a single key (never dot-split)
|
|
253
253
|
* isFieldPath(['address', 'city']) // true — descends
|
|
254
254
|
* isFieldPath(42) // false
|
|
255
255
|
* ```
|
|
@@ -276,8 +276,8 @@ var isNumberRecord = (0, _orkestrel_contract.whereOf)(_orkestrel_contract.isReco
|
|
|
276
276
|
* predicate.
|
|
277
277
|
*
|
|
278
278
|
* @remarks
|
|
279
|
-
* `value` may be
|
|
280
|
-
*
|
|
279
|
+
* `value` may be anything (including `null` / `undefined`) but the key must be
|
|
280
|
+
* present — exact-record semantics reject a check that lost its `value` key.
|
|
281
281
|
*
|
|
282
282
|
* @param value - The value to test
|
|
283
283
|
* @returns True if `value` is a well-formed check; false otherwise
|
|
@@ -361,8 +361,8 @@ function isFactorRange(value) {
|
|
|
361
361
|
}, ["bounds"])(value);
|
|
362
362
|
}
|
|
363
363
|
/**
|
|
364
|
-
* Determines whether a value is a {@link Source} —
|
|
365
|
-
*
|
|
364
|
+
* Determines whether a value is a {@link Source} — a static, field, lookup, or
|
|
365
|
+
* range factor source, discriminated by `origin`.
|
|
366
366
|
*
|
|
367
367
|
* @param value - The value to test
|
|
368
368
|
* @returns True if `value` is a well-formed static / field / lookup / range source; false otherwise
|
|
@@ -473,9 +473,9 @@ function isFactorGroup(value) {
|
|
|
473
473
|
* tree of atoms and compounds, discriminated by `form`.
|
|
474
474
|
*
|
|
475
475
|
* @remarks
|
|
476
|
-
* Recursive through `lazyOf` — recursion is
|
|
476
|
+
* Recursive through `lazyOf` — recursion is bounded by the stack, not
|
|
477
477
|
* unbounded: nesting beyond the engine's stack budget (roughly 1000 levels)
|
|
478
|
-
* and cyclic input are
|
|
478
|
+
* and cyclic input are contained as `false`, never a throw. Input past that
|
|
479
479
|
* bound is rejected, not validated.
|
|
480
480
|
*
|
|
481
481
|
* @param value - The value to test
|
|
@@ -535,9 +535,9 @@ function isRule(value) {
|
|
|
535
535
|
* `form`.
|
|
536
536
|
*
|
|
537
537
|
* @remarks
|
|
538
|
-
* Recursive through `lazyOf` — recursion is
|
|
538
|
+
* Recursive through `lazyOf` — recursion is bounded by the stack, not
|
|
539
539
|
* unbounded: nesting beyond the engine's stack budget (roughly 1000 levels)
|
|
540
|
-
* and cyclic input are
|
|
540
|
+
* and cyclic input are contained as `false`, never a throw. Input past that
|
|
541
541
|
* bound is rejected, not validated.
|
|
542
542
|
*
|
|
543
543
|
* @param value - The value to test
|
|
@@ -756,8 +756,8 @@ function isInferentialDefinition(value) {
|
|
|
756
756
|
}, ["description", "depth"])(value);
|
|
757
757
|
}
|
|
758
758
|
/**
|
|
759
|
-
* Determines whether a value is a {@link Definition} —
|
|
760
|
-
* definition
|
|
759
|
+
* Determines whether a value is a {@link Definition} — a quantitative, logical,
|
|
760
|
+
* symbolic, or inferential definition shape, discriminated by `reasoning`.
|
|
761
761
|
*
|
|
762
762
|
* @param value - The value to test
|
|
763
763
|
* @returns True if `value` is a well-formed definition of any reasoning; false otherwise
|
|
@@ -865,6 +865,12 @@ function isResultFact(value) {
|
|
|
865
865
|
/**
|
|
866
866
|
* Determines whether a value is a {@link CheckResult}.
|
|
867
867
|
*
|
|
868
|
+
* @remarks
|
|
869
|
+
* `actual` must be present and may hold anything, including `undefined` — the
|
|
870
|
+
* guard reads its presence, never its value. A result whose `actual` is
|
|
871
|
+
* `undefined` therefore does not survive a JSON round trip: `JSON.stringify`
|
|
872
|
+
* drops the key, and the parsed record is refused here.
|
|
873
|
+
*
|
|
868
874
|
* @param value - The value to test
|
|
869
875
|
* @returns True if every published check-result member is valid; false otherwise
|
|
870
876
|
*
|
|
@@ -886,6 +892,10 @@ function isCheckResult(value) {
|
|
|
886
892
|
/**
|
|
887
893
|
* Determines whether a value is a {@link FactorResult}.
|
|
888
894
|
*
|
|
895
|
+
* @remarks
|
|
896
|
+
* The optional `raw` and `checks` members are absent-or-valid: an absent key
|
|
897
|
+
* passes, a present key is checked in full.
|
|
898
|
+
*
|
|
889
899
|
* @param value - The value to test
|
|
890
900
|
* @returns True if every published factor-result member is valid; false otherwise
|
|
891
901
|
*
|
|
@@ -1057,7 +1067,7 @@ function isLogicalResult(value) {
|
|
|
1057
1067
|
* Determines whether a value is a {@link SymbolicResult}.
|
|
1058
1068
|
*
|
|
1059
1069
|
* @remarks
|
|
1060
|
-
* `solutions` is checked across its
|
|
1070
|
+
* `solutions` is checked across its own string-named members, enumerable or
|
|
1061
1071
|
* not. Inherited members are deliberately unread: they belong to the
|
|
1062
1072
|
* accepted-prototype property, not to the record this guard certifies.
|
|
1063
1073
|
*
|
|
@@ -1135,13 +1145,13 @@ function isReasonValidationResult(value) {
|
|
|
1135
1145
|
})(value);
|
|
1136
1146
|
}
|
|
1137
1147
|
/**
|
|
1138
|
-
* Determines whether a value is a `DefinitionBuilder`
|
|
1148
|
+
* Determines whether a value is a `DefinitionBuilder` entity — the brand-guarded
|
|
1139
1149
|
* stateful workspace, not the plain {@link Definition} data union.
|
|
1140
1150
|
*
|
|
1141
1151
|
* @remarks
|
|
1142
1152
|
* A `unique symbol` brand check (`Reflect.get`): a plain subject
|
|
1143
1153
|
* is an open record whose values may legally be functions, so a
|
|
1144
|
-
* method-presence check (`typeof value.build === 'function'`) is
|
|
1154
|
+
* method-presence check (`typeof value.build === 'function'`) is forgeable —
|
|
1145
1155
|
* this guard is not. A module-owned `unique symbol` cannot be produced by
|
|
1146
1156
|
* `JSON.parse` or written by any consumer that does not import
|
|
1147
1157
|
* `DEFINITION_BUILDER_BRAND`, so plain data can never forge it. Total: a
|
|
@@ -1165,12 +1175,12 @@ function isDefinitionBuilder(value) {
|
|
|
1165
1175
|
return (0, _orkestrel_contract.isObject)(value) && Reflect.get(value, DEFINITION_BUILDER_BRAND) === true;
|
|
1166
1176
|
}
|
|
1167
1177
|
/**
|
|
1168
|
-
* Determines whether a value is a `SubjectBuilder`
|
|
1178
|
+
* Determines whether a value is a `SubjectBuilder` entity — the brand-guarded
|
|
1169
1179
|
* stateful workspace, not the plain {@link Subject} data record.
|
|
1170
1180
|
*
|
|
1171
1181
|
* @remarks
|
|
1172
1182
|
* A `unique symbol` brand check (`Reflect.get`), distinct from
|
|
1173
|
-
* {@link isDefinitionBuilder} —
|
|
1183
|
+
* {@link isDefinitionBuilder} — neither entity can ever match the other's
|
|
1174
1184
|
* guard. Total: a non-object, a missing brand, or a hostile prototype all
|
|
1175
1185
|
* return `false`, never throw.
|
|
1176
1186
|
*
|
|
@@ -1198,7 +1208,7 @@ function isSubjectBuilder(value) {
|
|
|
1198
1208
|
*
|
|
1199
1209
|
* @remarks
|
|
1200
1210
|
* Display-only: the joined form is how a field appears in traces and derived
|
|
1201
|
-
* overlays; it is
|
|
1211
|
+
* overlays; it is never re-parsed into a path (a string stays a single key).
|
|
1202
1212
|
*
|
|
1203
1213
|
* @param field - The field path to format
|
|
1204
1214
|
* @returns The display string
|
|
@@ -1243,7 +1253,7 @@ function clamp(value, limit) {
|
|
|
1243
1253
|
*
|
|
1244
1254
|
* @remarks
|
|
1245
1255
|
* The range test behind the `between` and `outside` `Comparison` operators: only
|
|
1246
|
-
* the
|
|
1256
|
+
* the first two elements of `range` are read, each end is inclusive, and a
|
|
1247
1257
|
* non-numeric `value`, a non-array `range`, a `range` shorter than two
|
|
1248
1258
|
* elements, or a non-numeric bound all report `false`. `outside` is the pure
|
|
1249
1259
|
* negation of this predicate, so a malformed range reads as outside.
|
|
@@ -1307,9 +1317,9 @@ function emptyAggregate(aggregation) {
|
|
|
1307
1317
|
* source passes its value through; `field` and `range` coerce through the
|
|
1308
1318
|
* contracts `parseNumberField`, so a non-finite subject number or a
|
|
1309
1319
|
* non-numeric string is unresolvable and takes `fallback`; `lookup` reads only
|
|
1310
|
-
*
|
|
1320
|
+
* the table's own keys, and a missing or `null` field takes `fallback` directly
|
|
1311
1321
|
* rather than letting a `''` key intercept absent data. A `range` scans its
|
|
1312
|
-
* bands in order and the
|
|
1322
|
+
* bands in order and the first match wins — a band without `bounds` is a
|
|
1313
1323
|
* catch-all and an absent bound side is open. A malformed factor carrying no
|
|
1314
1324
|
* source at all takes `fallback` rather than crashing.
|
|
1315
1325
|
*
|
|
@@ -1359,9 +1369,9 @@ function resolveSource(source, subject, fallback) {
|
|
|
1359
1369
|
* @remarks
|
|
1360
1370
|
* `Math.round` semantics — halves round toward `+∞` (`2.5` → `3`, `-2.5` → `-2`).
|
|
1361
1371
|
* A negative precision rounds at whole-number scales (`-1` → tens, `-2` →
|
|
1362
|
-
* hundreds).
|
|
1372
|
+
* hundreds). A precision whose scale factor overflows the double range
|
|
1363
1373
|
* (`10^p` → `Infinity` at roughly `p > 308`, `0` at roughly `p < -323`) returns
|
|
1364
|
-
* the value
|
|
1374
|
+
* the value unchanged — passthrough, never `NaN`.
|
|
1365
1375
|
*
|
|
1366
1376
|
* @param value - The number to round
|
|
1367
1377
|
* @param precision - Decimal places to keep (defaults to `0`)
|
|
@@ -1389,7 +1399,7 @@ function roundTo(value, precision = 0) {
|
|
|
1389
1399
|
* @remarks
|
|
1390
1400
|
* This is the derivation-bookkeeping equality of the chaining reasoners: the
|
|
1391
1401
|
* logical overlay and the inferential fact-dedupe compare with it so a
|
|
1392
|
-
* NaN-valued conclusion or fact term derives exactly
|
|
1402
|
+
* NaN-valued conclusion or fact term derives exactly once and the fixpoint
|
|
1393
1403
|
* converges (raw `===` would re-derive it every iteration, never converging).
|
|
1394
1404
|
* It matches `Array.prototype.includes` semantics — the same membership test
|
|
1395
1405
|
* the `any` / `none` comparisons use.
|
|
@@ -1416,7 +1426,7 @@ function equalValues(left, right) {
|
|
|
1416
1426
|
* @remarks
|
|
1417
1427
|
* The shared evaluation-order helper of the quantitative (factors) and logical
|
|
1418
1428
|
* (rules) reasoners: lower priorities run first, an absent `priority` defaults
|
|
1419
|
-
* to `0`, equal priorities keep
|
|
1429
|
+
* to `0`, equal priorities keep declaration order (stable), and the input array
|
|
1420
1430
|
* is never mutated. An array hole, `null`, or other non-record entry is dropped
|
|
1421
1431
|
* rather than sorted — the output may be shorter than the input.
|
|
1422
1432
|
*
|
|
@@ -1440,12 +1450,12 @@ function sortByPriority(items) {
|
|
|
1440
1450
|
return usable.sort((left, right) => (left.priority ?? 0) - (right.priority ?? 0));
|
|
1441
1451
|
}
|
|
1442
1452
|
/**
|
|
1443
|
-
* Collects the ids that appear
|
|
1453
|
+
* Collects the ids that appear more than once in an id-carrying list — each
|
|
1444
1454
|
* duplicated id reported once, in first-occurrence order.
|
|
1445
1455
|
*
|
|
1446
1456
|
* @remarks
|
|
1447
1457
|
* The shared uniqueness scan behind every reasoner's `validate()` duplicate-id
|
|
1448
|
-
*
|
|
1458
|
+
* warnings (rules, groups, factors, equations, inferences). Runtime stays
|
|
1449
1459
|
* permissive about duplicates (first/last-wins artifacts) — this helper only
|
|
1450
1460
|
* surfaces them.
|
|
1451
1461
|
*
|
|
@@ -1471,7 +1481,7 @@ function findDuplicates(items) {
|
|
|
1471
1481
|
* @remarks
|
|
1472
1482
|
* Keys both stored facts and premise patterns (both are `Fact`-shaped) for
|
|
1473
1483
|
* {@link indexByArity}: `matchFacts` already rejects an arity mismatch, so
|
|
1474
|
-
* narrowing a same-predicate bucket to same
|
|
1484
|
+
* narrowing a same-predicate bucket to one of the same predicate and arity only
|
|
1475
1485
|
* excludes candidates that could never unify anyway. Only `predicate` — the
|
|
1476
1486
|
* one free-form, adversary-controlled part — is length-prefixed
|
|
1477
1487
|
* (`length + ':' + predicate`), mirroring {@link factToKey}'s framing so a
|
|
@@ -1500,7 +1510,7 @@ function factToArityKey(fact) {
|
|
|
1500
1510
|
* @remarks
|
|
1501
1511
|
* The index behind the inferential reasoner's same-predicate-and-arity join
|
|
1502
1512
|
* scans (`#findAllBindings` / `#calculatePremiseConfidence`): `matchFacts`
|
|
1503
|
-
* already rejects a predicate
|
|
1513
|
+
* already rejects a predicate or an arity mismatch, so restricting a premise's
|
|
1504
1514
|
* search to its own predicate+arity bucket changes nothing but the cost — the
|
|
1505
1515
|
* surviving matches and their append order are identical to a predicate-only
|
|
1506
1516
|
* index. Append order within a bucket is preserved, so a "first match wins"
|
|
@@ -1536,9 +1546,9 @@ function indexByArity(facts) {
|
|
|
1536
1546
|
* forward-chaining dedupe. Primitives (and `null`) key by value, typeof-prefixed
|
|
1537
1547
|
* so `1` (`number:1`) never collides with `'1'` (`string:1`); `-0` folds to `+0`
|
|
1538
1548
|
* (both `number:0`) and `NaN` is self-consistent (`number:NaN`), matching
|
|
1539
|
-
* SameValueZero. Objects and functions key by
|
|
1549
|
+
* SameValueZero. Objects and functions key by reference through `identities` — a
|
|
1540
1550
|
* first sighting is assigned the map's current size as its id, so distinct
|
|
1541
|
-
* objects never collide and the
|
|
1551
|
+
* objects never collide and the same reference always reproduces its key.
|
|
1542
1552
|
*
|
|
1543
1553
|
* @param term - The term to key
|
|
1544
1554
|
* @param identities - The caller-created reference-identity ledger, threaded across a dedupe pass (a newly seen object/function is registered in it)
|
|
@@ -1565,14 +1575,14 @@ function termToKey(term, identities) {
|
|
|
1565
1575
|
}
|
|
1566
1576
|
/**
|
|
1567
1577
|
* Derives a fact's canonical dedup key — predicate + arity + per-term
|
|
1568
|
-
* SameValueZero identity
|
|
1578
|
+
* SameValueZero identity, with confidence excluded from it.
|
|
1569
1579
|
*
|
|
1570
1580
|
* @remarks
|
|
1571
1581
|
* The dedup key of the inferential reasoner's forward fixpoint: two facts with
|
|
1572
1582
|
* the same predicate, arity, and SameValueZero-equal terms share a key (so a
|
|
1573
1583
|
* NaN-term fact derives once and ±0 collapse keeping the first), while
|
|
1574
1584
|
* confidence never enters the key. Each part — the predicate, the stringified
|
|
1575
|
-
* arity, and every {@link termToKey} — is
|
|
1585
|
+
* arity, and every {@link termToKey} — is length-prefixed (`length + ':' + part`)
|
|
1576
1586
|
* before joining, so the delimiter can never be forged by an adversarial string
|
|
1577
1587
|
* term embedding it: two distinct facts always produce distinct keys, even when
|
|
1578
1588
|
* a term string contains the delimiter (an injective framing raw joining lacked).
|
|
@@ -1603,10 +1613,10 @@ function factToKey(fact, identities) {
|
|
|
1603
1613
|
*
|
|
1604
1614
|
* @remarks
|
|
1605
1615
|
* The bidirectional unification of the inferential reasoner: a `'?'`-prefixed
|
|
1606
|
-
* string term on
|
|
1616
|
+
* string term on either side (pattern or candidate) is a variable that binds to
|
|
1607
1617
|
* the opposite term (the `'?'` prefix is kept in the binding key), while
|
|
1608
1618
|
* consistency is enforced within the match — a variable seen twice must bind the
|
|
1609
|
-
*
|
|
1619
|
+
* same value (raw `!==`) or the whole match fails. A predicate mismatch or an
|
|
1610
1620
|
* arity (term-count) mismatch fails immediately; non-variable terms must be
|
|
1611
1621
|
* strictly (`===`) equal.
|
|
1612
1622
|
*
|
|
@@ -1648,7 +1658,7 @@ function matchFacts(pattern, candidate) {
|
|
|
1648
1658
|
* @remarks
|
|
1649
1659
|
* The pattern-instantiation step of the inferential reasoner: a `'?'`-prefixed
|
|
1650
1660
|
* string term that is present in `bindings` is replaced by its bound value;
|
|
1651
|
-
* every other term (constants and
|
|
1661
|
+
* every other term (constants and unbound variables alike) is kept verbatim. The
|
|
1652
1662
|
* returned fact is a fresh copy (`{ ...fact, terms }`) — the input is never
|
|
1653
1663
|
* mutated.
|
|
1654
1664
|
*
|
|
@@ -1675,7 +1685,7 @@ function instantiateFact(fact, bindings) {
|
|
|
1675
1685
|
}
|
|
1676
1686
|
/**
|
|
1677
1687
|
* Computes the confidence a set of matched premises contributes to a derived
|
|
1678
|
-
* fact — the product of each premise's
|
|
1688
|
+
* fact — the product of each premise's first matching fact's confidence.
|
|
1679
1689
|
*
|
|
1680
1690
|
* @remarks
|
|
1681
1691
|
* The confidence half of the inferential reasoner's forward derivation: each
|
|
@@ -1716,7 +1726,7 @@ function computePremiseConfidence(premises, index, bindings) {
|
|
|
1716
1726
|
* inferential reasoner's subject-injection step.
|
|
1717
1727
|
*
|
|
1718
1728
|
* @remarks
|
|
1719
|
-
* Every own subject field
|
|
1729
|
+
* Every own subject field except `id` becomes a `has(key, value)` fact at full
|
|
1720
1730
|
* `DEFAULT_CONFIDENCE`; `null` / `undefined` and any `object` (including arrays)
|
|
1721
1731
|
* value is skipped. The returned `trace` carries one line per injection plus a
|
|
1722
1732
|
* final count when at least one fact was produced, so no caller-owned
|
|
@@ -1794,21 +1804,21 @@ function findUnboundVariables(inference) {
|
|
|
1794
1804
|
return unbound;
|
|
1795
1805
|
}
|
|
1796
1806
|
/**
|
|
1797
|
-
* Determines whether a symbolic expression contains an
|
|
1807
|
+
* Determines whether a symbolic expression contains an unbound occurrence of a
|
|
1798
1808
|
* target variable.
|
|
1799
1809
|
*
|
|
1800
1810
|
* @remarks
|
|
1801
1811
|
* The variable-presence probe of the symbolic reasoner's isolation: a `variable`
|
|
1802
|
-
* node matches only when its name is `target`
|
|
1812
|
+
* node matches only when its name is `target` and `target` is not already in
|
|
1803
1813
|
* `bindings` (a pre-bound target is a known value, not an unknown to isolate); a
|
|
1804
1814
|
* `constant` never matches; an `operation` recurses into both operands (the
|
|
1805
|
-
* `right` operand may be absent on a unary node). The walk is an
|
|
1815
|
+
* `right` operand may be absent on a unary node). The walk is an iterative
|
|
1806
1816
|
* worklist (never recursive) with short-circuit `true` on the first hit, so it
|
|
1807
1817
|
* stays total on pathologically deep expression trees.
|
|
1808
1818
|
*
|
|
1809
1819
|
* @param expression - The expression to probe
|
|
1810
1820
|
* @param target - The variable name being sought
|
|
1811
|
-
* @param bindings - The known bindings (a bound target does
|
|
1821
|
+
* @param bindings - The known bindings (a bound target does not count as present)
|
|
1812
1822
|
* @returns True if an unbound `target` occurs in the expression; false otherwise
|
|
1813
1823
|
*
|
|
1814
1824
|
* @example
|
|
@@ -1834,7 +1844,7 @@ function containsVariable(expression, target, bindings) {
|
|
|
1834
1844
|
return false;
|
|
1835
1845
|
}
|
|
1836
1846
|
/**
|
|
1837
|
-
* Inverts a `x op right = value` step, solving for the
|
|
1847
|
+
* Inverts a `x op right = value` step, solving for the left operand `x`.
|
|
1838
1848
|
*
|
|
1839
1849
|
* @remarks
|
|
1840
1850
|
* The left-operand inverse of the symbolic reasoner's isolation: `add` inverts
|
|
@@ -1869,7 +1879,7 @@ function invertLeft(operator, value, rightValue) {
|
|
|
1869
1879
|
}
|
|
1870
1880
|
}
|
|
1871
1881
|
/**
|
|
1872
|
-
* Inverts a `left op x = value` step, solving for the
|
|
1882
|
+
* Inverts a `left op x = value` step, solving for the right operand `x`.
|
|
1873
1883
|
*
|
|
1874
1884
|
* @remarks
|
|
1875
1885
|
* The right-operand inverse of the symbolic reasoner's isolation: `add` inverts
|
|
@@ -1911,7 +1921,7 @@ function invertRight(operator, value, leftValue) {
|
|
|
1911
1921
|
* by zero is `NaN` (never a throw), the unary operations (`round` / `ceil` /
|
|
1912
1922
|
* `floor` / `abs`) ignore `right`, and `percentage` is `left * (right / 100)`.
|
|
1913
1923
|
* `operator` is typed `string` because untrusted definitions reach here
|
|
1914
|
-
* unchecked; the
|
|
1924
|
+
* unchecked; the only throwing path is the unknown-operator default, which
|
|
1915
1925
|
* throws `ReasonError('OPERATOR', …, { operator })` and is caught per equation
|
|
1916
1926
|
* upstream.
|
|
1917
1927
|
*
|
|
@@ -1982,7 +1992,7 @@ function resolveOperand(operation, operand) {
|
|
|
1982
1992
|
* The shared atom-walk behind both {@link extractConclusions} and the raters'
|
|
1983
1993
|
* conclusion merge: an `atom` yields itself; a compound flattens its operands in
|
|
1984
1994
|
* authored order, so a later operand's atoms follow an earlier one's. The walk is
|
|
1985
|
-
* an
|
|
1995
|
+
* an iterative explicit-stack traversal (never recursive), so it stays total on
|
|
1986
1996
|
* pathologically deep expression trees; a hole in an `operands` array is skipped,
|
|
1987
1997
|
* matching `flatMap`'s hole-skipping behavior.
|
|
1988
1998
|
*
|
|
@@ -2017,13 +2027,13 @@ function extractAtoms(expression) {
|
|
|
2017
2027
|
}
|
|
2018
2028
|
/**
|
|
2019
2029
|
* Flattens a logical conclusion expression into its asserted `field = value`
|
|
2020
|
-
* pairs
|
|
2030
|
+
* pairs, ignoring the connectives.
|
|
2021
2031
|
*
|
|
2022
2032
|
* @remarks
|
|
2023
2033
|
* The conclusion-extraction step of the logical reasoner's chaining: every
|
|
2024
2034
|
* `atom` inside the expression asserts its `formatField(check.field) =
|
|
2025
2035
|
* check.value` pair, and compounds are walked without regard to the connective
|
|
2026
|
-
* (an atom under `not` / `or` is asserted the same way).
|
|
2036
|
+
* (an atom under `not` / `or` is asserted the same way). A later operand wins on
|
|
2027
2037
|
* a key clash (`Object.assign` order). Recursion runs through this exported
|
|
2028
2038
|
* function itself; the derived-overlay keys are `formatField` strings (an array
|
|
2029
2039
|
* field path flattens to its dot-joined form).
|
|
@@ -2050,13 +2060,13 @@ function extractConclusions(expression) {
|
|
|
2050
2060
|
*
|
|
2051
2061
|
* @remarks
|
|
2052
2062
|
* The reported keys are the `formatField`-flattened overlay keys an array-path
|
|
2053
|
-
* conclusion atom writes
|
|
2054
|
-
* also reads
|
|
2063
|
+
* conclusion atom writes anywhere among `rules` that an array-path premise atom
|
|
2064
|
+
* also reads anywhere among `rules`. The cross-rule authoring-time footgun
|
|
2055
2065
|
* probe behind `LogicalReasoner.validate`'s overlay-key-mismatch warning: a
|
|
2056
|
-
* logical conclusion's derived overlay is a
|
|
2066
|
+
* logical conclusion's derived overlay is a flat record keyed by
|
|
2057
2067
|
* `formatField(check.field)` — an array `FieldPath` dot-joins into one string
|
|
2058
|
-
* key. A premise that reads the same field through a
|
|
2059
|
-
* that flat key correctly, but a premise that reads it through an
|
|
2068
|
+
* key. A premise that reads the same field through a dotted-string path resolves
|
|
2069
|
+
* that flat key correctly, but a premise that reads it through an array path
|
|
2060
2070
|
* calls `resolveField`, which descends key-by-key into nesting the flat
|
|
2061
2071
|
* overlay never created, so the chain silently fails to connect. Collects the
|
|
2062
2072
|
* flattened keys of every array-path conclusion atom across `rules` (once
|
|
@@ -2198,15 +2208,15 @@ function definitionToEnvelope(definition) {
|
|
|
2198
2208
|
}
|
|
2199
2209
|
/**
|
|
2200
2210
|
* Inserts `item` into an id-keyed collection, deduping any existing element
|
|
2201
|
-
* sharing its id, then placing it at the
|
|
2211
|
+
* sharing its id, then placing it at the end, or immediately after `target`.
|
|
2202
2212
|
*
|
|
2203
2213
|
* @remarks
|
|
2204
|
-
* Insertion
|
|
2214
|
+
* Insertion dedupes on the id first: `filtered` is `items` with every `item.id`
|
|
2205
2215
|
* twin removed, because an input array may already carry same-id twins.
|
|
2206
|
-
* Re-appending an existing id therefore
|
|
2216
|
+
* Re-appending an existing id therefore repositions it rather than updating it
|
|
2207
2217
|
* in place — {@link replaceById} is the position-preserving alternative. With
|
|
2208
2218
|
* no `target`, `item` lands at the end; with a `target`, it lands immediately
|
|
2209
|
-
* after the element whose `id === target` (searched in the
|
|
2219
|
+
* after the element whose `id === target` (searched in the deduped array). A
|
|
2210
2220
|
* `target` naming no element throws {@link ReasonError} (`'TARGET'`).
|
|
2211
2221
|
*
|
|
2212
2222
|
* @typeParam T - An id-carrying element type
|
|
@@ -2241,7 +2251,7 @@ function appendById(items, item, target) {
|
|
|
2241
2251
|
}
|
|
2242
2252
|
/**
|
|
2243
2253
|
* Inserts `item` into an id-keyed collection, deduping any existing element
|
|
2244
|
-
* sharing its id, then placing it at the
|
|
2254
|
+
* sharing its id, then placing it at the start, or immediately before `target`.
|
|
2245
2255
|
*
|
|
2246
2256
|
* @remarks
|
|
2247
2257
|
* Mirrors {@link appendById}'s dedup-then-insert semantics exactly, only the
|
|
@@ -2281,7 +2291,7 @@ function prependById(items, item, target) {
|
|
|
2281
2291
|
];
|
|
2282
2292
|
}
|
|
2283
2293
|
/**
|
|
2284
|
-
* Swaps the element sharing `item.id`
|
|
2294
|
+
* Swaps the element sharing `item.id` in place, preserving its position.
|
|
2285
2295
|
*
|
|
2286
2296
|
* @remarks
|
|
2287
2297
|
* The position-preserving update primitive — unlike {@link appendById}, which
|
|
@@ -2338,11 +2348,11 @@ function removeById(items, id) {
|
|
|
2338
2348
|
*
|
|
2339
2349
|
* @remarks
|
|
2340
2350
|
* A Strategic-Merge-Patch-style id-keyed upsert:
|
|
2341
|
-
* the result is ordered by `incoming`'s id order
|
|
2351
|
+
* the result is ordered by `incoming`'s id order first (each element resolved
|
|
2342
2352
|
* through `resolve` when its id also exists in `base`, defaulting to
|
|
2343
|
-
* incoming-wins-wholesale),
|
|
2353
|
+
* incoming-wins-wholesale), then the `base`-only survivors in `base`'s own
|
|
2344
2354
|
* order (retained, never deleted — merge is additive). Same-id twins within
|
|
2345
|
-
*
|
|
2355
|
+
* either input are deduped to their first occurrence.
|
|
2346
2356
|
*
|
|
2347
2357
|
* @typeParam T - An id-carrying element type
|
|
2348
2358
|
* @param base - The base collection
|
|
@@ -2381,7 +2391,7 @@ function mergeById(base, incoming, resolve) {
|
|
|
2381
2391
|
* insert at the end, or immediately after `target`.
|
|
2382
2392
|
*
|
|
2383
2393
|
* @remarks
|
|
2384
|
-
* Group order is
|
|
2394
|
+
* Group order is cosmetic (group aggregation is order-independent) but honored
|
|
2385
2395
|
* uniformly, same as every `append*` helper. Composes with {@link appendFactor}:
|
|
2386
2396
|
* `appendGroup(def, appendFactor(group, factor))`.
|
|
2387
2397
|
*
|
|
@@ -2428,8 +2438,8 @@ function prependGroup(definition, group, target) {
|
|
|
2428
2438
|
};
|
|
2429
2439
|
}
|
|
2430
2440
|
/**
|
|
2431
|
-
* Swaps the group sharing `group.id` in a {@link QuantitativeDefinition}
|
|
2432
|
-
*
|
|
2441
|
+
* Swaps the group sharing `group.id` in a {@link QuantitativeDefinition} in
|
|
2442
|
+
* place, preserving its position (appended when absent).
|
|
2433
2443
|
*
|
|
2434
2444
|
* @param definition - The definition to update
|
|
2435
2445
|
* @param group - The replacement group
|
|
@@ -2476,9 +2486,9 @@ function removeGroup(definition, id) {
|
|
|
2476
2486
|
* at the end, or immediately after `target`.
|
|
2477
2487
|
*
|
|
2478
2488
|
* @remarks
|
|
2479
|
-
* Factor order is
|
|
2489
|
+
* Factor order is load-bearing: the same-priority tiebreak is declaration
|
|
2480
2490
|
* order ({@link sortByPriority} is a stable ascending sort). Operates on the
|
|
2481
|
-
* factor's
|
|
2491
|
+
* factor's direct container — compose into a definition through
|
|
2482
2492
|
* `appendGroup(def, appendFactor(group, factor))`.
|
|
2483
2493
|
*
|
|
2484
2494
|
* @param group - The group to insert into
|
|
@@ -2524,8 +2534,8 @@ function prependFactor(group, factor, target) {
|
|
|
2524
2534
|
};
|
|
2525
2535
|
}
|
|
2526
2536
|
/**
|
|
2527
|
-
* Swaps the factor sharing `factor.id` in a {@link FactorGroup}
|
|
2528
|
-
* preserving its position (
|
|
2537
|
+
* Swaps the factor sharing `factor.id` in a {@link FactorGroup} in place,
|
|
2538
|
+
* preserving its position (appended when absent).
|
|
2529
2539
|
*
|
|
2530
2540
|
* @param group - The group to update
|
|
2531
2541
|
* @param factor - The replacement factor
|
|
@@ -2571,7 +2581,7 @@ function removeFactor(group, id) {
|
|
|
2571
2581
|
* at the end, or immediately after `target`.
|
|
2572
2582
|
*
|
|
2573
2583
|
* @remarks
|
|
2574
|
-
* Order is
|
|
2584
|
+
* Order is load-bearing: the forward conclusion is the last declared
|
|
2575
2585
|
* non-disabled rule, so `appendRule` without a `target` makes the new rule the
|
|
2576
2586
|
* conclusion.
|
|
2577
2587
|
*
|
|
@@ -2618,8 +2628,8 @@ function prependRule(definition, rule, target) {
|
|
|
2618
2628
|
};
|
|
2619
2629
|
}
|
|
2620
2630
|
/**
|
|
2621
|
-
* Swaps the rule sharing `rule.id` in a {@link LogicalDefinition}
|
|
2622
|
-
* preserving its position (
|
|
2631
|
+
* Swaps the rule sharing `rule.id` in a {@link LogicalDefinition} in place,
|
|
2632
|
+
* preserving its position (appended when absent).
|
|
2623
2633
|
*
|
|
2624
2634
|
* @param definition - The definition to update
|
|
2625
2635
|
* @param rule - The replacement rule
|
|
@@ -2666,8 +2676,8 @@ function removeRule(definition, id) {
|
|
|
2666
2676
|
* then-insert at the end, or immediately after `target`.
|
|
2667
2677
|
*
|
|
2668
2678
|
* @remarks
|
|
2669
|
-
* Order is
|
|
2670
|
-
*
|
|
2679
|
+
* Order is load-bearing: equations solve strictly in order and each rounded
|
|
2680
|
+
* solution feeds forward.
|
|
2671
2681
|
*
|
|
2672
2682
|
* @param definition - The definition to insert into
|
|
2673
2683
|
* @param equation - The equation to insert
|
|
@@ -2712,8 +2722,8 @@ function prependEquation(definition, equation, target) {
|
|
|
2712
2722
|
};
|
|
2713
2723
|
}
|
|
2714
2724
|
/**
|
|
2715
|
-
* Swaps the equation sharing `equation.id` in a {@link SymbolicDefinition}
|
|
2716
|
-
*
|
|
2725
|
+
* Swaps the equation sharing `equation.id` in a {@link SymbolicDefinition} in
|
|
2726
|
+
* place, preserving its position (appended when absent).
|
|
2717
2727
|
*
|
|
2718
2728
|
* @param definition - The definition to update
|
|
2719
2729
|
* @param equation - The replacement equation
|
|
@@ -2787,7 +2797,7 @@ function addVariable(definition, name, value) {
|
|
|
2787
2797
|
* Removes one entry of a {@link SymbolicDefinition}'s `variables`.
|
|
2788
2798
|
*
|
|
2789
2799
|
* @remarks
|
|
2790
|
-
* The destructure-rest form
|
|
2800
|
+
* The destructure-rest form omits the key entirely (never sets it to
|
|
2791
2801
|
* `undefined`), keeping the result exact-record valid. A no-op (fresh copy)
|
|
2792
2802
|
* when `name` is absent.
|
|
2793
2803
|
*
|
|
@@ -2814,7 +2824,7 @@ function removeVariable(definition, name) {
|
|
|
2814
2824
|
* insert at the end, or immediately after `target`.
|
|
2815
2825
|
*
|
|
2816
2826
|
* @remarks
|
|
2817
|
-
* `Fact.id` is an
|
|
2827
|
+
* `Fact.id` is an authoring label — the runtime content-dedups facts by
|
|
2818
2828
|
* predicate+arity+terms ({@link factToKey}), independently of this helper's
|
|
2819
2829
|
* id-keyed dedup.
|
|
2820
2830
|
*
|
|
@@ -2861,8 +2871,8 @@ function prependFact(definition, fact, target) {
|
|
|
2861
2871
|
};
|
|
2862
2872
|
}
|
|
2863
2873
|
/**
|
|
2864
|
-
* Swaps the fact sharing `fact.id` in an {@link InferentialDefinition}
|
|
2865
|
-
*
|
|
2874
|
+
* Swaps the fact sharing `fact.id` in an {@link InferentialDefinition} in
|
|
2875
|
+
* place, preserving its position (appended when absent).
|
|
2866
2876
|
*
|
|
2867
2877
|
* @param definition - The definition to update
|
|
2868
2878
|
* @param fact - The replacement fact
|
|
@@ -2909,7 +2919,7 @@ function removeFact(definition, id) {
|
|
|
2909
2919
|
* dedup-then-insert at the end, or immediately after `target`.
|
|
2910
2920
|
*
|
|
2911
2921
|
* @remarks
|
|
2912
|
-
* Order is
|
|
2922
|
+
* Order is load-bearing: backward proving iterates in declaration order and
|
|
2913
2923
|
* returns on first success.
|
|
2914
2924
|
*
|
|
2915
2925
|
* @param definition - The definition to insert into
|
|
@@ -2962,7 +2972,7 @@ function prependInference(definition, inference, target) {
|
|
|
2962
2972
|
}
|
|
2963
2973
|
/**
|
|
2964
2974
|
* Swaps the inference sharing `inference.id` in an {@link InferentialDefinition}
|
|
2965
|
-
*
|
|
2975
|
+
* in place, preserving its position (appended when absent).
|
|
2966
2976
|
*
|
|
2967
2977
|
* @param definition - The definition to update
|
|
2968
2978
|
* @param inference - The replacement inference
|
|
@@ -3009,10 +3019,10 @@ function removeInference(definition, id) {
|
|
|
3009
3019
|
* Reconciles two {@link QuantitativeDefinition}s onto `base`'s id.
|
|
3010
3020
|
*
|
|
3011
3021
|
* @remarks
|
|
3012
|
-
* The merge is
|
|
3022
|
+
* The merge is additive: a base-only group survives into the result and is
|
|
3013
3023
|
* never deleted, and a scalar absent from `incoming` keeps its base value —
|
|
3014
3024
|
* merge never clears a field, which is what {@link clearQuantitativeDefinition}
|
|
3015
|
-
* is for. `groups` merges through {@link mergeById}; a matched (same-id)
|
|
3025
|
+
* is for. `groups` merges through {@link mergeById}; a matched (same-id) pair of
|
|
3016
3026
|
* groups recurses one level deeper — their `factors` also merge through
|
|
3017
3027
|
* `mergeById` — the one exception to incoming-wins-wholesale. Every other
|
|
3018
3028
|
* scalar / value-object field is incoming-wins-when-present, else base kept.
|
|
@@ -3050,7 +3060,7 @@ function mergeQuantitativeDefinition(base, incoming) {
|
|
|
3050
3060
|
* Reconciles two {@link LogicalDefinition}s onto `base`'s id.
|
|
3051
3061
|
*
|
|
3052
3062
|
* @remarks
|
|
3053
|
-
* The merge is
|
|
3063
|
+
* The merge is additive: a base-only rule survives into the result and is never
|
|
3054
3064
|
* deleted, and a scalar absent from `incoming` keeps its base value — merge
|
|
3055
3065
|
* never clears a field, which is what {@link clearLogicalDefinition} is for.
|
|
3056
3066
|
* `rules` merges through {@link mergeById} (incoming-wins-wholesale on a matched
|
|
@@ -3083,7 +3093,7 @@ function mergeLogicalDefinition(base, incoming) {
|
|
|
3083
3093
|
* Reconciles two {@link SymbolicDefinition}s onto `base`'s id.
|
|
3084
3094
|
*
|
|
3085
3095
|
* @remarks
|
|
3086
|
-
* The merge is
|
|
3096
|
+
* The merge is additive: a base-only equation or variable survives into the
|
|
3087
3097
|
* result and is never deleted, and a scalar absent from `incoming` keeps its
|
|
3088
3098
|
* base value — merge never clears a field, which is what
|
|
3089
3099
|
* {@link clearSymbolicDefinition} is for. `equations` merges through
|
|
@@ -3123,7 +3133,7 @@ function mergeSymbolicDefinition(base, incoming) {
|
|
|
3123
3133
|
* Reconciles two {@link InferentialDefinition}s onto `base`'s id.
|
|
3124
3134
|
*
|
|
3125
3135
|
* @remarks
|
|
3126
|
-
* The merge is
|
|
3136
|
+
* The merge is additive: a base-only inference or fact survives into the result
|
|
3127
3137
|
* and is never deleted, and a scalar absent from `incoming` keeps its base
|
|
3128
3138
|
* value — merge never clears a field, which is what
|
|
3129
3139
|
* {@link clearInferentialDefinition} is for. `inferences` and `facts` each
|
|
@@ -3234,7 +3244,7 @@ function clearInferentialDefinition(definition, key) {
|
|
|
3234
3244
|
* Upserts one field of a {@link Subject} — copy-on-write spread.
|
|
3235
3245
|
*
|
|
3236
3246
|
* @remarks
|
|
3237
|
-
* Named `assignField` rather than `setField` because it
|
|
3247
|
+
* Named `assignField` rather than `setField` because it returns a fresh subject
|
|
3238
3248
|
* instead of writing into the one it is given — `set*` reads as an in-place
|
|
3239
3249
|
* write. Id-agnostic: overwrites an `id` key like any other field — id
|
|
3240
3250
|
* protection is an entity's job, not this helper's.
|
|
@@ -3261,7 +3271,7 @@ function assignField(subject, key, value) {
|
|
|
3261
3271
|
* Deletes one field of a {@link Subject} — destructure-rest omit.
|
|
3262
3272
|
*
|
|
3263
3273
|
* @remarks
|
|
3264
|
-
* The key is
|
|
3274
|
+
* The key is deleted entirely (never set to `undefined`), keeping the result
|
|
3265
3275
|
* exact-record valid. A no-op (fresh copy) when `key` is absent.
|
|
3266
3276
|
*
|
|
3267
3277
|
* @param subject - The subject to update
|
|
@@ -3316,8 +3326,8 @@ function mergeSubjects(base, incoming) {
|
|
|
3316
3326
|
* When `subject.id` is a string, each clone's id is minted
|
|
3317
3327
|
* `` `${baseId}-${index}` `` (index from `0`); with no string `id`, the clones
|
|
3318
3328
|
* pass through unchanged (still fresh copies). Pure and deterministic — the
|
|
3319
|
-
* same input always produces the same output (run-twice equality) — and
|
|
3320
|
-
*
|
|
3329
|
+
* same input always produces the same output (run-twice equality) — and emits
|
|
3330
|
+
* nothing. `count <= 0` yields an empty array.
|
|
3321
3331
|
*
|
|
3322
3332
|
* @param subject - The subject to clone
|
|
3323
3333
|
* @param count - How many clones to produce
|
|
@@ -3347,8 +3357,8 @@ function repeatSubject(subject, count) {
|
|
|
3347
3357
|
*
|
|
3348
3358
|
* @remarks
|
|
3349
3359
|
* The safe inverse of the builders: `parseJSONAs` composed with the data guard
|
|
3350
|
-
* {@link isDefinition}. A built definition body
|
|
3351
|
-
* `JSON.stringify(definition)` round-trips through `parseDefinition`.
|
|
3360
|
+
* {@link isDefinition}. A built definition body is the durable JSON payload —
|
|
3361
|
+
* `JSON.stringify(definition)` round-trips through `parseDefinition`. The
|
|
3352
3362
|
* authoring hazards: a required `Check.value: undefined` drops its key on
|
|
3353
3363
|
* `JSON.stringify` (author `null` instead), and a `Fact.terms` element of
|
|
3354
3364
|
* `undefined` serializes to `null` (terms must be JSON-safe scalars/strings).
|
|
@@ -3375,16 +3385,16 @@ function parseDefinition(json) {
|
|
|
3375
3385
|
* {@link ReasonerInterface}s.
|
|
3376
3386
|
*
|
|
3377
3387
|
* @remarks
|
|
3378
|
-
* Holds
|
|
3388
|
+
* Holds no strategy-specific logic: dispatch is purely a registry lookup by
|
|
3379
3389
|
* `definition.reasoning` (one reasoner per reasoning; re-registration
|
|
3380
3390
|
* replaces). A missing reasoner throws `MISSING` and a pre-run validation
|
|
3381
|
-
* failure (when the `validate` option is on) throws `INVALID` —
|
|
3382
|
-
* `bail` and
|
|
3391
|
+
* failure (when the `validate` option is on) throws `INVALID` — each bypasses
|
|
3392
|
+
* `bail` and emits nothing. A reasoner throw emits `error` with the raw thrown
|
|
3383
3393
|
* value, then rethrows under `bail: true` (the default) or converts to a
|
|
3384
|
-
* type-shaped failure result under `bail: false`; only
|
|
3394
|
+
* type-shaped failure result under `bail: false`; only a successful result emits
|
|
3385
3395
|
* `reason` (synchronously, before returning). The batch overload maps subjects
|
|
3386
3396
|
* in order (validation, when on, repeats per subject). `destroy()` clears the
|
|
3387
|
-
* registry, emits `destroy`, then destroys the emitter
|
|
3397
|
+
* registry, emits `destroy`, then destroys the emitter last and is
|
|
3388
3398
|
* idempotent; every other method afterwards throws `DESTROYED` — only the
|
|
3389
3399
|
* {@link emitter} getter keeps working.
|
|
3390
3400
|
*
|
|
@@ -3503,14 +3513,14 @@ var Reason = class {
|
|
|
3503
3513
|
* quantitative and logical reasoners.
|
|
3504
3514
|
*
|
|
3505
3515
|
* @remarks
|
|
3506
|
-
*
|
|
3516
|
+
* Total and strict: `evaluate` never throws (an unknown operator is caught and
|
|
3507
3517
|
* surfaced as `CheckResult.error` with `met: false`) and never coerces —
|
|
3508
3518
|
* `equals` / `not` are raw `===` / `!==`, the ordering operators demand numbers
|
|
3509
|
-
* on
|
|
3510
|
-
* not met for either — `none` is
|
|
3511
|
-
* input), while `outside`
|
|
3519
|
+
* on each side, `any` / `none` demand an array expected value (a non-array is
|
|
3520
|
+
* not met for either — `none` is not the raw complement of `any` on malformed
|
|
3521
|
+
* input), while `outside` is the pure negation of `between` (so a malformed
|
|
3512
3522
|
* range is `outside`). Fields resolve through the core `resolveField` — a string
|
|
3513
|
-
* is
|
|
3523
|
+
* is a single key, an array descends. Stateless and deterministic.
|
|
3514
3524
|
*
|
|
3515
3525
|
* @example
|
|
3516
3526
|
* ```ts
|
|
@@ -3574,7 +3584,7 @@ var Evaluator = class {
|
|
|
3574
3584
|
* per-factor pipeline stage.
|
|
3575
3585
|
*
|
|
3576
3586
|
* @remarks
|
|
3577
|
-
*
|
|
3587
|
+
* Total: never throws. Absent-`operand` defaults are operation-specific —
|
|
3578
3588
|
* identity-preserving `1` for `multiply` / `divide` / `power`, `0` for every
|
|
3579
3589
|
* other binary operation; `round` / `ceil` / `floor` / `abs` are unary and
|
|
3580
3590
|
* ignore the operand. `divide` by zero yields `NaN` (deliberately not JS's
|
|
@@ -3614,11 +3624,11 @@ var Transformer = class {
|
|
|
3614
3624
|
* reasoner's group and definition combiner.
|
|
3615
3625
|
*
|
|
3616
3626
|
* @remarks
|
|
3617
|
-
*
|
|
3627
|
+
* Total: never throws. Empty-input identities: `sum` / `average` → `0`,
|
|
3618
3628
|
* `product` → `1`, `minimum` / `maximum` → `NaN` (the deliberate "no data"
|
|
3619
|
-
* signal). Weights are honored
|
|
3629
|
+
* signal). Weights are honored only when their length matches `values` exactly
|
|
3620
3630
|
* (otherwise silently unweighted): a weight multiplies into a `sum`, acts as an
|
|
3621
|
-
*
|
|
3631
|
+
* exponent for a `product`, is the weight of a weighted mean for `average`
|
|
3622
3632
|
* (a zero total weight yields `0`, never a division blow-up), and is ignored by
|
|
3623
3633
|
* `minimum` / `maximum`. An unknown aggregation yields `0`. Stateless and
|
|
3624
3634
|
* deterministic.
|
|
@@ -3664,21 +3674,21 @@ var Aggregator = class {
|
|
|
3664
3674
|
* Performs factor-based numeric scoring.
|
|
3665
3675
|
*
|
|
3666
3676
|
* @remarks
|
|
3667
|
-
* Each factor runs a fixed pipeline: checks gate (
|
|
3668
|
-
* (`fallback` when unresolvable) → finite check → transforms chain →
|
|
3669
|
-
* clamp → finite recheck. Factors evaluate in stable ascending `priority`
|
|
3677
|
+
* Each factor runs a fixed pipeline: checks gate (every check met) → source
|
|
3678
|
+
* resolve (`fallback` when unresolvable) → finite check → transforms chain →
|
|
3679
|
+
* bounds clamp → finite recheck. Factors evaluate in stable ascending `priority`
|
|
3670
3680
|
* order; a `strict` group is all-or-nothing; a group's value is its `base` plus
|
|
3671
|
-
* the weighted aggregation of its
|
|
3681
|
+
* the weighted aggregation of its applied factors, clamped (never rounded); the
|
|
3672
3682
|
* definition's value is its `base` plus the unweighted aggregation of the
|
|
3673
|
-
*
|
|
3683
|
+
* applied groups' values, clamped, then rounded to `precision`. A
|
|
3674
3684
|
* required-factor failure or non-finite value appends an error (`success:
|
|
3675
3685
|
* false`) without aborting — the numeric `value` is always computed. The
|
|
3676
|
-
* definition-level value is finite-checked
|
|
3686
|
+
* definition-level value is finite-checked after rounding: a non-finite
|
|
3677
3687
|
* aggregate (a `minimum` / `maximum` over zero applied groups) appends an error
|
|
3678
3688
|
* while the `NaN` stays visible in `value`. Field sources coerce through the
|
|
3679
3689
|
* contracts `parseNumberField`: a non-finite subject number or a non-numeric
|
|
3680
3690
|
* string is unresolvable and takes the fallback path. Lookup sources read only
|
|
3681
|
-
*
|
|
3691
|
+
* the table's own keys, and a missing / `null` field falls back directly. Nothing
|
|
3682
3692
|
* mutates its inputs; fully deterministic.
|
|
3683
3693
|
*
|
|
3684
3694
|
* @example
|
|
@@ -3910,18 +3920,18 @@ var QuantitativeReasoner = class {
|
|
|
3910
3920
|
* @remarks
|
|
3911
3921
|
* Forward chaining is a naive fixpoint capped at `depth` iterations: rules run
|
|
3912
3922
|
* in ascending `priority` order each pass, and a firing rule's conclusion atoms
|
|
3913
|
-
* become a derived overlay that
|
|
3923
|
+
* become a derived overlay that shadows same-named subject fields on later
|
|
3914
3924
|
* passes (derived keys are `formatField(check.field)` strings). Convergence —
|
|
3915
3925
|
* one full pass with no new derivation — appends a trace containing
|
|
3916
3926
|
* `converged`. Final rule results re-evaluate against the settled overlay in
|
|
3917
|
-
*
|
|
3918
|
-
* overall `conclusion` is whether the
|
|
3919
|
-
* proves
|
|
3927
|
+
* original rule order (forward) / priority-sorted order (backward), and the
|
|
3928
|
+
* overall `conclusion` is whether the last result applied. Backward chaining
|
|
3929
|
+
* proves every rule goal-first: an unmet premise triggers sub-goal search
|
|
3920
3930
|
* through rules whose conclusion atoms assert the needed `field = value` pair,
|
|
3921
3931
|
* guarded by a visited-rule set (cycle-safe) plus the depth cap; `not` succeeds
|
|
3922
3932
|
* when its operand cannot be established (negation-as-failure) and `implies` is
|
|
3923
|
-
* vacuously true on an unprovable antecedent. Expression evaluation is
|
|
3924
|
-
* (no short-circuit); conclusion extraction
|
|
3933
|
+
* vacuously true on an unprovable antecedent. Expression evaluation is eager
|
|
3934
|
+
* (no short-circuit); conclusion extraction ignores connectives — every atom
|
|
3925
3935
|
* inside a conclusion is asserted, even under `not` / `or`. Overlay bookkeeping
|
|
3926
3936
|
* compares with SameValueZero (`equalValues`), so a NaN-valued conclusion
|
|
3927
3937
|
* derives once and the fixpoint converges. Nothing mutates its inputs; fully
|
|
@@ -4254,16 +4264,16 @@ var LogicalReasoner = class {
|
|
|
4254
4264
|
* @remarks
|
|
4255
4265
|
* Bindings seed from `definition.variables`, then numeric subject fields (a
|
|
4256
4266
|
* finite number or a numeric string, coerced through the contracts
|
|
4257
|
-
* `parseNumber`)
|
|
4267
|
+
* `parseNumber`) override same-named variables — the `id` field is skipped.
|
|
4258
4268
|
* Equations solve strictly in order: when the `target` is unbound and appears
|
|
4259
|
-
* on exactly
|
|
4269
|
+
* on exactly one side, it is isolated by peeling invertible operations (`add` /
|
|
4260
4270
|
* `subtract` / `multiply` / `divide`); a non-invertible operation, a target on
|
|
4261
4271
|
* both sides of an operation, or an unbound variable throws internally — the
|
|
4262
|
-
* throw is caught
|
|
4272
|
+
* throw is caught per equation and surfaced as a result error (`Equation
|
|
4263
4273
|
* "<id>": <message>` plus a `FAILED` trace) while later equations still run.
|
|
4264
4274
|
* Inversion or division by zero yields `NaN`, caught by the non-finite check.
|
|
4265
|
-
* A solved value is rounded to `precision`
|
|
4266
|
-
* see the rounded value; `solutions` reads
|
|
4275
|
+
* A solved value is rounded to `precision` before binding, so later equations
|
|
4276
|
+
* see the rounded value; `solutions` reads the settled bindings keyed by each
|
|
4267
4277
|
* equation's target (a failed equation's target still appears when bound
|
|
4268
4278
|
* elsewhere). Nothing mutates its inputs; fully deterministic.
|
|
4269
4279
|
*
|
|
@@ -4456,7 +4466,7 @@ var SymbolicReasoner = class {
|
|
|
4456
4466
|
*
|
|
4457
4467
|
* @remarks
|
|
4458
4468
|
* A string term starting with `?` is a unification variable — matching is
|
|
4459
|
-
* positional and
|
|
4469
|
+
* positional and bidirectional (variables may sit in facts as well as
|
|
4460
4470
|
* patterns), with binding consistency enforced within one match and across
|
|
4461
4471
|
* premises through pre-instantiation. Scalar subject fields (except `id`;
|
|
4462
4472
|
* `null` / `undefined` / objects / arrays skipped) inject as
|
|
@@ -4467,8 +4477,8 @@ var SymbolicReasoner = class {
|
|
|
4467
4477
|
* duplicate facts (same predicate, arity, and SameValueZero-equal terms — a
|
|
4468
4478
|
* NaN term derives once and converges) are never re-derived. Backward chaining
|
|
4469
4479
|
* proves each inference's conclusion in
|
|
4470
|
-
* declaration order and
|
|
4471
|
-
* (confidence = the inference's own — premise confidences are
|
|
4480
|
+
* declaration order and returns on the first success with one derived fact
|
|
4481
|
+
* (confidence = the inference's own — premise confidences are not propagated)
|
|
4472
4482
|
* plus its {@link ProofNode} tree; recursion is guarded only by the depth cap.
|
|
4473
4483
|
* Deriving nothing is still success. Nothing mutates its inputs; fully
|
|
4474
4484
|
* deterministic.
|
|
@@ -4800,17 +4810,17 @@ var Collection = class {
|
|
|
4800
4810
|
* kind-free manager over a symbolic definition's `equations`.
|
|
4801
4811
|
*
|
|
4802
4812
|
* @remarks
|
|
4803
|
-
*
|
|
4813
|
+
* Owns its `equations` as a private {@link Collection} — copy-on-write state
|
|
4804
4814
|
* shared by composition with the other list managers — plus its own
|
|
4805
4815
|
* {@link Emitter} over {@link EquationManagerEventMap}. Equation order is
|
|
4806
|
-
*
|
|
4807
|
-
*
|
|
4808
|
-
*
|
|
4816
|
+
* load-bearing — equations solve strictly in order and each rounded solution
|
|
4817
|
+
* feeds forward. `remove` is the batch family (array form declared
|
|
4818
|
+
* first): no argument removes every equation, one id removes that equation, an
|
|
4809
4819
|
* id list removes those equations and returns true only when every named id
|
|
4810
4820
|
* existed. It emits one `remove` per equation actually removed.
|
|
4811
4821
|
* `seat` is the owning builder's silent bulk re-seat
|
|
4812
4822
|
* channel (used by `merge`). `destroy()` is idempotent and tears the emitter
|
|
4813
|
-
* down
|
|
4823
|
+
* down last; any other call after it throws `ReasonError('DESTROYED', …)`.
|
|
4814
4824
|
*
|
|
4815
4825
|
* @example
|
|
4816
4826
|
* ```ts
|
|
@@ -4893,17 +4903,17 @@ var EquationManager = class {
|
|
|
4893
4903
|
* manager over an inferential definition's `facts`.
|
|
4894
4904
|
*
|
|
4895
4905
|
* @remarks
|
|
4896
|
-
*
|
|
4906
|
+
* Owns its `facts` as a private {@link Collection} — copy-on-write state shared
|
|
4897
4907
|
* by composition with the other list managers — plus its own {@link Emitter}
|
|
4898
|
-
* over {@link FactManagerEventMap}. `Fact.id` is an
|
|
4908
|
+
* over {@link FactManagerEventMap}. `Fact.id` is an authoring label — the
|
|
4899
4909
|
* runtime content-dedups facts by predicate+arity+terms, independently of this
|
|
4900
4910
|
* manager's id-keyed dedup. `remove` is the batch family (array form declared
|
|
4901
|
-
*
|
|
4911
|
+
* first): no argument removes every fact, one id removes that fact, an id list
|
|
4902
4912
|
* removes those facts and returns true only when every named id existed. It
|
|
4903
4913
|
* emits one `remove` per fact actually removed.
|
|
4904
4914
|
* `seat` is the owning builder's silent bulk re-seat
|
|
4905
4915
|
* channel (used by `merge`). `destroy()` is idempotent and tears the emitter
|
|
4906
|
-
* down
|
|
4916
|
+
* down last; any other call after it throws `ReasonError('DESTROYED', …)`.
|
|
4907
4917
|
*
|
|
4908
4918
|
* @example
|
|
4909
4919
|
* ```ts
|
|
@@ -4977,24 +4987,25 @@ var FactManager = class {
|
|
|
4977
4987
|
//#endregion
|
|
4978
4988
|
//#region src/core/builders/managers/FactorManager.ts
|
|
4979
4989
|
/**
|
|
4980
|
-
* Implements the {@link FactorManagerInterface} — the
|
|
4981
|
-
* manager: factors nest inside groups, so it holds
|
|
4990
|
+
* Implements the {@link FactorManagerInterface} — the one divergent
|
|
4991
|
+
* manager: factors nest inside groups, so it holds no collection state of its
|
|
4982
4992
|
* own and threads a required `groupId` locator.
|
|
4983
4993
|
*
|
|
4984
4994
|
* @remarks
|
|
4985
4995
|
* Constructor-injected with the sibling {@link GroupManagerInterface}: each
|
|
4986
4996
|
* write verb reads the located group (`groups.group(groupId)`), applies the
|
|
4987
|
-
* factor-level pure helper ({@link appendFactor}
|
|
4997
|
+
* factor-level pure helper ({@link appendFactor}, {@link prependFactor},
|
|
4998
|
+
* {@link replaceFactor}, or {@link removeFactor}), and writes the updated
|
|
4988
4999
|
* group back through `groups.replace(…)`. A `groupId` naming no existing group
|
|
4989
|
-
* throws `ReasonError('TARGET', …, { groupId })`. It still owns its
|
|
5000
|
+
* throws `ReasonError('TARGET', …, { groupId })`. It still owns its own
|
|
4990
5001
|
* {@link Emitter} over {@link FactorManagerEventMap} (factor-id payloads).
|
|
4991
5002
|
* `remove` is the batch family behind the leading `groupId` locator (array form
|
|
4992
|
-
* declared
|
|
5003
|
+
* declared first): the locator alone removes every factor of that group, a
|
|
4993
5004
|
* further id removes that factor, a further id list removes those factors and
|
|
4994
5005
|
* returns true only when every named id existed. It emits one `remove` per
|
|
4995
5006
|
* factor actually removed, each paired with a `replace` on the sibling
|
|
4996
5007
|
* `GroupManagerInterface` for the containing group.
|
|
4997
|
-
* `destroy()` is idempotent and tears the emitter down
|
|
5008
|
+
* `destroy()` is idempotent and tears the emitter down last; any other call
|
|
4998
5009
|
* after it throws `ReasonError('DESTROYED', …)`.
|
|
4999
5010
|
*
|
|
5000
5011
|
* @example
|
|
@@ -5093,16 +5104,16 @@ var FactorManager = class {
|
|
|
5093
5104
|
* manager over a quantitative definition's `groups`.
|
|
5094
5105
|
*
|
|
5095
5106
|
* @remarks
|
|
5096
|
-
*
|
|
5107
|
+
* Owns its `groups` as a private {@link Collection} — copy-on-write state
|
|
5097
5108
|
* shared by composition with the other list managers — plus its own
|
|
5098
5109
|
* {@link Emitter} over {@link GroupManagerEventMap}. Every write verb delegates
|
|
5099
|
-
* to the collection, then emits (the affected group id)
|
|
5100
|
-
* `remove` is the batch family (array form declared
|
|
5110
|
+
* to the collection, then emits (the affected group id) after the mutation.
|
|
5111
|
+
* `remove` is the batch family (array form declared first): no argument removes
|
|
5101
5112
|
* every group, one id removes that group, an id list removes those groups and
|
|
5102
5113
|
* returns true only when every named id existed. It emits one `remove` per
|
|
5103
5114
|
* group actually removed.
|
|
5104
5115
|
* `seat` is the owning builder's silent bulk re-seat channel (used by `merge`).
|
|
5105
|
-
* `destroy()` is idempotent and tears the emitter down
|
|
5116
|
+
* `destroy()` is idempotent and tears the emitter down last; any other call
|
|
5106
5117
|
* after it throws `ReasonError('DESTROYED', …)`.
|
|
5107
5118
|
*
|
|
5108
5119
|
* @example
|
|
@@ -5181,16 +5192,16 @@ var GroupManager = class {
|
|
|
5181
5192
|
* kind-free manager over an inferential definition's `inferences`.
|
|
5182
5193
|
*
|
|
5183
5194
|
* @remarks
|
|
5184
|
-
*
|
|
5195
|
+
* Owns its `inferences` as a private {@link Collection} — copy-on-write state
|
|
5185
5196
|
* shared by composition with the other list managers — plus its own
|
|
5186
5197
|
* {@link Emitter} over {@link InferenceManagerEventMap}. Inference order is
|
|
5187
|
-
*
|
|
5188
|
-
* first success. `remove` is the batch family (array form declared
|
|
5198
|
+
* load-bearing — backward proving iterates in declaration order and returns on
|
|
5199
|
+
* first success. `remove` is the batch family (array form declared first): no
|
|
5189
5200
|
* argument removes every inference, one id removes that inference, an id list
|
|
5190
5201
|
* removes those inferences and returns true only when every named id existed.
|
|
5191
5202
|
* It emits one `remove` per inference actually removed.
|
|
5192
5203
|
* `seat` is the owning builder's silent bulk re-seat channel
|
|
5193
|
-
* (used by `merge`). `destroy()` is idempotent and tears the emitter down
|
|
5204
|
+
* (used by `merge`). `destroy()` is idempotent and tears the emitter down last;
|
|
5194
5205
|
* any other call after it throws `ReasonError('DESTROYED', …)`.
|
|
5195
5206
|
*
|
|
5196
5207
|
* @example
|
|
@@ -5279,17 +5290,17 @@ var InferenceManager = class {
|
|
|
5279
5290
|
* manager over a logical definition's `rules`.
|
|
5280
5291
|
*
|
|
5281
5292
|
* @remarks
|
|
5282
|
-
*
|
|
5293
|
+
* Owns its `rules` as a private {@link Collection} — copy-on-write state shared
|
|
5283
5294
|
* by composition with the other list managers — plus its own {@link Emitter}
|
|
5284
|
-
* over {@link RuleManagerEventMap}. Rule order is
|
|
5285
|
-
* conclusion is the
|
|
5295
|
+
* over {@link RuleManagerEventMap}. Rule order is load-bearing — the forward
|
|
5296
|
+
* conclusion is the last declared non-disabled rule, so `append` without a
|
|
5286
5297
|
* `target` makes the new rule the conclusion. `remove` is the batch family
|
|
5287
|
-
* (array form declared
|
|
5298
|
+
* (array form declared first): no argument removes every rule, one id removes
|
|
5288
5299
|
* that rule, an id list removes those rules and returns true only when every
|
|
5289
5300
|
* named id existed. It emits one `remove` per rule actually removed. `seat` is
|
|
5290
5301
|
* the owning builder's
|
|
5291
5302
|
* silent bulk re-seat channel (used by `merge`). `destroy()` is idempotent and
|
|
5292
|
-
* tears the emitter down
|
|
5303
|
+
* tears the emitter down last; any other call after it throws
|
|
5293
5304
|
* `ReasonError('DESTROYED', …)`.
|
|
5294
5305
|
*
|
|
5295
5306
|
* @example
|
|
@@ -5371,17 +5382,17 @@ var RuleManager = class {
|
|
|
5371
5382
|
* unordered record.
|
|
5372
5383
|
*
|
|
5373
5384
|
* @remarks
|
|
5374
|
-
*
|
|
5385
|
+
* Owns its `#variables` record as private copy-on-write state and its own
|
|
5375
5386
|
* {@link Emitter} over {@link VariableManagerEventMap}. The record has no
|
|
5376
5387
|
* placement, so only `add` / `remove` exist (no `append` / `prepend`): `add`
|
|
5377
5388
|
* upserts and emits `add(name)`, `remove` omits the key entirely (never sets
|
|
5378
5389
|
* `undefined`) and emits `remove(name)`. `remove` is the batch family over
|
|
5379
|
-
*
|
|
5390
|
+
* names (array form declared first): no argument removes every variable, one
|
|
5380
5391
|
* name removes that variable, a name list removes those variables and returns
|
|
5381
5392
|
* true only when every named variable existed. It emits one `remove` per
|
|
5382
5393
|
* variable actually removed. `seat` is the owning builder's silent
|
|
5383
5394
|
* bulk re-seat channel (used by `merge`). `destroy()` is idempotent and tears
|
|
5384
|
-
* the emitter down
|
|
5395
|
+
* the emitter down last; any other call after it throws
|
|
5385
5396
|
* `ReasonError('DESTROYED', …)`.
|
|
5386
5397
|
*
|
|
5387
5398
|
* @example
|
|
@@ -5462,22 +5473,22 @@ var VariableManager = class {
|
|
|
5462
5473
|
//#region src/core/builders/DefinitionBuilder.ts
|
|
5463
5474
|
/**
|
|
5464
5475
|
* Implements a stateful workspace builder accumulating a {@link Definition}
|
|
5465
|
-
* through always-present self-owning manager properties: a private
|
|
5466
|
-
*
|
|
5476
|
+
* through always-present self-owning manager properties: a private scalar
|
|
5477
|
+
* envelope (reasoning / id / name plus the kind's scalars) composed with each
|
|
5467
5478
|
* collection read from its manager.
|
|
5468
5479
|
*
|
|
5469
5480
|
* @remarks
|
|
5470
|
-
* Each manager is
|
|
5471
|
-
*
|
|
5472
|
-
*
|
|
5473
|
-
*
|
|
5474
|
-
*
|
|
5481
|
+
* Each manager is the one the caller supplies, or a fresh one seeded from the
|
|
5482
|
+
* seed's matching collection (empty for off-kind collections). Managers are
|
|
5483
|
+
* kind-free — `build()` ignores an off-kind manager, never a `MISMATCH`.
|
|
5484
|
+
* `build()` is total, deterministic, and returns a fresh plain
|
|
5485
|
+
* {@link Definition} each call. `merge(incoming)` requires the same
|
|
5475
5486
|
* `reasoning` (else `MISMATCH`) and distributes incoming scalars into the
|
|
5476
5487
|
* envelope and collections into the managers through the matching `merge*`
|
|
5477
5488
|
* helper. `clear(key)` deletes one optional field of the envelope for the
|
|
5478
5489
|
* instance's `reasoning` (a non-clearable key throws `MISMATCH`). `destroy()`
|
|
5479
5490
|
* cascades to every manager, emits `destroy`, then tears the builder emitter
|
|
5480
|
-
* down
|
|
5491
|
+
* down last; it is idempotent, and post-destroy mutation / build throws
|
|
5481
5492
|
* `ReasonError('DESTROYED', …)`.
|
|
5482
5493
|
*
|
|
5483
5494
|
* @example
|
|
@@ -5659,27 +5670,26 @@ var DefinitionBuilder = class {
|
|
|
5659
5670
|
* flat key-value collection, no managers.
|
|
5660
5671
|
*
|
|
5661
5672
|
* @remarks
|
|
5662
|
-
* `id` is
|
|
5673
|
+
* `id` is optional (`options?.id ?? seed.id`). When present, the builder is
|
|
5663
5674
|
* id-ful: `build()` carries that `id` and `clear()` restores it. When absent,
|
|
5664
|
-
* the builder is
|
|
5665
|
-
*
|
|
5666
|
-
*
|
|
5667
|
-
*
|
|
5668
|
-
*
|
|
5669
|
-
*
|
|
5670
|
-
*
|
|
5671
|
-
*
|
|
5672
|
-
*
|
|
5673
|
-
* `
|
|
5674
|
-
*
|
|
5675
|
-
* `
|
|
5676
|
-
*
|
|
5677
|
-
*
|
|
5678
|
-
*
|
|
5679
|
-
* durable payload each call. Post-destroy mutation throws
|
|
5675
|
+
* the builder is anonymous — `.id` is `undefined` and the accumulated subject
|
|
5676
|
+
* carries no `id` key. `field(key)` / `fields()` are the singular / plural
|
|
5677
|
+
* accessor pair over top-level keys only. `set(key, value)` delegates to
|
|
5678
|
+
* `assignField`; setting `id` throws `ReasonError('MISMATCH', …)`, because the
|
|
5679
|
+
* id is immutable through the entity, id-ful or anonymous alike. `remove` is
|
|
5680
|
+
* the batch family (array form declared first): no argument removes every
|
|
5681
|
+
* non-id field and emits one `remove` per key in key order, one key removes
|
|
5682
|
+
* that field, and a key list removes those fields. Removing `'id'` through a
|
|
5683
|
+
* keyed form throws the same `MISMATCH` for the same reason. `merge(incoming)`
|
|
5684
|
+
* delegates to `mergeSubjects` (incoming-wins, base `id` preserved — plain
|
|
5685
|
+
* {@link Subject} data only). `clear()` removes every non-id field, restoring
|
|
5686
|
+
* `{ id }` when id-ful or an empty record when anonymous. `repeat(count)`
|
|
5687
|
+
* returns `count` deterministic minted-id clones as plain payloads — a pure
|
|
5688
|
+
* read that emits nothing. `build(): Subject` is total, deterministic, and
|
|
5689
|
+
* returns a fresh durable payload each call. Post-destroy mutation throws
|
|
5680
5690
|
* `ReasonError('DESTROYED', …)` — only the `emitter` getter and `destroy`
|
|
5681
5691
|
* itself keep working, mirroring `Reason`. `destroy()` is idempotent and
|
|
5682
|
-
* tears the emitter down
|
|
5692
|
+
* tears the emitter down last.
|
|
5683
5693
|
*
|
|
5684
5694
|
* @example
|
|
5685
5695
|
* ```ts
|
|
@@ -5688,7 +5698,7 @@ var DefinitionBuilder = class {
|
|
|
5688
5698
|
* const applicant = createSubjectBuilder({ id: 'alice', age: 25 })
|
|
5689
5699
|
* applicant.set('region', 'CA')
|
|
5690
5700
|
* applicant.merge({ licensed: true, accidents: 0 }) // incoming wins, id kept
|
|
5691
|
-
* applicant.remove(['accidents']) // batch form first — true when
|
|
5701
|
+
* applicant.remove(['accidents']) // batch form first — true when every key existed
|
|
5692
5702
|
* applicant.field('region') // 'CA'
|
|
5693
5703
|
* applicant.fields() // the live record
|
|
5694
5704
|
* applicant.repeat(2) // ids 'alice-0', 'alice-1'
|
|
@@ -5957,7 +5967,7 @@ function createInferentialReasoner(options) {
|
|
|
5957
5967
|
*
|
|
5958
5968
|
* @remarks
|
|
5959
5969
|
* `reasoners` — the initial registry (a later entry of the same reasoning
|
|
5960
|
-
* replaces an earlier one; the orchestrator ships with
|
|
5970
|
+
* replaces an earlier one; the orchestrator ships with no defaults). `bail` —
|
|
5961
5971
|
* `true` (the default) rethrows a reasoner throw after the `error` emit;
|
|
5962
5972
|
* `false` converts it to a failure result. `validate` — validate every
|
|
5963
5973
|
* definition before running it, throwing `INVALID` on failure (default
|
|
@@ -5967,16 +5977,32 @@ function createInferentialReasoner(options) {
|
|
|
5967
5977
|
* @param options - Optional registry, policies, and emitter hooks
|
|
5968
5978
|
* @returns A {@link ReasonInterface}
|
|
5969
5979
|
*
|
|
5970
|
-
* @example
|
|
5980
|
+
* @example Create an orchestrator and score a subject
|
|
5971
5981
|
* ```ts
|
|
5972
|
-
* import {
|
|
5982
|
+
* import {
|
|
5983
|
+
* createFactorGroup,
|
|
5984
|
+
* createFieldFactor,
|
|
5985
|
+
* createQuantitativeDefinition,
|
|
5986
|
+
* createQuantitativeReasoner,
|
|
5987
|
+
* createReason,
|
|
5988
|
+
* createStaticFactor,
|
|
5989
|
+
* } from '@orkestrel/reason'
|
|
5973
5990
|
*
|
|
5974
|
-
* const reason = createReason({
|
|
5975
|
-
*
|
|
5976
|
-
*
|
|
5977
|
-
*
|
|
5978
|
-
*
|
|
5979
|
-
*
|
|
5991
|
+
* const reason = createReason({ reasoners: [createQuantitativeReasoner()] })
|
|
5992
|
+
*
|
|
5993
|
+
* const definition = createQuantitativeDefinition('risk', 'Risk score', [
|
|
5994
|
+
* createFactorGroup('drivers', 'sum', [
|
|
5995
|
+
* createFieldFactor('age', 'age'), // reads subject.age, parseNumber-coerced
|
|
5996
|
+
* createStaticFactor('floor', 10), // a fixed contribution
|
|
5997
|
+
* ]),
|
|
5998
|
+
* ])
|
|
5999
|
+
*
|
|
6000
|
+
* const result = reason.reason({ age: 25 }, definition) // one subject → one result
|
|
6001
|
+
* if (result.reasoning === 'quantitative') result.value // 35 — narrow by the discriminant
|
|
6002
|
+
* result.trace // the step-by-step account of how the value came to be
|
|
6003
|
+
*
|
|
6004
|
+
* reason.supports('quantitative') // true — a reasoner is registered for this reasoning
|
|
6005
|
+
* reason.reasoner('quantitative')?.supports(definition) // the reasoner's own guard, same check
|
|
5980
6006
|
* ```
|
|
5981
6007
|
*/
|
|
5982
6008
|
function createReason(options) {
|
|
@@ -5988,15 +6014,14 @@ function createReason(options) {
|
|
|
5988
6014
|
* `variables`, `facts`, and `inferences` self-owning manager properties.
|
|
5989
6015
|
*
|
|
5990
6016
|
* @remarks
|
|
5991
|
-
* `id`. Default: `seed.id`. Each manager slot
|
|
5992
|
-
*
|
|
5993
|
-
*
|
|
5994
|
-
*
|
|
5995
|
-
*
|
|
5996
|
-
*
|
|
5997
|
-
*
|
|
5998
|
-
*
|
|
5999
|
-
* @param seed - The starting definition (any of the four reasoning kinds)
|
|
6017
|
+
* `id`. Default: `seed.id`. Each manager slot takes the manager the caller
|
|
6018
|
+
* supplies, or a fresh one seeded from the seed's matching collection. `on` —
|
|
6019
|
+
* initial event listeners. `error` — the emitter's listener-error handler.
|
|
6020
|
+
* Mutate through the manager properties (`groups` / `factors` / `rules` /
|
|
6021
|
+
* `equations` / `variables` / `facts` / `inferences`) and `merge` / `clear`,
|
|
6022
|
+
* then call `build()` to produce a fresh, plain {@link Definition} snapshot.
|
|
6023
|
+
*
|
|
6024
|
+
* @param seed - The starting definition, of any reasoning
|
|
6000
6025
|
* @param options - Optional `id` override, manager injections, and emitter hooks
|
|
6001
6026
|
* @returns A {@link DefinitionBuilderInterface}
|
|
6002
6027
|
*
|
|
@@ -6018,8 +6043,8 @@ function createDefinitionBuilder(seed, options) {
|
|
|
6018
6043
|
* {@link Subject}.
|
|
6019
6044
|
*
|
|
6020
6045
|
* @remarks
|
|
6021
|
-
* `id`. Default: `seed.id`;
|
|
6022
|
-
* a string `seed.id` is present the builder is
|
|
6046
|
+
* `id`. Default: `seed.id`; it is optional — when neither `options.id` nor
|
|
6047
|
+
* a string `seed.id` is present the builder is anonymous (`.id` is
|
|
6023
6048
|
* `undefined`, `build()` emits no `id` key). `on` — initial event listeners.
|
|
6024
6049
|
* `error` — the emitter's listener-error handler.
|
|
6025
6050
|
* Mutate through `set` / `remove` / `merge` / `clear`, then call `build()` to
|
|
@@ -6203,7 +6228,7 @@ function createInferenceManager(options) {
|
|
|
6203
6228
|
/**
|
|
6204
6229
|
* Creates a {@link Check} — one field predicate.
|
|
6205
6230
|
*
|
|
6206
|
-
* @param field - The subject field to resolve (a string is
|
|
6231
|
+
* @param field - The subject field to resolve (a string is a single key; an array descends)
|
|
6207
6232
|
* @param operator - The comparison to apply
|
|
6208
6233
|
* @param value - The expected value (any type — the operator decides what is meaningful)
|
|
6209
6234
|
* @returns A fresh check
|
|
@@ -6273,7 +6298,7 @@ function createCompound(operator, operands) {
|
|
|
6273
6298
|
* `enabled` through `overrides`.
|
|
6274
6299
|
*
|
|
6275
6300
|
* @param id - The rule id
|
|
6276
|
-
* @param premises - The expressions that must
|
|
6301
|
+
* @param premises - The expressions that must all hold
|
|
6277
6302
|
* @param conclusion - The expression whose atoms are asserted when they do
|
|
6278
6303
|
* @param overrides - Optional {@link Rule} fields merged over the defaults
|
|
6279
6304
|
* @returns A fresh rule
|
|
@@ -6298,7 +6323,7 @@ function createRule(id, premises, conclusion, overrides) {
|
|
|
6298
6323
|
* Creates a {@link Transform} — one math step.
|
|
6299
6324
|
*
|
|
6300
6325
|
* @remarks
|
|
6301
|
-
* The `operand` key is
|
|
6326
|
+
* The `operand` key is omitted when absent (never set to `undefined`), so the
|
|
6302
6327
|
* transform stays exact-record valid; the transformer then applies its
|
|
6303
6328
|
* per-operation default (`1` for `multiply` / `divide` / `power`, `0` otherwise).
|
|
6304
6329
|
*
|
|
@@ -6324,7 +6349,7 @@ function createTransform(operator, operand) {
|
|
|
6324
6349
|
* Creates a {@link Bounds} — an inclusive numeric clamp.
|
|
6325
6350
|
*
|
|
6326
6351
|
* @remarks
|
|
6327
|
-
* Absent sides are
|
|
6352
|
+
* Absent sides are omitted (never set to `undefined`) — an absent bound is
|
|
6328
6353
|
* unbounded on that side.
|
|
6329
6354
|
*
|
|
6330
6355
|
* @param minimum - The inclusive lower bound
|
|
@@ -6387,7 +6412,7 @@ function createConstant(value) {
|
|
|
6387
6412
|
* Creates an operation {@link SymbolicExpression} node.
|
|
6388
6413
|
*
|
|
6389
6414
|
* @remarks
|
|
6390
|
-
* The `right` key is
|
|
6415
|
+
* The `right` key is omitted when absent — correct for the unary operations
|
|
6391
6416
|
* (`round` / `ceil` / `floor` / `abs`); a binary operation with no `right`
|
|
6392
6417
|
* treats it as the constant `0`.
|
|
6393
6418
|
*
|
|
@@ -6484,7 +6509,7 @@ function createFact(id, predicate, terms, confidence) {
|
|
|
6484
6509
|
* `enabled` through `overrides`.
|
|
6485
6510
|
*
|
|
6486
6511
|
* @param id - The inference id
|
|
6487
|
-
* @param premises - The fact patterns that must
|
|
6512
|
+
* @param premises - The fact patterns that must all unify
|
|
6488
6513
|
* @param conclusion - The fact pattern derived when they do
|
|
6489
6514
|
* @param overrides - Optional {@link Inference} fields merged over the defaults
|
|
6490
6515
|
* @returns A fresh inference
|