@kortexya/reasoninglayer 1.28.0 → 2.1.0

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/dist/index.js CHANGED
@@ -5,7 +5,7 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/config.ts
8
- var SDK_VERSION = "1.28.0";
8
+ var SDK_VERSION = "2.1.0";
9
9
  function resolveConfig(config) {
10
10
  if (!config.baseUrl) {
11
11
  throw new Error("ClientConfig.baseUrl is required");
@@ -1162,11 +1162,11 @@ var Sorts = class {
1162
1162
  ...params
1163
1163
  });
1164
1164
  /**
1165
- * @description Per Definition IV.5 (Milanese & Pasi, IEEE TFS 2024 — CC-BY manuscript in reasoninglayer-sources/pdf_sources/), verbatim: ≺∼· ≝ ((≺∼ .− ∼) ⊍ ⪯)⊕ The combined chain preorder ≺∼ of Definition IV.1 with every DIRECTLY-similar pair deleted (`.−` zeroes the pair — it is not an arithmetic difference), the crisp order unioned back, and the result re-closed. A chain survives when its ENDPOINTS are not directly similar: slasher ⪯ horror ∼₀.₅ thriller keeps 0.5 while (horror, thriller) itself answers 0 — two similar sorts meet through their GLB instead (Fig. 4c: horror ⩏ thriller = slasher). The combined ≺∼ — where a direct ∼ edge IS a step; the coarse retrieval mode of Example V.4 — backs equivalence classes and term substitutability internally. (History: the differencing form here is ORIGINAL and faithful; #203 swapped in the combined semantics, and a 2026-08-23 pass re-documented that as correct from secondary sources. The accepted manuscript settled it the other way.)
1165
+ * @description Omitted, the answer is Def. IV.5 `≾̇` — the default because that is the relation the graded GLB and term substitutability are computed from. `granularity: "combined"` answers Def. IV.1 `≺∼`, where a similarity edge IS a step, so a directly-similar pair reads its similarity degree instead of the `0` the pair deletion gives it. A caller asking "how close are these two sorts" wants the second; a caller asking "does this sort substitute for that one" wants the first (#282). Per Definition IV.5 (Milanese & Pasi, IEEE TFS 2024 — CC-BY manuscript in reasoninglayer-sources/pdf_sources/), verbatim: ≺∼· ≝ ((≺∼ .− ∼) ⊍ ⪯)⊕ The combined chain preorder ≺∼ of Definition IV.1 with every DIRECTLY-similar pair deleted (`.−` zeroes the pair — it is not an arithmetic difference), the crisp order unioned back, and the result re-closed. A chain survives when its ENDPOINTS are not directly similar: slasher ⪯ horror ∼₀.₅ thriller keeps 0.5 while (horror, thriller) itself answers 0 — two similar sorts meet through their GLB instead (Fig. 4c: horror ⩏ thriller = slasher). The combined ≺∼ — where a direct ∼ edge IS a step; the coarse retrieval mode of Example V.4 — backs equivalence classes and term substitutability internally. (History: the differencing form here is ORIGINAL and faithful; #203 swapped in the combined semantics, and a 2026-08-23 pass re-documented that as correct from secondary sources. The accepted manuscript settled it the other way.)
1166
1166
  *
1167
1167
  * @tags sorts
1168
1168
  * @name GetPreorderDegree
1169
- * @summary Get preorder degree ≾̇(s₁, s₂) between two sorts
1169
+ * @summary Get the preorder degree between two sorts, in either of the paper's two readings — `granularity` selects which, exactly as `GET /api/v1/sorts/quotient-order` does, and the answer echoes it back.
1170
1170
  * @request POST:/api/v1/sorts/preorder-degree
1171
1171
  */
1172
1172
  getPreorderDegree = (data, params = {}) => this.http.request({
@@ -1867,7 +1867,7 @@ var Inference = class {
1867
1867
  ...params
1868
1868
  });
1869
1869
  /**
1870
- * @description # TRUE HOMOICONIC API Request contains a goal term and optional constraints. Response returns solutions with term-based substitutions. ## Temporal Reasoning Use constraints to filter by temporal relations: ```json { "goal": {"sort_name": "Employment", "features": {"valid_to": {"name": "?EndTime"}}}, "constraints": [{"type": "Guard", "left": "?EndTime", "op": "lt", "right": "1583020800000"}] } ``` ## Reading a solution `solutions[].proof.kind` says how the goal was established, and is always present: `proved` (a rule was applied — either it fired in this search, or the goal was a conclusion a forward chain had materialised and the engine recovered the rule from its recorded derivation, so `rule_term_id` and `rule_label` are filled), `fact` (a stored fact with no recorded derivation), `residuated` (an open-world leaf: unknown, never false), `unattributed` (a sound answer whose derivation the engine could not report). A client never has to infer this from the node's shape. A goal that carries `constraints` is a CONJUNCTION: its root node holds one subproof per clause and reports the strongest kind the clauses carry — `proved` when any clause was proved by a rule, else `fact`. `solutions[].substitution.bindings` carries one entry per query variable the engine resolved. A variable left unresolved is ABSENT; it is never bound to itself. # Authorization Requires X-Tenant-Id header. Traced: this is the path the zanzibar gateway hits for every permission check, so it is where an end-to-end trace either explains a slow request or does not. `skip_all` because the request body can be large and has no business in a span attribute.
1870
+ * @description # TRUE HOMOICONIC API Request contains a goal term and optional constraints. Response returns solutions with term-based substitutions. ## Temporal Reasoning Use constraints to filter by temporal relations: ```json { "goal": {"sort_name": "Employment", "features": {"valid_to": {"name": "?EndTime"}}}, "constraints": [{"type": "Guard", "left": "?EndTime", "op": "lt", "right": "1583020800000"}] } ``` ## Reading a solution `solutions[].proof.kind` says how the goal was established, and is always present: `proved` (a rule was applied — either it fired in this search, or the goal was a conclusion a forward chain had materialised and the engine recovered the rule from its recorded derivation, so `rule_term_id` and `rule_label` are filled), `fact` (a stored fact with no recorded derivation), `residuated` (an open-world leaf: unknown, never false), `unattributed` (a sound answer whose derivation the engine could not report). A client never has to infer this from the node's shape. A goal that carries `constraints` is a CONJUNCTION: its root node holds one subproof per clause and reports the strongest kind the clauses carry — `proved` when any clause was proved by a rule, else `fact`. `solutions[].substitution.bindings` carries one entry per query variable the engine resolved. A variable left unresolved is ABSENT; it is never bound to itself. ## Joining a proof to the thing it proves `proof.goal_term_id` is the TermId of the CONCLUSION the node proved. It joins to `POST /api/v1/query/by-sort` and `GET /api/v1/terms/{id}`, and two solutions of one goal share it only when they prove the same conclusion. It is ABSENT when there is no such id — a goal proved without a preceding `CHAIN` materialised no conclusion, and a derivation replayed from a persistent store cannot be attributed to one. A client falls back deliberately there rather than by accident. `proof.rule_head_term_id` names the rule's instantiated HEAD on a rule application, when it differs from the conclusion. ⛔ It is rule scaffolding: `GET /api/v1/terms/{id}` refuses it deliberately (#192). It is a grouping key, not a fetchable id. # Authorization Requires X-Tenant-Id header. Traced: this is the path the zanzibar gateway hits for every permission check, so it is where an end-to-end trace either explains a slow request or does not. `skip_all` because the request body can be large and has no business in a span attribute.
1871
1871
  *
1872
1872
  * @tags inference
1873
1873
  * @name BackwardChain
@@ -13668,19 +13668,56 @@ function BulkSetSimilaritiesResponseFromApiToFront(dto) {
13668
13668
  errors: dto.errors
13669
13669
  };
13670
13670
  }
13671
+ var SORT_PREORDER_GRANULARITIES = [
13672
+ "similarity_deleted",
13673
+ "combined"
13674
+ ];
13675
+ function toSortPreorderGranularity(value) {
13676
+ const known = SORT_PREORDER_GRANULARITIES.find((candidate) => candidate === value);
13677
+ if (known === void 0) {
13678
+ throw new ValidationError(
13679
+ `Unknown preorder granularity "${value}" \u2014 expected ${SORT_PREORDER_GRANULARITIES.join(" or ")}.`
13680
+ );
13681
+ }
13682
+ return known;
13683
+ }
13671
13684
  function GetPreorderDegreeRequestFromFrontToApi(model) {
13672
13685
  return {
13673
13686
  sort1_id: model.sort1Id,
13674
- sort2_id: model.sort2Id
13687
+ sort2_id: model.sort2Id,
13688
+ granularity: model.granularity
13675
13689
  };
13676
13690
  }
13677
13691
  function GetPreorderDegreeResponseFromApiToFront(dto) {
13678
13692
  return {
13679
13693
  sort1Id: dto.sort1_id,
13680
13694
  sort2Id: dto.sort2_id,
13695
+ degree: dto.degree,
13696
+ granularity: toSortPreorderGranularity(dto.granularity)
13697
+ };
13698
+ }
13699
+ function QuotientClassFromApiToFront(dto) {
13700
+ return {
13701
+ sortIds: dto.sort_ids,
13702
+ size: dto.size,
13703
+ alpha: dto.alpha
13704
+ };
13705
+ }
13706
+ function QuotientOrderEdgeFromApiToFront(dto) {
13707
+ return {
13708
+ from: dto.from,
13709
+ to: dto.to,
13681
13710
  degree: dto.degree
13682
13711
  };
13683
13712
  }
13713
+ function GetQuotientOrderResponseFromApiToFront(dto) {
13714
+ return {
13715
+ granularity: toSortPreorderGranularity(dto.granularity),
13716
+ classes: dto.classes.map(QuotientClassFromApiToFront),
13717
+ count: dto.count,
13718
+ orderEdges: dto.order_edges.map(QuotientOrderEdgeFromApiToFront)
13719
+ };
13720
+ }
13684
13721
  function EquivalenceClassFromApiToFront(dto) {
13685
13722
  return {
13686
13723
  sortIds: dto.sort_ids,
@@ -14527,13 +14564,32 @@ var SortsClient = class {
14527
14564
  /**
14528
14565
  * Compute the preorder degree between two sorts.
14529
14566
  *
14530
- * @param request - Sort pair to compute preorder degree for.
14531
- * @returns The preorder degree response including sort IDs and degree.
14532
- * @throws {@link ApiError} If the sorts do not exist.
14533
- *
14534
- * @remarks
14535
- * Per Definition IV.5 (Milanese and Pasi 2024), the combined preorder is:
14536
- * `preorder_dot = ((similarity - subsumption) union subsumption)^+`
14567
+ * @param request - Sort pair to compute preorder degree for, and optionally
14568
+ * which of the two preorders to read it from.
14569
+ * @returns The preorder degree response including sort IDs, degree, and the
14570
+ * granularity the degree was read from.
14571
+ * @throws {@link ApiError} If the sorts do not exist, or if `granularity`
14572
+ * carries a spelling the engine does not accept.
14573
+ * @throws {@link ValidationError} If the engine answers a granularity this
14574
+ * SDK version does not know.
14575
+ *
14576
+ * @remarks
14577
+ * Per Definition IV.5 (Milanese and Pasi, IEEE TFS 2024), the dotted preorder
14578
+ * is `preorder_dot = ((combined_preorder .- similarity) union subsumption)^+`,
14579
+ * where `.-` DELETES each directly-similar pair — it is NOT an arithmetic
14580
+ * difference. So a directly-similar pair answers `0` under the default
14581
+ * granularity: two similar sorts meet through their GLB, not through each
14582
+ * other.
14583
+ *
14584
+ * `granularity` selects the reading, with the same two spellings
14585
+ * `GET /api/v1/sorts/quotient-order` uses:
14586
+ * - omitted or `similarity_deleted` — Definition IV.5, the default, and the
14587
+ * relation the graded GLB and term substitutability are computed from.
14588
+ * - `combined` — Definition IV.1, where a similarity edge IS a step, so a
14589
+ * directly-similar pair answers its similarity degree.
14590
+ *
14591
+ * The response always echoes the granularity back, so a `0.0` is never
14592
+ * ambiguous between "no path" and "the pair deletion zeroed it".
14537
14593
  *
14538
14594
  * Degree interpretation:
14539
14595
  * - 1.0 = subsumption (sort1 <= sort2)
@@ -14544,17 +14600,78 @@ var SortsClient = class {
14544
14600
  *
14545
14601
  * @example
14546
14602
  * ```typescript
14547
- * const result = await client.sorts.getPreorderDegree({
14603
+ * const strict = await client.sorts.getPreorderDegree({
14604
+ * sort1Id: 'uuid-1',
14605
+ * sort2Id: 'uuid-2',
14606
+ * });
14607
+ * console.log(strict.degree, strict.granularity); // 0 'similarity_deleted'
14608
+ *
14609
+ * const coarse = await client.sorts.getPreorderDegree({
14548
14610
  * sort1Id: 'uuid-1',
14549
14611
  * sort2Id: 'uuid-2',
14612
+ * granularity: 'combined',
14550
14613
  * });
14551
- * console.log(result.degree); // 0.72
14614
+ * console.log(coarse.degree, coarse.granularity); // 0.5 'combined'
14552
14615
  * ```
14553
14616
  */
14554
14617
  async getPreorderDegree(request, requestOptions) {
14555
14618
  const response = await this.sorts.getPreorderDegree(GetPreorderDegreeRequestFromFrontToApi(request), toRequestParams(requestOptions));
14556
14619
  return GetPreorderDegreeResponseFromApiToFront(response.data);
14557
14620
  }
14621
+ /**
14622
+ * Get the Definition IV.9 quotient order over the caller's own lattice.
14623
+ *
14624
+ * @param options - Which of the two fuzzy preorders to quotient. Omitted
14625
+ * means `combined`, the engine's default HERE.
14626
+ * @returns The equivalence classes with their degrees, and the fuzzy partial
14627
+ * order between them.
14628
+ * @throws {@link ApiError} 400 when `granularity` carries a spelling the
14629
+ * engine does not accept.
14630
+ * @throws {@link ValidationError} If the engine answers a granularity this
14631
+ * SDK version does not know.
14632
+ *
14633
+ * @remarks
14634
+ * This is the tenant-scoped companion of
14635
+ * {@link SortsClient.getEquivalenceClasses}: the classes, degrees and order
14636
+ * describe exactly the sorts the caller can see, where the older
14637
+ * equivalence-classes route computes process-wide and then filters. Prefer
14638
+ * this one.
14639
+ *
14640
+ * ⚠️ The default granularity here is `combined`, NOT the
14641
+ * `similarity_deleted` default of {@link SortsClient.getPreorderDegree}. The
14642
+ * two routes take the same two spellings and disagree on which is the
14643
+ * default, so state it when it matters. The response echoes it back either
14644
+ * way.
14645
+ *
14646
+ * `orderEdges` is SPARSE and indexes into `classes`: a pair with no edge has
14647
+ * degree `0`. The order is a partial order — antisymmetric, unlike either
14648
+ * preorder it is built from.
14649
+ *
14650
+ * Uses tagged serialization format.
14651
+ *
14652
+ * @example
14653
+ * ```typescript
14654
+ * const quotient = await client.sorts.getQuotientOrder({
14655
+ * granularity: 'similarity_deleted',
14656
+ * });
14657
+ *
14658
+ * for (const cls of quotient.classes) {
14659
+ * console.log(`class of ${cls.size} sorts, degree ${cls.alpha}`);
14660
+ * }
14661
+ * for (const edge of quotient.orderEdges) {
14662
+ * const lower = quotient.classes[edge.from];
14663
+ * const upper = quotient.classes[edge.to];
14664
+ * console.log(`${lower.sortIds} <= ${upper.sortIds} at ${edge.degree}`);
14665
+ * }
14666
+ * ```
14667
+ */
14668
+ async getQuotientOrder(options, requestOptions) {
14669
+ const response = await this.sorts.getQuotientOrder(
14670
+ { granularity: options?.granularity },
14671
+ toRequestParams(requestOptions)
14672
+ );
14673
+ return GetQuotientOrderResponseFromApiToFront(response.data);
14674
+ }
14558
14675
  /**
14559
14676
  * Get equivalence classes based on the combined preorder.
14560
14677
  *
@@ -14562,8 +14679,16 @@ var SortsClient = class {
14562
14679
  * @throws {@link ApiError} If the lattice cannot be computed.
14563
14680
  *
14564
14681
  * @remarks
14565
- * Per Definition IV.9 (Milanese and Pasi 2024):
14566
- * s1 ~ s2 iff preorder_dot(s1, s2) > 0 AND preorder_dot(s2, s1) > 0.
14682
+ * Per Definition IV.9 (Milanese and Pasi 2024), two sorts are equivalent when
14683
+ * each reaches the other: `s1 ~ s2` iff `preorder(s1, s2) > 0` AND
14684
+ * `preorder(s2, s1) > 0`. The preorder here is the COMBINED one, where a
14685
+ * similarity edge is itself a step — not the `similarity_deleted` default of
14686
+ * {@link SortsClient.getPreorderDegree}.
14687
+ *
14688
+ * ⚠️ This route computes PROCESS-WIDE and then filters, so its classes can
14689
+ * be shaped by sorts the caller cannot see. {@link SortsClient.getQuotientOrder}
14690
+ * computes on the tenant-visible hierarchy instead, returns the same classes
14691
+ * with their degrees, and adds the partial order between them. Prefer it.
14567
14692
  *
14568
14693
  * Uses tagged serialization format.
14569
14694
  *
@@ -15744,31 +15869,42 @@ function convertFeatures(features) {
15744
15869
  }
15745
15870
 
15746
15871
  // src/normalizers/homoiconic.ts
15747
- function FeatureInputValueDtoFromFrontToApi(value) {
15872
+ function assertPresent(value, what) {
15873
+ if (value === null || value === void 0) {
15874
+ throw new ValidationError(
15875
+ `${what} is required \u2014 received ${value === null ? "null" : "undefined"}.`,
15876
+ what
15877
+ );
15878
+ }
15879
+ }
15880
+ function FeatureInputValueDtoFromFrontToApi(value, path = "feature value") {
15881
+ assertPresent(value, path);
15748
15882
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
15749
15883
  return value;
15750
15884
  }
15751
15885
  if (Array.isArray(value)) {
15752
- return value.map(FeatureInputValueDtoFromFrontToApi);
15886
+ return value.map(
15887
+ (element, index) => FeatureInputValueDtoFromFrontToApi(element, `${path}[${index}]`)
15888
+ );
15753
15889
  }
15754
15890
  if ("name" in value && "constraint" in value) {
15755
15891
  return {
15756
15892
  name: value.name,
15757
- constraint: TermInputDtoFromFrontToApi(value.constraint)
15893
+ constraint: TermInputDtoFromFrontToApi(value.constraint, `${path}.constraint`)
15758
15894
  };
15759
15895
  }
15760
15896
  if ("name" in value) {
15761
15897
  return { name: value.name };
15762
15898
  }
15763
15899
  if ("sortId" in value) {
15764
- const features = value.features ? featuresInputFromFrontToApi(value.features) : void 0;
15900
+ const features = value.features ? featuresInputFromFrontToApi(value.features, `${path}.features`) : void 0;
15765
15901
  return {
15766
15902
  sort_id: value.sortId,
15767
15903
  ...features ? { features } : {}
15768
15904
  };
15769
15905
  }
15770
15906
  if ("sortName" in value) {
15771
- const features = value.features ? featuresInputFromFrontToApi(value.features) : void 0;
15907
+ const features = value.features ? featuresInputFromFrontToApi(value.features, `${path}.features`) : void 0;
15772
15908
  return {
15773
15909
  sort_name: value.sortName,
15774
15910
  ...features ? { features } : {}
@@ -15779,14 +15915,15 @@ function FeatureInputValueDtoFromFrontToApi(value) {
15779
15915
  }
15780
15916
  return { term_id: value.termId };
15781
15917
  }
15782
- function featuresInputFromFrontToApi(features) {
15918
+ function featuresInputFromFrontToApi(features, path = "features") {
15783
15919
  const result = {};
15784
15920
  for (const [key, val] of Object.entries(features)) {
15785
- result[key] = FeatureInputValueDtoFromFrontToApi(val);
15921
+ result[key] = FeatureInputValueDtoFromFrontToApi(val, `${path}.${key}`);
15786
15922
  }
15787
15923
  return result;
15788
15924
  }
15789
- function TermInputDtoFromFrontToApi(model) {
15925
+ function TermInputDtoFromFrontToApi(model, path = "term") {
15926
+ assertPresent(model, path);
15790
15927
  if ("termId" in model) {
15791
15928
  return { term_id: model.termId };
15792
15929
  }
@@ -15801,14 +15938,14 @@ function TermInputDtoFromFrontToApi(model) {
15801
15938
  if ("sortId" in model) {
15802
15939
  const inline = {
15803
15940
  sort_id: model.sortId,
15804
- features: featuresInputFromFrontToApi(model.features)
15941
+ features: featuresInputFromFrontToApi(model.features, `${path}.features`)
15805
15942
  };
15806
15943
  if (model.binding !== void 0) inline.binding = model.binding;
15807
15944
  return inline;
15808
15945
  }
15809
15946
  const byName = {
15810
15947
  sort_name: model.sortName,
15811
- features: model.features ? featuresInputFromFrontToApi(model.features) : void 0
15948
+ features: model.features ? featuresInputFromFrontToApi(model.features, `${path}.features`) : void 0
15812
15949
  };
15813
15950
  if (model.binding !== void 0) byName.binding = model.binding;
15814
15951
  return byName;
@@ -15870,6 +16007,7 @@ function ProofDtoFromApiToFront(dto) {
15870
16007
  kind: dto.kind,
15871
16008
  goalTermId: dto.goal_term_id,
15872
16009
  ruleTermId: dto.rule_term_id,
16010
+ ruleHeadTermId: dto.rule_head_term_id,
15873
16011
  goalDisplay: dto.goal_display,
15874
16012
  ruleLabel: dto.rule_label,
15875
16013
  substitution: HomoiconicSubstitutionDtoFromApiToFront(dto.substitution),
@@ -16369,7 +16507,9 @@ function RuleAggregatorDtoFromFrontToApi(model) {
16369
16507
  function AddRuleRequestFromFrontToApi(model) {
16370
16508
  return {
16371
16509
  term: TermInputDtoFromFrontToApi(model.term),
16372
- antecedents: model.antecedents?.map(TermInputDtoFromFrontToApi),
16510
+ antecedents: model.antecedents?.map(
16511
+ (t, i) => TermInputDtoFromFrontToApi(t, `antecedents[${i}]`)
16512
+ ),
16373
16513
  certainty: model.certainty,
16374
16514
  aggregator: model.aggregator ? RuleAggregatorDtoFromFrontToApi(model.aggregator) : model.aggregator
16375
16515
  };
@@ -16386,7 +16526,7 @@ function BulkAddRulesRequestFromFrontToApi(model) {
16386
16526
  }
16387
16527
  function BulkAddFactsRequestFromFrontToApi(model) {
16388
16528
  return {
16389
- facts: model.facts.map(TermInputDtoFromFrontToApi)
16529
+ facts: model.facts.map((t, i) => TermInputDtoFromFrontToApi(t, `facts[${i}]`))
16390
16530
  };
16391
16531
  }
16392
16532
  function BackwardChainRequestFromFrontToApi(model) {
@@ -16404,12 +16544,15 @@ function BackwardChainRequestFromFrontToApi(model) {
16404
16544
  }
16405
16545
  function ForwardChainRequestFromFrontToApi(model) {
16406
16546
  return {
16407
- initial_facts: model.initialFacts?.map(TermInputDtoFromFrontToApi),
16547
+ initial_facts: model.initialFacts?.map(
16548
+ (t, i) => TermInputDtoFromFrontToApi(t, `initialFacts[${i}]`)
16549
+ ),
16408
16550
  keep_derived: model.keepDerived,
16409
16551
  enable_provenance_tags: model.enableProvenanceTags,
16410
16552
  max_iterations: model.maxIterations,
16411
16553
  max_facts: model.maxFacts,
16412
- emit_provenance: model.emitProvenance
16554
+ emit_provenance: model.emitProvenance,
16555
+ timeout_ms: model.timeoutMs ?? void 0
16413
16556
  };
16414
16557
  }
16415
16558
  function FuzzyProveRequestFromFrontToApi(model) {
@@ -16426,7 +16569,7 @@ function FuzzyProveRequestFromFrontToApi(model) {
16426
16569
  }
16427
16570
  function BulkFuzzyProveRequestFromFrontToApi(model) {
16428
16571
  return {
16429
- goals: model.goals?.map(TermInputDtoFromFrontToApi),
16572
+ goals: model.goals?.map((t, i) => TermInputDtoFromFrontToApi(t, `goals[${i}]`)),
16430
16573
  goal_ids: model.goalIds ?? void 0,
16431
16574
  max_depth: model.maxDepth,
16432
16575
  min_degree: model.minDegree,
@@ -16449,7 +16592,7 @@ function BayesianPredictRequestFromFrontToApi(model) {
16449
16592
  }
16450
16593
  function CreateGoalRequestFromFrontToApi(model) {
16451
16594
  return {
16452
- clauses: model.clauses.map(TermInputDtoFromFrontToApi),
16595
+ clauses: model.clauses.map((t, i) => TermInputDtoFromFrontToApi(t, `clauses[${i}]`)),
16453
16596
  constraints: model.constraints?.map(ConstraintInputDtoFromFrontToApi),
16454
16597
  min_degree: model.minDegree ?? void 0
16455
16598
  };
@@ -16749,6 +16892,14 @@ var InferenceClient = class {
16749
16892
  *
16750
16893
  * The `timeout_ms` field on the request is a wall-clock timeout for the search.
16751
16894
  * When it fires, the backend returns whatever solutions have been found so far.
16895
+ *
16896
+ * To join a proof node to the thing it proves, read `proof.goalTermId` — the
16897
+ * conclusion's term ID, which `client.terms.getTerm()` and
16898
+ * `client.query.findBySort()` both answer for. It is OPTIONAL: a goal proved
16899
+ * without a preceding forward chain materialises no conclusion, so the node
16900
+ * carries no id and `proof.goalDisplay` renders it instead. Do not read
16901
+ * `proof.ruleHeadTermId` as a fetchable id — it names the rule's instantiated
16902
+ * head, which the term routes refuse.
16752
16903
  */
16753
16904
  async backwardChain(request, requestOptions) {
16754
16905
  const wireRequest = {
@@ -16852,13 +17003,37 @@ var InferenceClient = class {
16852
17003
  /**
16853
17004
  * Run negation-as-failure (NAF) proof search.
16854
17005
  *
16855
- * @param request - NAF prove request.
17006
+ * @param request - NAF prove request. Each literal's `term` takes a
17007
+ * {@link psi} term or a wire {@link TermInputDto}, like every other
17008
+ * term-carrying method.
16856
17009
  * @returns NAF proof result.
16857
17010
  *
17011
+ * @remarks
17012
+ * Uses the untagged (homoiconic) serialization format: a literal's features
17013
+ * are plain scalars and `"?Var"` strings.
17014
+ *
17015
+ * @example
17016
+ * ```typescript
17017
+ * const result = await client.inference.nafProve({
17018
+ * literals: [
17019
+ * { term: psi('employee', { name: '?Name' }) },
17020
+ * { term: psi('senior_engineer', { name: '?Name' }), negated: true },
17021
+ * ],
17022
+ * maxSolutions: 10,
17023
+ * });
17024
+ * ```
17025
+ *
16858
17026
  * @see proveWithNegation — friendlier alias for this method.
16859
17027
  */
16860
17028
  async nafProve(request, requestOptions) {
16861
- const response = await this.api.nafProve(NafProveRequestFromFrontToApi(request), toRequestParams(requestOptions));
17029
+ const wireRequest = {
17030
+ ...request,
17031
+ literals: request.literals?.map((literal) => ({
17032
+ ...literal,
17033
+ term: convertTermArg(literal.term)
17034
+ }))
17035
+ };
17036
+ const response = await this.api.nafProve(NafProveRequestFromFrontToApi(wireRequest), toRequestParams(requestOptions));
16862
17037
  return NafProveResponseFromApiToFront(response.data);
16863
17038
  }
16864
17039
  /**
@@ -23785,7 +23960,7 @@ function EntailmentRequestFromFrontToApi(model) {
23785
23960
  return {
23786
23961
  antecedent: TermInputDtoFromFrontToApi(model.antecedent),
23787
23962
  consequent: TermInputDtoFromFrontToApi(model.consequent),
23788
- facts: model.facts?.map(TermInputDtoFromFrontToApi)
23963
+ facts: model.facts?.map((t, i) => TermInputDtoFromFrontToApi(t, `facts[${i}]`))
23789
23964
  };
23790
23965
  }
23791
23966
  function EntailmentResponseFromApiToFront(dto) {
@@ -23799,7 +23974,7 @@ function DisentailmentRequestFromFrontToApi(model) {
23799
23974
  return {
23800
23975
  antecedent: TermInputDtoFromFrontToApi(model.antecedent),
23801
23976
  consequent: TermInputDtoFromFrontToApi(model.consequent),
23802
- facts: model.facts?.map(TermInputDtoFromFrontToApi)
23977
+ facts: model.facts?.map((t, i) => TermInputDtoFromFrontToApi(t, `facts[${i}]`))
23803
23978
  };
23804
23979
  }
23805
23980
  function DisentailmentResponseFromApiToFront(dto) {
@@ -25390,12 +25565,25 @@ function SourceDetailResponseFromApiToFront(dto) {
25390
25565
  supportedModes: dto.supported_modes
25391
25566
  };
25392
25567
  }
25568
+ function ConfigFieldDtoFromApiToFront(dto) {
25569
+ return {
25570
+ // `name` is the factory's own JSON key and goes back on the wire
25571
+ // verbatim — never camelCased, in either direction (#14).
25572
+ name: dto.name,
25573
+ type: dto.type,
25574
+ required: dto.required
25575
+ };
25576
+ }
25393
25577
  function SourceTypeDtoFromApiToFront(dto) {
25394
25578
  return {
25395
25579
  sourceType: dto.source_type,
25396
25580
  aliases: dto.aliases,
25397
25581
  available: dto.available,
25398
- supportedModes: dto.supported_modes
25582
+ supportedModes: dto.supported_modes,
25583
+ // Defaulted rather than left absent: the field is required on the current
25584
+ // engine, and an empty list reads correctly on an older one — a form built
25585
+ // from no fields is visibly empty, where an absent list is a crash.
25586
+ configFields: (dto.config_fields ?? []).map(ConfigFieldDtoFromApiToFront)
25399
25587
  };
25400
25588
  }
25401
25589
  function ListSourceTypesResponseFromApiToFront(dto) {
@@ -25415,6 +25603,7 @@ function DiscoverableTypeDtoFromApiToFront(dto) {
25415
25603
  return {
25416
25604
  comment: dto.comment,
25417
25605
  estimatedRows: dto.estimated_rows,
25606
+ columnCount: dto.column_count,
25418
25607
  name: dto.name
25419
25608
  };
25420
25609
  }
@@ -25425,6 +25614,15 @@ function ListTablesResponseFromApiToFront(dto) {
25425
25614
  total: dto.total
25426
25615
  };
25427
25616
  }
25617
+ function KeyProvenanceDtoFromApiToFront(dto) {
25618
+ return {
25619
+ source: dto.source,
25620
+ chosenBy: dto.chosen_by,
25621
+ explanation: dto.explanation,
25622
+ guaranteedUnique: dto.guaranteed_unique,
25623
+ durability: dto.durability
25624
+ };
25625
+ }
25428
25626
  function DiscoveredFeatureDtoFromApiToFront(dto) {
25429
25627
  return {
25430
25628
  constraints: dto.constraints,
@@ -25432,10 +25630,16 @@ function DiscoveredFeatureDtoFromApiToFront(dto) {
25432
25630
  isIdentifier: dto.is_identifier,
25433
25631
  isRelation: dto.is_relation,
25434
25632
  name: dto.name,
25633
+ // The engine's own OSFQL-readable spelling. Defaulted to `name`, which it
25634
+ // is identical to, so an older engine that predates it stays usable.
25635
+ featureName: dto.feature_name ?? dto.name,
25435
25636
  relationTarget: dto.relation_target,
25436
25637
  required: dto.required,
25437
25638
  sourceName: dto.source_name,
25438
- typeHint: dto.type_hint
25639
+ typeHint: dto.type_hint,
25640
+ // The difference between a declared primary key and a guess. Carried
25641
+ // through so a mapping wizard can present the guess as a guess (#14).
25642
+ identifierProvenance: dto.identifier_provenance ? KeyProvenanceDtoFromApiToFront(dto.identifier_provenance) : dto.identifier_provenance
25439
25643
  };
25440
25644
  }
25441
25645
  function DiscoveredSortDtoFromApiToFront(dto) {
@@ -31285,7 +31489,9 @@ var OptimizeClient = class {
31285
31489
  }
31286
31490
  const ruleResponse = await this.inferenceApi.addRule({
31287
31491
  term: TermInputDtoFromFrontToApi(compiled.solutionTerm),
31288
- antecedents: compiled.antecedents.map(TermInputDtoFromFrontToApi),
31492
+ antecedents: compiled.antecedents.map(
31493
+ (t, i) => TermInputDtoFromFrontToApi(t, `antecedents[${i}]`)
31494
+ ),
31289
31495
  certainty: 1
31290
31496
  }, toRequestParams(requestOptions));
31291
31497
  ruleTermId = extractRuleTermId(ruleResponse.data);
@@ -31964,6 +32170,7 @@ function OsfqlResponseFromApiToFront(dto) {
31964
32170
  bindings,
31965
32171
  fetched,
31966
32172
  producedTermIds: dto.produced_term_ids,
32173
+ updatedTermIds: dto.updated_term_ids,
31967
32174
  definedSortIds: dto.defined_sort_ids,
31968
32175
  diagnostics: dto.diagnostics,
31969
32176
  statementCount: dto.statement_count
@@ -32035,11 +32242,25 @@ function OsfqlPreviewAffectedFromApiToFront(dto) {
32035
32242
  affected.exact = dto.exact;
32036
32243
  }
32037
32244
  if (dto.sample_rows !== void 0) {
32038
- const rows = OsfqlBindingsFromApiToFront(dto.sample_rows);
32039
- if (rows === void 0) {
32040
- return void 0;
32245
+ const rows = [];
32246
+ let unparsed = 0;
32247
+ const wireRows = dto.sample_rows;
32248
+ if (Array.isArray(wireRows)) {
32249
+ for (const row of wireRows) {
32250
+ const parsed = OsfqlBindingFromApiToFront(row);
32251
+ if (parsed === void 0) {
32252
+ unparsed += 1;
32253
+ } else {
32254
+ rows.push(parsed);
32255
+ }
32256
+ }
32257
+ } else {
32258
+ unparsed = 1;
32041
32259
  }
32042
32260
  affected.sampleRows = rows;
32261
+ if (unparsed > 0) {
32262
+ affected.unparsedSampleRows = unparsed;
32263
+ }
32043
32264
  }
32044
32265
  if (dto.by_sort !== void 0) {
32045
32266
  affected.bySort = dto.by_sort.map(OsfqlPreviewSortCountFromApiToFront);
@@ -32060,34 +32281,15 @@ function OsfqlPreviewStatementFromApiToFront(dto) {
32060
32281
  source: dto.source
32061
32282
  };
32062
32283
  if (dto.affected !== void 0) {
32063
- const affected = OsfqlPreviewAffectedFromApiToFront(dto.affected);
32064
- if (affected === void 0) {
32065
- return void 0;
32066
- }
32067
- statement.affected = affected;
32284
+ statement.affected = OsfqlPreviewAffectedFromApiToFront(dto.affected);
32068
32285
  }
32069
32286
  if (dto.nested !== void 0) {
32070
- const nested = [];
32071
- for (const child of dto.nested) {
32072
- const parsed = OsfqlPreviewStatementFromApiToFront(child);
32073
- if (parsed === void 0) {
32074
- return void 0;
32075
- }
32076
- nested.push(parsed);
32077
- }
32078
- statement.nested = nested;
32287
+ statement.nested = dto.nested.map(OsfqlPreviewStatementFromApiToFront);
32079
32288
  }
32080
32289
  return statement;
32081
32290
  }
32082
32291
  function OsfqlPreviewResponseFromApiToFront(dto) {
32083
- const statements = [];
32084
- for (const entry of dto.statements) {
32085
- const parsed = OsfqlPreviewStatementFromApiToFront(entry);
32086
- if (parsed === void 0) {
32087
- return void 0;
32088
- }
32089
- statements.push(parsed);
32090
- }
32292
+ const statements = dto.statements.map(OsfqlPreviewStatementFromApiToFront);
32091
32293
  const response = { mutates: dto.mutates, statements };
32092
32294
  if (dto.atomic_refusal !== void 0) {
32093
32295
  response.atomicRefusal = dto.atomic_refusal ? OsfqlAtomicRefusalFromApiToFront(dto.atomic_refusal) : dto.atomic_refusal;
@@ -32183,8 +32385,6 @@ var OsfqlClient = class {
32183
32385
  * atomic refusal when there is one.
32184
32386
  * @throws {ApiError} If the program does not parse (HTTP 400, `OsfqlErrorResponse`),
32185
32387
  * or the request otherwise fails.
32186
- * @throws {ReasoningLayerError} If a sample row carries a value that does not satisfy
32187
- * the published {@link OsfqlValue} contract.
32188
32388
  *
32189
32389
  * @remarks
32190
32390
  * **Why call this instead of classifying the program client-side.** Three
@@ -32219,9 +32419,16 @@ var OsfqlClient = class {
32219
32419
  * Two further measured facts. The top-level `mutates` DOES fold nested
32220
32420
  * statements now: the `IF` program above answers `true`, and so does an `IF`
32221
32421
  * whose only writing branch is the `ELSE` — the earlier defect where an `IF`
32222
- * with a writing branch answered `false` is fixed. And `affected` being absent
32223
- * is ambiguous: `RETRACT customer(tier: "bronze")` matching zero rows omits
32224
- * the field entirely rather than answering `count: 0`, exactly as a read does.
32422
+ * with a writing branch answered `false` is fixed. And `affected` is NOT
32423
+ * ambiguous: a destructive statement that matches zero rows answers
32424
+ * `{count: 0, exact: true}` rather than omitting the block. Measured
32425
+ * 2026-09-21 — `preview('RETRACT widget(name: "nobody");')` against an empty
32426
+ * `widget` answers `affected: {"count":0,"exact":true}`, while
32427
+ * `preview('MATCH widget(name: ?N);')` carries no `affected` key at all. So
32428
+ * an ABSENT block means the statement has no affected-row set; `count: 0`
32429
+ * means the rows were counted and there are none. A confirm dialog can tell
32430
+ * the two apart, which is what the block was separated for. See
32431
+ * {@link OsfqlPreviewAffected.count}.
32225
32432
  *
32226
32433
  * `statement.index` is a single counter over the whole program: an `IF` at
32227
32434
  * index 1 carries nested entries at index 2 and 3.
@@ -32262,13 +32469,7 @@ var OsfqlClient = class {
32262
32469
  OsfqlRequestFromFrontToApi({ ...options, query }),
32263
32470
  toRequestParams(requestOptions)
32264
32471
  );
32265
- const parsed = OsfqlPreviewResponseFromApiToFront(response.data);
32266
- if (parsed === void 0) {
32267
- throw new ReasoningLayerError(
32268
- "osfql/preview returned an affected sample row that does not match the published OsfqlValue contract (expected tagged values with a lowercase `type` discriminator)"
32269
- );
32270
- }
32271
- return parsed;
32472
+ return OsfqlPreviewResponseFromApiToFront(response.data);
32272
32473
  }
32273
32474
  /**
32274
32475
  * Diagnose an OSFQL program for contradictions and inconsistencies.
@@ -34201,6 +34402,27 @@ function AuditPageFromApiToFront(dto) {
34201
34402
  offset: dto.offset
34202
34403
  };
34203
34404
  }
34405
+ function RiskTotalsDtoFromApiToFront(dto) {
34406
+ return {
34407
+ nSafe: dto.n_safe,
34408
+ nWarning: dto.n_warning,
34409
+ nUnsafe: dto.n_unsafe,
34410
+ nUngraded: dto.n_ungraded,
34411
+ nGradedByVerification: dto.n_graded_by_verification,
34412
+ nVerified: dto.n_verified,
34413
+ nRefuted: dto.n_refuted,
34414
+ nAbstained: dto.n_abstained,
34415
+ nFabricationDetected: dto.n_fabrication_detected,
34416
+ nFabricationClean: dto.n_fabrication_clean,
34417
+ nFabricationUnknown: dto.n_fabrication_unknown,
34418
+ nClaimsTotal: dto.n_claims_total,
34419
+ nClaimsRefuted: dto.n_claims_refuted,
34420
+ // Carried through as `null`, never folded to `0`. `null` is "not
34421
+ // measured" — the denominator is checked responses only — and `0` would
34422
+ // report a clean fabrication rate for a ledger nobody checked (#11).
34423
+ fabricationRate: dto.fabrication_rate
34424
+ };
34425
+ }
34204
34426
  function SummaryResponseFromApiToFront(dto) {
34205
34427
  const out = {
34206
34428
  nRecords: dto.n_records,
@@ -34210,6 +34432,12 @@ function SummaryResponseFromApiToFront(dto) {
34210
34432
  };
34211
34433
  if (dto.ts_first) out.tsFirst = dto.ts_first;
34212
34434
  if (dto.ts_last) out.tsLast = dto.ts_last;
34435
+ if (dto.risk !== void 0 && dto.risk !== null) {
34436
+ out.risk = RiskTotalsDtoFromApiToFront(dto.risk);
34437
+ }
34438
+ if (dto.n_oversight_decisions !== void 0 && dto.n_oversight_decisions !== null) {
34439
+ out.nOversightDecisions = dto.n_oversight_decisions;
34440
+ }
34213
34441
  return out;
34214
34442
  }
34215
34443
  function VerifyResponseFromApiToFront(dto) {
@@ -36436,6 +36664,23 @@ function ImportOwlResponseFromApiToFront(dto) {
36436
36664
  sortsCreated: dto.sorts_created
36437
36665
  };
36438
36666
  }
36667
+ function ExecuteTranspiledRequestFromFrontToApi(model) {
36668
+ return {
36669
+ osfql: model.osfql
36670
+ };
36671
+ }
36672
+ function ExecuteTranspiledResponseFromApiToFront(dto) {
36673
+ return {
36674
+ // `rows` are the source's OWN records; their keys are its column names and
36675
+ // are data, carried verbatim. The generated type erases them to `any[]`,
36676
+ // so the shipped surface narrows them to one object per row (#12).
36677
+ rows: dto.rows,
36678
+ rowCount: dto.row_count,
36679
+ query: dto.query,
36680
+ dialect: dto.dialect,
36681
+ sourceId: dto.source_id
36682
+ };
36683
+ }
36439
36684
  function TranspileRequestFromFrontToApi(model) {
36440
36685
  return {
36441
36686
  dialect: model.dialect,
@@ -36694,6 +36939,46 @@ var OntologyBridgeClient = class {
36694
36939
  );
36695
36940
  return TranspileResponseFromApiToFront(response.data);
36696
36941
  }
36942
+ /**
36943
+ * Transpile an OSFQL query AND run it on the source it is bound to.
36944
+ *
36945
+ * @param request - The OSFQL query. No dialect: the binding names the
36946
+ * source, and the source's type decides the dialect.
36947
+ * @param requestOptions - Per-call request options.
36948
+ * @returns The rows the source returned, the native query that fetched them,
36949
+ * its dialect, and the source id.
36950
+ * @throws {ApiError} If the request fails.
36951
+ *
36952
+ * @remarks
36953
+ * Sent to `POST /api/v1/ontology/query`. The response uses the snake_case
36954
+ * wire format (`row_count`, `source_id`); this client normalizes at the
36955
+ * boundary. `rows` are the source's own records, one object per row, and
36956
+ * their KEYS are the source's column names — data, carried verbatim.
36957
+ *
36958
+ * **This is the second half of {@link OntologyBridgeClient.transpile}, and
36959
+ * for a `transpile`-mode source it is the only route that answers.** Such a
36960
+ * source deliberately ingests nothing: its bound sorts are live views over
36961
+ * the operator's own database, so every KB query over them reports no
36962
+ * results. `transpile` emits the native query and stops; this runs it.
36963
+ *
36964
+ * @example
36965
+ * ```typescript
36966
+ * const result = await client.ontologyBridge.executeTranspiled({
36967
+ * osfql: 'MATCH person(name: ?N);',
36968
+ * });
36969
+ * console.log(result.dialect); // "postgres"
36970
+ * console.log(result.query); // the SQL that ran
36971
+ * console.log(result.rowCount); // 12
36972
+ * for (const row of result.rows) console.log(row['name']);
36973
+ * ```
36974
+ */
36975
+ async executeTranspiled(request, requestOptions) {
36976
+ const response = await this.api.executeTranspiled(
36977
+ ExecuteTranspiledRequestFromFrontToApi(request),
36978
+ toRequestParams(requestOptions)
36979
+ );
36980
+ return ExecuteTranspiledResponseFromApiToFront(response.data);
36981
+ }
36697
36982
  /**
36698
36983
  * Remove a sort-table binding.
36699
36984
  *
@@ -38939,12 +39224,46 @@ function ConformanceRequestFromFrontToApi(model) {
38939
39224
  ontology: model.ontology
38940
39225
  };
38941
39226
  }
39227
+ function stringAt(source, key) {
39228
+ const value = Reflect.get(source, key);
39229
+ return typeof value === "string" ? value : void 0;
39230
+ }
39231
+ function suggestedFixesAt(source) {
39232
+ const value = Reflect.get(source, "suggested_fixes");
39233
+ if (!Array.isArray(value)) return void 0;
39234
+ const fixes = [];
39235
+ for (const entry of value) {
39236
+ if (typeof entry === "object" && entry !== null && !Array.isArray(entry)) {
39237
+ fixes.push({ ...entry });
39238
+ }
39239
+ }
39240
+ return fixes;
39241
+ }
39242
+ function ConformanceViolationDtoFromApiToFront(dto) {
39243
+ if (typeof dto !== "object" || dto === null) return {};
39244
+ const violation = {};
39245
+ const subject = stringAt(dto, "subject");
39246
+ if (subject !== void 0) violation.subject = subject;
39247
+ const object = stringAt(dto, "object");
39248
+ if (object !== void 0) violation.object = object;
39249
+ const feature = stringAt(dto, "feature");
39250
+ if (feature !== void 0) violation.feature = feature;
39251
+ const subjectSort = stringAt(dto, "subject_sort");
39252
+ if (subjectSort !== void 0) violation.subjectSort = subjectSort;
39253
+ const objectSort = stringAt(dto, "object_sort");
39254
+ if (objectSort !== void 0) violation.objectSort = objectSort;
39255
+ const kind = stringAt(dto, "kind");
39256
+ if (kind !== void 0) violation.kind = kind;
39257
+ const suggestedFixes = suggestedFixesAt(dto);
39258
+ if (suggestedFixes !== void 0) violation.suggestedFixes = suggestedFixes;
39259
+ return violation;
39260
+ }
38942
39261
  function ConformanceCheckResponseFromApiToFront(dto) {
38943
39262
  return {
38944
39263
  conformant: dto.conformant,
38945
39264
  totalViolations: dto.total_violations,
38946
39265
  byKind: ViolationCountsDtoFromApiToFront(dto.by_kind),
38947
- violations: dto.violations.map(ViolationDtoFromApiToFront)
39266
+ violations: dto.violations.map(ConformanceViolationDtoFromApiToFront)
38948
39267
  };
38949
39268
  }
38950
39269
  function ConformanceRepairResponseFromApiToFront(dto) {
@@ -38982,6 +39301,11 @@ var ConformanceClient = class {
38982
39301
  * The ontology travels as an opaque string in the declared RDF format; no
38983
39302
  * value serialization is applied to it.
38984
39303
  *
39304
+ * Each violation is a {@link ConformanceViolationDto}, NOT the shared
39305
+ * `ViolationDto`. The two share no key, and the route's OpenAPI slot holds
39306
+ * the wrong one — which is why the fields are narrowed from the wire in the
39307
+ * normalizer and why every one of them is optional (#13).
39308
+ *
38985
39309
  * @example
38986
39310
  * ```typescript
38987
39311
  * const result = await client.conformance.check({
@@ -38993,7 +39317,8 @@ var ConformanceClient = class {
38993
39317
  * console.log(result.totalViolations, 'violations');
38994
39318
  * console.log(result.byKind.v1Inversion, 'subject/object inversions');
38995
39319
  * for (const violation of result.violations) {
38996
- * console.log(violation.severity, violation.description);
39320
+ * console.log(violation.kind, violation.subject, violation.feature, violation.object);
39321
+ * console.log(violation.suggestedFixes); // [{ action: 'swap' }]
38997
39322
  * }
38998
39323
  * }
38999
39324
  * ```