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