@orkestrel/reason 0.0.10 → 0.0.12

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