@orkestrel/reason 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { GUARD_DEPTH_LIMIT, arrayOf, holds, isArray, isBoolean, isFiniteNumber, isNumber, isObject, isRecord, isString, lazyOf, literalOf, notOf, orOf, parseJSONAs, parseNumber, parseNumberField, readArrayEntries, recordOf, resolveField, unionOf, whereOf } from "@orkestrel/contract";
1
+ import { GUARD_DEPTH_LIMIT, arrayOf, holds, isArray, isBoolean, isError, isFiniteNumber, isFunction, isInstance, isNumber, isObject, isRecord, isString, lazyOf, literalOf, notOf, orOf, parseJSONAs, parseNumber, parseNumberField, readArrayEntries, recordOf, resolveField, unionOf, whereOf } from "@orkestrel/contract";
2
2
  import { Emitter } from "@orkestrel/emitter";
3
3
  //#region src/core/constants.ts
4
4
  /**
@@ -143,7 +143,7 @@ var ReasonError = class extends Error {
143
143
  * ```
144
144
  */
145
145
  function isReasonError(value) {
146
- return value instanceof ReasonError;
146
+ return isInstance(value, ReasonError);
147
147
  }
148
148
  //#endregion
149
149
  //#region src/core/validators.ts
@@ -1350,7 +1350,7 @@ function resolveSource(source, subject, fallback) {
1350
1350
  const value = parseNumberField(subject, source.field);
1351
1351
  if (value === void 0) return fallback;
1352
1352
  for (const range of source.ranges) {
1353
- if (typeof range !== "object" || range === null) continue;
1353
+ if (!isObject(range)) continue;
1354
1354
  const limit = range.bounds;
1355
1355
  if (!limit) return range.value;
1356
1356
  const aboveMinimum = limit.minimum === void 0 || value >= limit.minimum;
@@ -1388,7 +1388,7 @@ function resolveSource(source, subject, fallback) {
1388
1388
  */
1389
1389
  function roundTo(value, precision = 0) {
1390
1390
  const factor = Math.pow(10, precision);
1391
- if (!Number.isFinite(factor) || factor === 0) return value;
1391
+ if (!isFiniteNumber(factor) || factor === 0) return value;
1392
1392
  return Math.round(value * factor) / factor;
1393
1393
  }
1394
1394
  /**
@@ -1443,7 +1443,7 @@ function equalValues(left, right) {
1443
1443
  function sortByPriority(items) {
1444
1444
  const usable = [];
1445
1445
  for (const item of items) {
1446
- if (typeof item !== "object" || item === null) continue;
1446
+ if (!isObject(item)) continue;
1447
1447
  usable.push(item);
1448
1448
  }
1449
1449
  return usable.sort((left, right) => (left.priority ?? 0) - (right.priority ?? 0));
@@ -1563,7 +1563,7 @@ function indexByArity(facts) {
1563
1563
  * ```
1564
1564
  */
1565
1565
  function termToKey(term, identities) {
1566
- if (typeof term === "object" && term !== null || typeof term === "function") {
1566
+ if (isObject(term) || isFunction(term)) {
1567
1567
  const existing = identities.get(term);
1568
1568
  if (existing !== void 0) return `${typeof term}:#${existing}`;
1569
1569
  const id = identities.size;
@@ -1638,11 +1638,11 @@ function matchFacts(pattern, candidate) {
1638
1638
  for (let index = 0; index < pattern.terms.length; index++) {
1639
1639
  const patternTerm = pattern.terms[index];
1640
1640
  const factTerm = candidate.terms[index];
1641
- if (typeof patternTerm === "string" && patternTerm.startsWith("?")) {
1641
+ if (isString(patternTerm) && patternTerm.startsWith("?")) {
1642
1642
  if (patternTerm in bindings) {
1643
1643
  if (bindings[patternTerm] !== factTerm) return void 0;
1644
1644
  } else bindings[patternTerm] = factTerm;
1645
- } else if (typeof factTerm === "string" && factTerm.startsWith("?")) {
1645
+ } else if (isString(factTerm) && factTerm.startsWith("?")) {
1646
1646
  if (factTerm in bindings) {
1647
1647
  if (bindings[factTerm] !== patternTerm) return void 0;
1648
1648
  } else bindings[factTerm] = patternTerm;
@@ -1674,7 +1674,7 @@ function matchFacts(pattern, candidate) {
1674
1674
  */
1675
1675
  function instantiateFact(fact, bindings) {
1676
1676
  const terms = fact.terms.map((term) => {
1677
- if (typeof term === "string" && term.startsWith("?") && term in bindings) return bindings[term];
1677
+ if (isString(term) && term.startsWith("?") && term in bindings) return bindings[term];
1678
1678
  return term;
1679
1679
  });
1680
1680
  return {
@@ -1748,7 +1748,7 @@ function subjectToFacts(subject) {
1748
1748
  if (key === "id") continue;
1749
1749
  const value = subject[key];
1750
1750
  if (value === void 0 || value === null) continue;
1751
- if (typeof value === "object") continue;
1751
+ if (isObject(value)) continue;
1752
1752
  facts.push({
1753
1753
  id: `subject:${key}`,
1754
1754
  predicate: "has",
@@ -2091,7 +2091,7 @@ function findOverlayMismatches(rules) {
2091
2091
  const writeKeys = [];
2092
2092
  const seenWrites = /* @__PURE__ */ new Set();
2093
2093
  for (const candidate of rules) for (const atomLeaf of extractAtoms(candidate.conclusion)) {
2094
- if (!Array.isArray(atomLeaf.check.field)) continue;
2094
+ if (!isArray(atomLeaf.check.field)) continue;
2095
2095
  const key = formatField(atomLeaf.check.field);
2096
2096
  if (seenWrites.has(key)) continue;
2097
2097
  seenWrites.add(key);
@@ -2099,7 +2099,7 @@ function findOverlayMismatches(rules) {
2099
2099
  }
2100
2100
  const readKeys = /* @__PURE__ */ new Set();
2101
2101
  for (const candidate of rules) for (const premise of candidate.premises) for (const atomLeaf of extractAtoms(premise)) {
2102
- if (!Array.isArray(atomLeaf.check.field)) continue;
2102
+ if (!isArray(atomLeaf.check.field)) continue;
2103
2103
  readKeys.add(formatField(atomLeaf.check.field));
2104
2104
  }
2105
2105
  return writeKeys.filter((key) => readKeys.has(key));
@@ -3343,7 +3343,7 @@ function mergeSubjects(base, incoming) {
3343
3343
  function repeatSubject(subject, count) {
3344
3344
  const baseId = subject.id;
3345
3345
  const clones = [];
3346
- for (let index = 0; index < count; index += 1) clones.push(typeof baseId === "string" ? {
3346
+ for (let index = 0; index < count; index += 1) clones.push(isString(baseId) ? {
3347
3347
  ...subject,
3348
3348
  id: `${baseId}-${index}`
3349
3349
  } : { ...subject });
@@ -3498,7 +3498,7 @@ var Reason = class {
3498
3498
  } catch (error) {
3499
3499
  this.#emitter.emit("error", error);
3500
3500
  if (this.#bail) throw error;
3501
- return buildErrorResult(definition, error instanceof Error ? error.message : String(error));
3501
+ return buildErrorResult(definition, isError(error) ? error.message : String(error));
3502
3502
  }
3503
3503
  }
3504
3504
  #ensureAlive() {
@@ -3548,7 +3548,7 @@ var Evaluator = class {
3548
3548
  actual
3549
3549
  };
3550
3550
  } catch (error) {
3551
- const message = error instanceof Error ? error.message : String(error);
3551
+ const message = isError(error) ? error.message : String(error);
3552
3552
  return {
3553
3553
  field: check.field,
3554
3554
  met: false,
@@ -3764,7 +3764,7 @@ var QuantitativeReasoner = class {
3764
3764
  definition: definition.id,
3765
3765
  reasoning: this.reasoning
3766
3766
  });
3767
- if (!definition.groups || !Array.isArray(definition.groups)) return {
3767
+ if (!isArray(definition.groups)) return {
3768
3768
  reasoning: "quantitative",
3769
3769
  value: 0,
3770
3770
  groups: [],
@@ -3778,7 +3778,7 @@ var QuantitativeReasoner = class {
3778
3778
  let count = 0;
3779
3779
  const groupResults = [];
3780
3780
  for (const group of definition.groups) {
3781
- if (typeof group !== "object" || group === null) continue;
3781
+ if (!isObject(group)) continue;
3782
3782
  if (group.enabled === false) {
3783
3783
  trace.push(`Skipped group "${group.id}" (disabled)`);
3784
3784
  continue;
@@ -3793,7 +3793,7 @@ var QuantitativeReasoner = class {
3793
3793
  trace.push(`Aggregated ${groupValues.length} groups with "${definition.aggregation}": base=${base}, raw=${value}`);
3794
3794
  value = clamp(value, definition.bounds);
3795
3795
  value = roundTo(value, definition.precision ?? 4);
3796
- if (!Number.isFinite(value)) {
3796
+ if (!isFiniteNumber(value)) {
3797
3797
  const description = Number.isNaN(value) ? "NaN" : String(value);
3798
3798
  trace.push(`Definition "${definition.id}": produced non-finite value (${description})`);
3799
3799
  errors.push(`Definition "${definition.id}" produced non-finite value: ${description}`);
@@ -3839,7 +3839,7 @@ var QuantitativeReasoner = class {
3839
3839
  const factorValues = appliedFactors.map((factor) => factor.value);
3840
3840
  const weightById = /* @__PURE__ */ new Map();
3841
3841
  for (const original of group.factors) {
3842
- if (typeof original !== "object" || original === null) continue;
3842
+ if (!isObject(original)) continue;
3843
3843
  if (!weightById.has(original.id)) weightById.set(original.id, original.weight ?? 1);
3844
3844
  }
3845
3845
  const weights = appliedFactors.map((factor) => weightById.get(factor.id) ?? 1);
@@ -3877,7 +3877,7 @@ var QuantitativeReasoner = class {
3877
3877
  value: 0
3878
3878
  };
3879
3879
  }
3880
- if (!Number.isFinite(raw)) {
3880
+ if (!isFiniteNumber(raw)) {
3881
3881
  const description = Number.isNaN(raw) ? "NaN" : String(raw);
3882
3882
  trace.push(`Factor "${factor.id}": source produced non-finite value (${description})`);
3883
3883
  errors.push(`Factor "${factor.id}" produced non-finite value: ${description}`);
@@ -3891,7 +3891,7 @@ var QuantitativeReasoner = class {
3891
3891
  let value = raw;
3892
3892
  if (factor.transforms && factor.transforms.length > 0) value = this.#transformer.chain(value, factor.transforms);
3893
3893
  value = clamp(value, factor.bounds);
3894
- if (!Number.isFinite(value)) {
3894
+ if (!isFiniteNumber(value)) {
3895
3895
  const description = Number.isNaN(value) ? "NaN" : String(value);
3896
3896
  trace.push(`Factor "${factor.id}": produced non-finite value (${description})`);
3897
3897
  errors.push(`Factor "${factor.id}" produced non-finite value: ${description}`);
@@ -4003,7 +4003,7 @@ var LogicalReasoner = class {
4003
4003
  definition: definition.id,
4004
4004
  reasoning: this.reasoning
4005
4005
  });
4006
- if (!definition.rules || !Array.isArray(definition.rules)) return {
4006
+ if (!isArray(definition.rules)) return {
4007
4007
  reasoning: "logical",
4008
4008
  conclusion: false,
4009
4009
  rules: [],
@@ -4032,7 +4032,7 @@ var LogicalReasoner = class {
4032
4032
  const sortedRules = sortByPriority(definition.rules);
4033
4033
  const reportedErrors = /* @__PURE__ */ new Set();
4034
4034
  for (const rule of sortedRules) {
4035
- if (typeof rule !== "object" || rule === null) continue;
4035
+ if (!isObject(rule)) continue;
4036
4036
  if (rule.enabled === false) continue;
4037
4037
  if (!rule.premises || rule.premises.length === 0) {
4038
4038
  errors.push(`Rule "${rule.id}" has no premises — skipped`);
@@ -4074,7 +4074,7 @@ var LogicalReasoner = class {
4074
4074
  };
4075
4075
  const finalResults = [];
4076
4076
  for (const rule of definition.rules) {
4077
- if (typeof rule !== "object" || rule === null) continue;
4077
+ if (!isObject(rule)) continue;
4078
4078
  if (rule.enabled === false) continue;
4079
4079
  if (reportedErrors.has(rule.id)) continue;
4080
4080
  finalResults.push(this.#evaluateRule(rule, finalSubject));
@@ -4090,9 +4090,9 @@ var LogicalReasoner = class {
4090
4090
  const ruleResults = /* @__PURE__ */ new Map();
4091
4091
  if (definition.rules.length === 0) trace.push("No rules defined");
4092
4092
  const sortedRules = sortByPriority(definition.rules.filter((rule) => {
4093
- if (typeof rule !== "object" || rule === null) return false;
4093
+ if (!isObject(rule)) return false;
4094
4094
  if (rule.enabled === false) return false;
4095
- if (!rule.premises || !Array.isArray(rule.premises)) {
4095
+ if (!isArray(rule.premises)) {
4096
4096
  errors.push(`Rule "${rule.id}" has no premises — skipped`);
4097
4097
  return false;
4098
4098
  }
@@ -4103,7 +4103,7 @@ var LogicalReasoner = class {
4103
4103
  return true;
4104
4104
  }));
4105
4105
  for (const rule of definition.rules) {
4106
- if (typeof rule !== "object" || rule === null) continue;
4106
+ if (!isObject(rule)) continue;
4107
4107
  if (rule.enabled === false) trace.push(`Skipped rule "${rule.id}" (disabled)`);
4108
4108
  }
4109
4109
  for (const rule of sortedRules) this.#proveRule(rule, 0, /* @__PURE__ */ new Set(), sortedRules, derived, subject, trace, ruleResults, maxDepth);
@@ -4154,7 +4154,7 @@ var LogicalReasoner = class {
4154
4154
  #proveExpression(expression, rules, depth, visited, derived, subject, trace, ruleResults, maxDepth) {
4155
4155
  if (depth > maxDepth) return false;
4156
4156
  if (expression.form === "atom") for (const rule of rules) {
4157
- if (typeof rule !== "object" || rule === null) continue;
4157
+ if (!isObject(rule)) continue;
4158
4158
  if (visited.has(rule.id)) continue;
4159
4159
  const conclusionFacts = extractConclusions(rule.conclusion);
4160
4160
  const field = formatField(expression.check.field);
@@ -4340,7 +4340,7 @@ var SymbolicReasoner = class {
4340
4340
  definition: definition.id,
4341
4341
  reasoning: this.reasoning
4342
4342
  });
4343
- if (!definition.equations || !Array.isArray(definition.equations)) return {
4343
+ if (!isArray(definition.equations)) return {
4344
4344
  reasoning: "symbolic",
4345
4345
  solutions: {},
4346
4346
  success: false,
@@ -4373,12 +4373,12 @@ var SymbolicReasoner = class {
4373
4373
  };
4374
4374
  }
4375
4375
  for (const equation of definition.equations) {
4376
- if (typeof equation !== "object" || equation === null) continue;
4376
+ if (!isObject(equation)) continue;
4377
4377
  try {
4378
4378
  const value = this.#solve(equation, bindings);
4379
4379
  const rounded = roundTo(value, precision);
4380
- if (!Number.isFinite(value) || !Number.isFinite(rounded)) {
4381
- const offender = Number.isFinite(value) ? rounded : value;
4380
+ if (!isFiniteNumber(value) || !isFiniteNumber(rounded)) {
4381
+ const offender = isFiniteNumber(value) ? rounded : value;
4382
4382
  const description = Number.isNaN(offender) ? "NaN" : `${offender}`;
4383
4383
  errors.push(`Equation "${equation.id}": produced non-finite value (${description})`);
4384
4384
  trace.push(`Equation "${equation.id}": FAILED — produced non-finite value (${description})`);
@@ -4387,14 +4387,14 @@ var SymbolicReasoner = class {
4387
4387
  bindings[equation.target] = rounded;
4388
4388
  trace.push(`Equation "${equation.id}": ${equation.target} = ${rounded}`);
4389
4389
  } catch (error) {
4390
- const message = error instanceof Error ? error.message : String(error);
4390
+ const message = isError(error) ? error.message : String(error);
4391
4391
  errors.push(`Equation "${equation.id}": ${message}`);
4392
4392
  trace.push(`Equation "${equation.id}": FAILED — ${message}`);
4393
4393
  }
4394
4394
  }
4395
4395
  const solutions = {};
4396
4396
  for (const equation of definition.equations) {
4397
- if (typeof equation !== "object" || equation === null) continue;
4397
+ if (!isObject(equation)) continue;
4398
4398
  const value = bindings[equation.target];
4399
4399
  if (value !== void 0) solutions[equation.target] = value;
4400
4400
  }
@@ -4540,11 +4540,11 @@ var InferentialReasoner = class {
4540
4540
  if (!definition.inferences || definition.inferences.length === 0) warnings.push("Definition has no inference rules");
4541
4541
  for (const id of findDuplicates(definition.inferences ?? [])) warnings.push(`Duplicate inference id "${id}"`);
4542
4542
  for (const fact of definition.facts ?? []) {
4543
- if (typeof fact !== "object" || fact === null) continue;
4543
+ if (!isObject(fact)) continue;
4544
4544
  if (fact.confidence !== void 0 && !(fact.confidence >= 0 && fact.confidence <= 1)) warnings.push(`Fact "${fact.id}" confidence outside [0, 1]`);
4545
4545
  }
4546
4546
  for (const inference of definition.inferences ?? []) {
4547
- if (typeof inference !== "object" || inference === null) continue;
4547
+ if (!isObject(inference)) continue;
4548
4548
  if (!inference.id) errors.push("Inference must have an id");
4549
4549
  if (!inference.premises || inference.premises.length === 0) warnings.push(`Inference "${inference.id}" has no premises`);
4550
4550
  if (!inference.conclusion) errors.push(`Inference "${inference.id}" must have a conclusion`);
@@ -4562,7 +4562,7 @@ var InferentialReasoner = class {
4562
4562
  definition: definition.id,
4563
4563
  reasoning: this.reasoning
4564
4564
  });
4565
- if (!definition.facts || !Array.isArray(definition.facts) || !definition.inferences || !Array.isArray(definition.inferences)) return {
4565
+ if (!definition.facts || !isArray(definition.facts) || !definition.inferences || !isArray(definition.inferences)) return {
4566
4566
  reasoning: "inferential",
4567
4567
  derived: [],
4568
4568
  success: false,
@@ -4587,7 +4587,7 @@ var InferentialReasoner = class {
4587
4587
  const maxDepth = definition.depth ?? 10;
4588
4588
  const knownFacts = [];
4589
4589
  for (const known of [...definition.facts, ...subjectFacts]) {
4590
- if (typeof known !== "object" || known === null) continue;
4590
+ if (!isObject(known)) continue;
4591
4591
  knownFacts.push(known);
4592
4592
  }
4593
4593
  const derived = [];
@@ -4602,7 +4602,7 @@ var InferentialReasoner = class {
4602
4602
  }
4603
4603
  const validInferences = [];
4604
4604
  for (const inference of definition.inferences) {
4605
- if (typeof inference !== "object" || inference === null) continue;
4605
+ if (!isObject(inference)) continue;
4606
4606
  if (inference.enabled === false) continue;
4607
4607
  if (!inference.premises || inference.premises.length === 0) {
4608
4608
  errors.push(`Inference "${inference.id}" has no premises — skipped`);
@@ -4651,7 +4651,7 @@ var InferentialReasoner = class {
4651
4651
  const derived = [];
4652
4652
  const allBaseFacts = [];
4653
4653
  for (const known of [...definition.facts, ...subjectFacts]) {
4654
- if (typeof known !== "object" || known === null) continue;
4654
+ if (!isObject(known)) continue;
4655
4655
  allBaseFacts.push(known);
4656
4656
  }
4657
4657
  if (definition.inferences.length === 0) {
@@ -4659,7 +4659,7 @@ var InferentialReasoner = class {
4659
4659
  return { derived };
4660
4660
  }
4661
4661
  for (const inference of definition.inferences) {
4662
- if (typeof inference !== "object" || inference === null) continue;
4662
+ if (!isObject(inference)) continue;
4663
4663
  if (inference.enabled === false) continue;
4664
4664
  if (!inference.conclusion) {
4665
4665
  errors.push(`Inference "${inference.id}" has no conclusion — skipped`);
@@ -4688,9 +4688,9 @@ var InferentialReasoner = class {
4688
4688
  depth
4689
4689
  };
4690
4690
  for (const inference of inferences) {
4691
- if (typeof inference !== "object" || inference === null) continue;
4691
+ if (!isObject(inference)) continue;
4692
4692
  if (inference.enabled === false) continue;
4693
- if (!inference.premises || !Array.isArray(inference.premises)) continue;
4693
+ if (!isArray(inference.premises)) continue;
4694
4694
  if (!inference.conclusion) continue;
4695
4695
  const conclusionBindings = matchFacts(goal, inference.conclusion);
4696
4696
  if (!conclusionBindings) continue;
@@ -5714,8 +5714,8 @@ var SubjectBuilder = class {
5714
5714
  #destroyed = false;
5715
5715
  constructor(seed, options) {
5716
5716
  const id = options?.id ?? seed.id;
5717
- this.#id = typeof id === "string" ? id : void 0;
5718
- if (typeof this.#id === "string") this.#subject = {
5717
+ this.#id = isString(id) ? id : void 0;
5718
+ if (isString(this.#id)) this.#subject = {
5719
5719
  ...seed,
5720
5720
  id: this.#id
5721
5721
  };
@@ -5761,7 +5761,7 @@ var SubjectBuilder = class {
5761
5761
  merge(incoming) {
5762
5762
  this.#ensureAlive();
5763
5763
  const merged = mergeSubjects(this.#subject, incoming);
5764
- if (typeof this.#id !== "string" && Object.hasOwn(merged, "id")) {
5764
+ if (!isString(this.#id) && Object.hasOwn(merged, "id")) {
5765
5765
  const { id: _id, ...rest } = merged;
5766
5766
  this.#subject = rest;
5767
5767
  } else this.#subject = merged;
@@ -5769,7 +5769,7 @@ var SubjectBuilder = class {
5769
5769
  }
5770
5770
  clear() {
5771
5771
  this.#ensureAlive();
5772
- this.#subject = typeof this.#id === "string" ? { id: this.#id } : {};
5772
+ this.#subject = isString(this.#id) ? { id: this.#id } : {};
5773
5773
  this.#emitter.emit("clear");
5774
5774
  }
5775
5775
  repeat(count) {