@kortexya/reasoninglayer 1.13.0 → 1.15.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.13.0";
8
+ var SDK_VERSION = "1.15.0";
9
9
  function resolveConfig(config) {
10
10
  if (!config.baseUrl) {
11
11
  throw new Error("ClientConfig.baseUrl is required");
@@ -541,29 +541,61 @@ var HttpClient = class {
541
541
  };
542
542
  };
543
543
 
544
- // src/serialization.ts
544
+ // src/user-data-fields.ts
545
545
  var USER_DATA_FIELDS = /* @__PURE__ */ new Set([
546
- // features — term/query feature maps (Record<string, ValueDto>)
547
- "features",
548
- // bindings — variable binding maps
546
+ "annotations",
547
+ "answers",
548
+ "antecedentFeatures",
549
+ "antecedent_features",
549
550
  "bindings",
550
- // evidence — causal evidence maps
551
+ "coefficients",
552
+ "conceptValues",
553
+ "concept_values",
554
+ "contextDependentRelations",
555
+ "context_dependent_relations",
556
+ "correctPattern",
557
+ "correct_pattern",
558
+ "currentValues",
559
+ "current_values",
560
+ "dataVersions",
561
+ "data_versions",
551
562
  "evidence",
552
- // exogenous values — causal intervention values
553
- "exogenous_values",
554
- "exogenousValues",
555
- // modified/suggested params — action review params
556
- "modified_params",
563
+ "extra",
564
+ "extracted",
565
+ "features",
566
+ "fieldTypes",
567
+ "field_types",
568
+ "filter",
569
+ "initialBindings",
570
+ "initial_bindings",
571
+ "inputs",
572
+ "interventions",
557
573
  "modifiedParams",
558
- "suggested_params",
559
- "suggestedParams",
560
- // match key — row matching keys
561
- "match_key",
562
- "matchKey",
563
- // concept values — RAG concept values
564
- "concept_values",
565
- "conceptValues"
574
+ "modified_params",
575
+ "observations",
576
+ "optionalInputs",
577
+ "optional_inputs",
578
+ "original",
579
+ "originalValues",
580
+ "original_values",
581
+ "outputs",
582
+ "perStrategyTaxonomies",
583
+ "per_strategy_taxonomies",
584
+ "propsOverride",
585
+ "props_override",
586
+ "roleMinimums",
587
+ "role_minimums",
588
+ "scope",
589
+ "scoresByName",
590
+ "scores_by_name",
591
+ "sortNames",
592
+ "sort_names",
593
+ "topK",
594
+ "top_k",
595
+ "values"
566
596
  ]);
597
+
598
+ // src/serialization.ts
567
599
  function camelToSnake(str) {
568
600
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
569
601
  }
@@ -630,11 +662,11 @@ function buildAuthHeaders(config) {
630
662
  return headers;
631
663
  }
632
664
  function transformRequestInit(init) {
633
- if (!init?.body || typeof init.body !== "string") return init;
634
- const headers = init.headers;
635
- if (hasRawBodyHeader(headers)) {
636
- return { ...init, headers: withoutRawBodyHeader(headers) };
665
+ if (!init) return init;
666
+ if (hasRawBodyHeader(init.headers)) {
667
+ return { ...init, headers: withoutRawBodyHeader(init.headers) };
637
668
  }
669
+ if (!init.body || typeof init.body !== "string") return init;
638
670
  try {
639
671
  const parsed = JSON.parse(init.body);
640
672
  const snaked = toSnakeCase(parsed);
@@ -643,15 +675,14 @@ function transformRequestInit(init) {
643
675
  return init;
644
676
  }
645
677
  }
678
+ var RAW_BODY_HEADER_LOWER = RAW_BODY_HEADER.toLowerCase();
646
679
  function hasRawBodyHeader(headers) {
647
680
  if (!headers) return false;
648
681
  if (headers instanceof Headers) return headers.get(RAW_BODY_HEADER) !== null;
649
682
  if (Array.isArray(headers)) {
650
- return headers.some(([name]) => name.toLowerCase() === RAW_BODY_HEADER.toLowerCase());
683
+ return headers.some(([name]) => name.toLowerCase() === RAW_BODY_HEADER_LOWER);
651
684
  }
652
- return Object.keys(headers).some(
653
- (name) => name.toLowerCase() === RAW_BODY_HEADER.toLowerCase()
654
- );
685
+ return Object.keys(headers).some((name) => name.toLowerCase() === RAW_BODY_HEADER_LOWER);
655
686
  }
656
687
  function withoutRawBodyHeader(headers) {
657
688
  if (headers instanceof Headers) {
@@ -660,12 +691,12 @@ function withoutRawBodyHeader(headers) {
660
691
  return copy;
661
692
  }
662
693
  if (Array.isArray(headers)) {
663
- return headers.filter(([name]) => name.toLowerCase() !== RAW_BODY_HEADER.toLowerCase());
694
+ return headers.filter(([name]) => name.toLowerCase() !== RAW_BODY_HEADER_LOWER);
664
695
  }
665
696
  if (headers) {
666
697
  const rest = {};
667
698
  for (const [name, value] of Object.entries(headers)) {
668
- if (name.toLowerCase() !== RAW_BODY_HEADER.toLowerCase()) {
699
+ if (name.toLowerCase() !== RAW_BODY_HEADER_LOWER) {
669
700
  rest[name] = value;
670
701
  }
671
702
  }
@@ -1381,9 +1412,10 @@ var Terms = class {
1381
1412
  * @request GET:/api/v1/terms
1382
1413
  * @secure
1383
1414
  */
1384
- listTerms = (params = {}) => this.http.request({
1415
+ listTerms = (query, params = {}) => this.http.request({
1385
1416
  path: `/api/v1/terms`,
1386
1417
  method: "GET",
1418
+ query,
1387
1419
  secure: true,
1388
1420
  format: "json",
1389
1421
  ...params
@@ -1463,7 +1495,7 @@ var Inference = class {
1463
1495
  ...params
1464
1496
  });
1465
1497
  /**
1466
- * @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"}] } ``` # Authorization Requires X-Tenant-Id header.
1498
+ * @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"}] } ``` # 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.
1467
1499
  *
1468
1500
  * @tags inference
1469
1501
  * @name BackwardChain
@@ -1720,9 +1752,10 @@ var Inference = class {
1720
1752
  * @request GET:/api/v1/inference/facts/{tenant_id}
1721
1753
  * @secure
1722
1754
  */
1723
- getFacts = (tenantId, params = {}) => this.http.request({
1755
+ getFacts = (tenantId, query, params = {}) => this.http.request({
1724
1756
  path: `/api/v1/inference/facts/${tenantId}`,
1725
1757
  method: "GET",
1758
+ query,
1726
1759
  secure: true,
1727
1760
  format: "json",
1728
1761
  ...params
@@ -2612,7 +2645,7 @@ var Ingestion = class {
2612
2645
  ...params
2613
2646
  });
2614
2647
  /**
2615
- * @description POST /api/v1/ingest/document This endpoint accepts a document (as base64 or URL) and: 1. Parses it to Markdown using the document parser service (Docling) 2. Processes the Markdown through the existing ingestion pipeline 3. Returns combined statistics from both stages # Headers - `X-Tenant-Id`: Tenant ID for multi-tenancy isolation (required) # Request Body - `document`: Document source (base64 or URL) - `document_type`: Optional type hint (auto-detected if not provided) - `owner_id`: User ID who owns the ingested data - `ocr_config`: Optional OCR/parsing configuration - `ingestion_config`: Optional markdown ingestion configuration # Response - `success`: Whether ingestion completed successfully - `parse_stats`: Statistics from document parsing - `metadata`: Extracted document metadata - `ingestion_stats`: Statistics from markdown ingestion - `pending_review`: Entities that need human review
2648
+ * @description POST /api/v1/ingest/document This endpoint accepts a document (as base64 or URL) and: 1. Parses it to Markdown using the document parser service (Docling) 2. Returns the generated Markdown to the caller 3. Unless `parse_only` is true, processes the Markdown through ingestion 4. Returns combined statistics from the completed stages # Headers - `X-Tenant-Id`: Tenant ID for multi-tenancy isolation (required) # Request Body - `document`: Document source (base64 or URL) - `document_type`: Optional type hint (auto-detected if not provided) - `owner_id`: User ID who owns the ingested data - `ocr_config`: Optional OCR/parsing configuration - `ingestion_config`: Optional markdown ingestion configuration - `parse_only`: Return Markdown without creating sessions or semantic terms # Response - `success`: Whether ingestion completed successfully - `parse_stats`: Statistics from document parsing - `metadata`: Extracted document metadata - `markdown`: Markdown generated by Docling/OCR - `ingestion_stats`: Statistics from markdown ingestion - `pending_review`: Entities that need human review
2616
2649
  *
2617
2650
  * @tags ingestion
2618
2651
  * @name IngestDocument
@@ -2947,6 +2980,22 @@ var StructuredIngestion = class {
2947
2980
  format: "json",
2948
2981
  ...params
2949
2982
  });
2983
+ /**
2984
+ * @description The pre-registration half of #71's mode-discovery surface: a client rendering a "new source" picker learns, at type-selection time, which types registration would accept and which write-path modes each would serve — without constructing a source (postgres, for example, opens a connection pool eagerly). Static per build, so no tenant state is consulted; auth is still required, as for every route under `/api/v1`.
2985
+ *
2986
+ * @tags structured_ingestion
2987
+ * @name ListSourceTypesCatalog
2988
+ * @summary List the source types this build can register, with their mode capabilities.
2989
+ * @request GET:/api/v1/sources/types
2990
+ * @secure
2991
+ */
2992
+ listSourceTypesCatalog = (params = {}) => this.http.request({
2993
+ path: `/api/v1/sources/types`,
2994
+ method: "GET",
2995
+ secure: true,
2996
+ format: "json",
2997
+ ...params
2998
+ });
2950
2999
  /**
2951
3000
  * @description Creates a connector instance from the provided configuration and registers it with the structured ingestion service for subsequent schema discovery and data ingestion.
2952
3001
  *
@@ -12089,7 +12138,8 @@ function ProofDtoFromApiToFront(dto) {
12089
12138
  ruleLabel: dto.rule_label,
12090
12139
  substitution: HomoiconicSubstitutionDtoFromApiToFront(dto.substitution),
12091
12140
  subproofs: dto.subproofs?.map(ProofDtoFromApiToFront),
12092
- certainty: dto.certainty
12141
+ certainty: dto.certainty,
12142
+ residuated: dto.residuated
12093
12143
  };
12094
12144
  }
12095
12145
  function ProvenanceTagDtoFromApiToFront(dto) {
@@ -12105,6 +12155,7 @@ function SolutionDtoFromApiToFront(dto) {
12105
12155
  certainty: dto.certainty,
12106
12156
  evidenceMatched: dto.evidence_matched ?? void 0,
12107
12157
  evidenceRatio: dto.evidence_ratio ?? void 0,
12158
+ evidenceSupport: dto.evidence_support ?? void 0,
12108
12159
  residuatedSorts: dto.residuated_sorts
12109
12160
  };
12110
12161
  }
@@ -12483,11 +12534,19 @@ function TaggedForwardChainResponseFromApiToFront(dto) {
12483
12534
  totalFacts: dto.total_facts
12484
12535
  };
12485
12536
  }
12537
+ function RuleAggregatorDtoFromFrontToApi(model) {
12538
+ return {
12539
+ group_by: model.groupBy,
12540
+ op: model.op,
12541
+ target: model.target
12542
+ };
12543
+ }
12486
12544
  function AddRuleRequestFromFrontToApi(model) {
12487
12545
  return {
12488
12546
  term: TermInputDtoFromFrontToApi(model.term),
12489
12547
  antecedents: model.antecedents?.map(TermInputDtoFromFrontToApi),
12490
- certainty: model.certainty
12548
+ certainty: model.certainty,
12549
+ aggregator: model.aggregator ? RuleAggregatorDtoFromFrontToApi(model.aggregator) : model.aggregator
12491
12550
  };
12492
12551
  }
12493
12552
  function AddFactRequestFromFrontToApi(model) {
@@ -12524,7 +12583,8 @@ function ForwardChainRequestFromFrontToApi(model) {
12524
12583
  persist_derived: model.persistDerived,
12525
12584
  enable_provenance_tags: model.enableProvenanceTags,
12526
12585
  max_iterations: model.maxIterations,
12527
- max_facts: model.maxFacts
12586
+ max_facts: model.maxFacts,
12587
+ emit_provenance: model.emitProvenance
12528
12588
  };
12529
12589
  }
12530
12590
  function FuzzyProveRequestFromFrontToApi(model) {
@@ -12535,7 +12595,8 @@ function FuzzyProveRequestFromFrontToApi(model) {
12535
12595
  max_solutions: model.maxSolutions,
12536
12596
  open_world: model.openWorld,
12537
12597
  save_goal: model.saveGoal,
12538
- tnorm: model.tnorm
12598
+ tnorm: model.tnorm,
12599
+ scope: model.scope
12539
12600
  };
12540
12601
  }
12541
12602
  function BulkFuzzyProveRequestFromFrontToApi(model) {
@@ -12641,14 +12702,29 @@ var InferenceClient = class {
12641
12702
  /**
12642
12703
  * Add an inference rule.
12643
12704
  *
12644
- * @param request - Rule definition using TermInputDto.
12705
+ * @param request - Rule definition using TermInputDto. Set `aggregator` to declare an
12706
+ * engine-side head aggregator (see {@link RuleAggregatorDto}).
12645
12707
  * @returns The created rule wrapped in an AddRuleResponse.
12708
+ * @throws {ApiError} If the rule is rejected or the request fails.
12709
+ *
12710
+ * @remarks
12711
+ * **Serialization format**: untagged `TermInputDto` / `FeatureInputValueDto`.
12712
+ *
12713
+ * @example
12714
+ * ```typescript
12715
+ * await client.inference.addRule({
12716
+ * term: psi('total_spend', { customer_id: Var('C'), amount: Var('A') }),
12717
+ * antecedents: [psi('order', { customer_id: Var('C'), amount: Var('A') })],
12718
+ * aggregator: { groupBy: ['customer_id'], op: 'sum', target: 'amount' },
12719
+ * });
12720
+ * ```
12646
12721
  */
12647
12722
  async addRule(request) {
12648
12723
  const wireRequest = {
12649
12724
  term: convertTermArg(request.term),
12650
12725
  antecedents: request.antecedents?.map(convertTermArg),
12651
- certainty: request.certainty
12726
+ certainty: request.certainty,
12727
+ aggregator: request.aggregator
12652
12728
  };
12653
12729
  const response = await this.api.addRule(AddRuleRequestFromFrontToApi(wireRequest));
12654
12730
  return AddRuleResponseFromApiToFront(response.data);
@@ -17265,6 +17341,22 @@ function CausalAnalyzeRequestFromFrontToApi(model) {
17265
17341
  question: CausalAnalyzeQuestionDtoFromFrontToApi(model.question)
17266
17342
  };
17267
17343
  }
17344
+ function DiDValidationRequestFromFrontToApi(model) {
17345
+ return {
17346
+ covariates: model.covariates,
17347
+ outcome_post: model.outcomePost,
17348
+ outcome_pre: model.outcomePre,
17349
+ treatment: model.treatment
17350
+ };
17351
+ }
17352
+ function DiDValidationResponseFromApiToFront(dto) {
17353
+ return {
17354
+ badControls: dto.bad_controls,
17355
+ explanation: dto.explanation,
17356
+ framework: dto.framework,
17357
+ isValid: dto.is_valid
17358
+ };
17359
+ }
17268
17360
 
17269
17361
  // src/resources/causal.ts
17270
17362
  var CausalClient = class {
@@ -18055,6 +18147,53 @@ var CausalClient = class {
18055
18147
  );
18056
18148
  return RefuteEstimateResponseFromApiToFront(response.data);
18057
18149
  }
18150
+ // ===========================================================================
18151
+ // Design validation
18152
+ // ===========================================================================
18153
+ /**
18154
+ * Validate a Difference-in-Differences (DiD) design.
18155
+ *
18156
+ * @param request - The treatment variable, the pre- and post-treatment outcome
18157
+ * variables, and an optional conditioning set.
18158
+ * @returns Whether the design is theoretically sound, an explanation, the bad
18159
+ * controls found in the conditioning set, and the framework used.
18160
+ * @throws {BadRequestError} If the request is malformed.
18161
+ * @throws {ApiError} If the request otherwise fails.
18162
+ *
18163
+ * @remarks
18164
+ * Checks the design against the causal structure the backend builds from the
18165
+ * tenant's homoiconic rules, using the Transformed SWIG (Delta-SWIG) framework
18166
+ * of Knaus & Pfleiderer (2026). This is a design check over the *graph*: no
18167
+ * sample data is submitted and nothing is estimated — validate the design here,
18168
+ * then estimate the effect with {@link CausalClient.ateEstimate}.
18169
+ *
18170
+ * A design can be invalid even with an empty conditioning set (parallel trends
18171
+ * unsupported by the structure); `badControls` names the covariates that induce
18172
+ * bias if conditioned on, so an invalid design is often repaired by dropping
18173
+ * them and re-validating.
18174
+ *
18175
+ * Plain scalar JSON — no value serialization (`ValueDto` / `FeatureValueDto`)
18176
+ * is involved.
18177
+ *
18178
+ * @example
18179
+ * ```typescript
18180
+ * const did = await client.causal.validateDid({
18181
+ * treatment: 'minimum_wage_hike',
18182
+ * outcomePre: 'employment_2025',
18183
+ * outcomePost: 'employment_2026',
18184
+ * covariates: ['county_gdp'],
18185
+ * });
18186
+ * console.log(did.isValid); // false
18187
+ * console.log(did.badControls); // ['county_gdp']
18188
+ * console.log(did.framework); // 'Delta-SWIG (Knaus & Pfleiderer, 2026)'
18189
+ * ```
18190
+ */
18191
+ async validateDid(request) {
18192
+ const response = await this.api.validateDid(
18193
+ DiDValidationRequestFromFrontToApi(request)
18194
+ );
18195
+ return DiDValidationResponseFromApiToFront(response.data);
18196
+ }
18058
18197
  };
18059
18198
 
18060
18199
  // src/normalizers/ingestion.ts
@@ -20963,7 +21102,8 @@ function RegisterSourceRequestFromFrontToApi(model) {
20963
21102
  source_id: model.sourceId,
20964
21103
  source_name: model.sourceName,
20965
21104
  source_type: model.sourceType,
20966
- config: model.config
21105
+ config: model.config,
21106
+ mode: model.mode
20967
21107
  };
20968
21108
  }
20969
21109
  function RegisterSourceResponseFromApiToFront(dto) {
@@ -20971,12 +21111,15 @@ function RegisterSourceResponseFromApiToFront(dto) {
20971
21111
  success: dto.success,
20972
21112
  sourceId: dto.source_id,
20973
21113
  sourceType: dto.source_type,
21114
+ mode: dto.mode,
21115
+ supportedModes: dto.supported_modes,
20974
21116
  message: dto.message
20975
21117
  };
20976
21118
  }
20977
21119
  function SourceSummaryDtoFromApiToFront(dto) {
20978
21120
  return {
20979
21121
  available: dto.available,
21122
+ mode: dto.mode,
20980
21123
  sourceId: dto.source_id,
20981
21124
  sourceType: dto.source_type
20982
21125
  };
@@ -20991,7 +21134,22 @@ function SourceDetailResponseFromApiToFront(dto) {
20991
21134
  return {
20992
21135
  sourceId: dto.source_id,
20993
21136
  sourceType: dto.source_type,
20994
- available: dto.available
21137
+ available: dto.available,
21138
+ mode: dto.mode,
21139
+ supportedModes: dto.supported_modes
21140
+ };
21141
+ }
21142
+ function SourceTypeDtoFromApiToFront(dto) {
21143
+ return {
21144
+ sourceType: dto.source_type,
21145
+ aliases: dto.aliases,
21146
+ available: dto.available,
21147
+ supportedModes: dto.supported_modes
21148
+ };
21149
+ }
21150
+ function ListSourceTypesResponseFromApiToFront(dto) {
21151
+ return {
21152
+ types: dto.types.map(SourceTypeDtoFromApiToFront)
20995
21153
  };
20996
21154
  }
20997
21155
  function DiscoverSchemaRequestFromFrontToApi(model) {
@@ -21071,6 +21229,7 @@ function IngestFromSourceRequestFromFrontToApi(model) {
21071
21229
  function StructuredIngestionStatsDtoFromApiToFront(dto) {
21072
21230
  return {
21073
21231
  columnsDiscovered: dto.columns_discovered,
21232
+ columnsDropped: dto.columns_dropped,
21074
21233
  documentsRendered: dto.documents_rendered,
21075
21234
  elapsedMs: dto.elapsed_ms,
21076
21235
  entitiesCreated: dto.entities_created,
@@ -21080,7 +21239,8 @@ function StructuredIngestionStatsDtoFromApiToFront(dto) {
21080
21239
  relationsDiscovered: dto.relations_discovered,
21081
21240
  sortsCreated: dto.sorts_created,
21082
21241
  tablesDiscovered: dto.tables_discovered,
21083
- termsCreated: dto.terms_created
21242
+ termsCreated: dto.terms_created,
21243
+ termsProjected: dto.terms_projected
21084
21244
  };
21085
21245
  }
21086
21246
  function IngestFromSourceResponseFromApiToFront(dto) {
@@ -21104,13 +21264,72 @@ var SourcesClient = class {
21104
21264
  /**
21105
21265
  * Register a new data source.
21106
21266
  *
21107
- * @param request - Source registration request.
21108
- * @returns Registration result.
21267
+ * @param request - Source registration request. Set `mode` to declare the write-path
21268
+ * intent (`'transpile'` for live SQL views, `'ingest'` to materialize rows as
21269
+ * Ψ-term facts); omit it to take the default, which is `'ingest'` for every
21270
+ * source type (#71).
21271
+ * @returns Registration result. `mode` always carries the **resolved** write-path
21272
+ * mode, including when the default applied; `supportedModes` advertises which
21273
+ * modes this source's adapter can serve.
21274
+ * @throws {ApiError} If registration fails, with **422** if `mode` is not one of
21275
+ * `transpile` / `ingest`, or with **422** if `mode: 'transpile'` is requested
21276
+ * for a source whose adapter cannot execute transpiled SQL (a live view over it
21277
+ * could never be queried).
21278
+ *
21279
+ * @remarks
21280
+ * Registering with `mode: 'transpile'` makes {@link SourcesClient.ingest} refuse this
21281
+ * source with a **409** — materializing a transpiled source would create a second,
21282
+ * divergent namespace over the same rows. To learn which types accept `transpile`
21283
+ * before registering, call {@link SourcesClient.listSourceTypes}.
21284
+ *
21285
+ * @example
21286
+ * ```typescript
21287
+ * const result = await client.sources.register({
21288
+ * sourceId: 'crm_postgres',
21289
+ * sourceName: 'CRM PostgreSQL',
21290
+ * sourceType: 'postgres',
21291
+ * config: { connection_string: 'postgres://user:pass@host/db' },
21292
+ * mode: 'ingest',
21293
+ * });
21294
+ * console.log(result.mode); // 'ingest'
21295
+ * console.log(result.supportedModes); // ['ingest', 'transpile']
21296
+ * ```
21109
21297
  */
21110
21298
  async register(request) {
21111
21299
  const response = await this.api.registerSource(RegisterSourceRequestFromFrontToApi(request));
21112
21300
  return RegisterSourceResponseFromApiToFront(response.data);
21113
21301
  }
21302
+ /**
21303
+ * List the source types this build can register, with their mode capabilities.
21304
+ *
21305
+ * @returns Every registrable source type, its availability in this build, and the
21306
+ * write-path modes each would serve — before any source exists.
21307
+ * @throws {ApiError} If the request fails.
21308
+ *
21309
+ * @remarks
21310
+ * Sent to `GET /api/v1/sources/types`. The pre-registration half of #71's
21311
+ * mode-discovery surface: a client rendering a "new source" picker learns, at
21312
+ * type-selection time, which types registration would accept (`available` — a
21313
+ * type behind an uncompiled cargo feature is `false`) and which modes each
21314
+ * would serve (`supportedModes` — always `'ingest'`, plus `'transpile'` only
21315
+ * for the SQL engines). Static per build, so no tenant state is consulted.
21316
+ *
21317
+ * Drive a mode selector from `supportedModes` rather than a hard-coded list of
21318
+ * source types: the set is the adapter's declared capability, so it stays
21319
+ * correct as adapters gain the ability (MySQL and SQLite did in #70).
21320
+ *
21321
+ * @example
21322
+ * ```typescript
21323
+ * const { types } = await client.sources.listSourceTypes();
21324
+ * const postgres = types.find((t) => t.sourceType === 'postgres');
21325
+ * console.log(postgres?.supportedModes); // ['ingest', 'transpile']
21326
+ * console.log(postgres?.aliases); // ['postgresql']
21327
+ * ```
21328
+ */
21329
+ async listSourceTypes() {
21330
+ const response = await this.api.listSourceTypesCatalog();
21331
+ return ListSourceTypesResponseFromApiToFront(response.data);
21332
+ }
21114
21333
  /**
21115
21334
  * List all registered data sources.
21116
21335
  *
@@ -22281,13 +22500,35 @@ function mapEntity(e) {
22281
22500
  sourceText: e.source_text ?? null
22282
22501
  };
22283
22502
  }
22503
+ function toRuleSeverity(severity) {
22504
+ switch (severity) {
22505
+ case "critical":
22506
+ case "major":
22507
+ case "minor":
22508
+ case "informational":
22509
+ return severity;
22510
+ default:
22511
+ return "informational";
22512
+ }
22513
+ }
22514
+ function toRuleStatus(status) {
22515
+ switch (status) {
22516
+ case "pass":
22517
+ case "fail":
22518
+ case "inconclusive":
22519
+ case "not_applicable":
22520
+ return status;
22521
+ default:
22522
+ return "inconclusive";
22523
+ }
22524
+ }
22284
22525
  function mapRuleResult(r) {
22285
22526
  return {
22286
22527
  ruleId: r.rule_id ?? "",
22287
22528
  ruleDescription: r.rule_description ?? "",
22288
22529
  ruleSort: r.rule_sort ?? "",
22289
- severity: r.severity ?? "informational",
22290
- status: r.status ?? "inconclusive",
22530
+ severity: toRuleSeverity(r.severity),
22531
+ status: toRuleStatus(r.status),
22291
22532
  confidence: r.confidence ?? 0,
22292
22533
  evidence: r.evidence ?? [],
22293
22534
  proofTrace: r.proof_trace ? r.proof_trace.map(mapProofStep) : null,
@@ -26537,11 +26778,112 @@ var FlowNetworksClient = class {
26537
26778
  };
26538
26779
 
26539
26780
  // src/normalizers/osfql.ts
26781
+ function isRecord(value) {
26782
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26783
+ }
26784
+ function OsfqlValueFromApiToFront(value) {
26785
+ if (!isRecord(value)) {
26786
+ return void 0;
26787
+ }
26788
+ const payload = value["value"];
26789
+ switch (value["type"]) {
26790
+ case "null":
26791
+ return { type: "null" };
26792
+ case "integer":
26793
+ return typeof payload === "number" ? { type: "integer", value: payload } : void 0;
26794
+ case "float":
26795
+ return typeof payload === "number" ? { type: "float", value: payload } : void 0;
26796
+ case "string":
26797
+ return typeof payload === "string" ? { type: "string", value: payload } : void 0;
26798
+ case "boolean":
26799
+ return typeof payload === "boolean" ? { type: "boolean", value: payload } : void 0;
26800
+ case "term_ref":
26801
+ return typeof payload === "string" ? { type: "term_ref", value: payload } : void 0;
26802
+ case "list": {
26803
+ if (!Array.isArray(payload)) {
26804
+ return void 0;
26805
+ }
26806
+ const items = payload;
26807
+ const parsed = [];
26808
+ for (const item of items) {
26809
+ const element = OsfqlValueFromApiToFront(item);
26810
+ if (element === void 0) {
26811
+ return void 0;
26812
+ }
26813
+ parsed.push(element);
26814
+ }
26815
+ return { type: "list", value: parsed };
26816
+ }
26817
+ case "term": {
26818
+ const term = OsfqlTermValueFromApiToFront(payload);
26819
+ return term === void 0 ? void 0 : { type: "term", value: term };
26820
+ }
26821
+ default:
26822
+ return void 0;
26823
+ }
26824
+ }
26825
+ function OsfqlTermValueFromApiToFront(value) {
26826
+ if (!isRecord(value)) {
26827
+ return void 0;
26828
+ }
26829
+ const sort = value["sort"];
26830
+ if (typeof sort !== "string") {
26831
+ return void 0;
26832
+ }
26833
+ const features = OsfqlBindingFromApiToFront(value["features"]);
26834
+ return features === void 0 ? void 0 : { sort, features };
26835
+ }
26836
+ function OsfqlBindingFromApiToFront(value) {
26837
+ if (!isRecord(value)) {
26838
+ return void 0;
26839
+ }
26840
+ const out = {};
26841
+ for (const [name, raw] of Object.entries(value)) {
26842
+ const parsed = OsfqlValueFromApiToFront(raw);
26843
+ if (parsed === void 0) {
26844
+ return void 0;
26845
+ }
26846
+ out[name] = parsed;
26847
+ }
26848
+ return out;
26849
+ }
26850
+ function OsfqlBindingsFromApiToFront(value) {
26851
+ if (!Array.isArray(value)) {
26852
+ return void 0;
26853
+ }
26854
+ const rows = value;
26855
+ const out = [];
26856
+ for (const row of rows) {
26857
+ const parsed = OsfqlBindingFromApiToFront(row);
26858
+ if (parsed === void 0) {
26859
+ return void 0;
26860
+ }
26861
+ out.push(parsed);
26862
+ }
26863
+ return out;
26864
+ }
26865
+ function OsfqlRequestFromFrontToApi(model) {
26866
+ return {
26867
+ query: model.query,
26868
+ reactive: model.reactive
26869
+ };
26870
+ }
26540
26871
  function OsfqlResponseFromApiToFront(dto) {
26872
+ const bindings = OsfqlBindingsFromApiToFront(dto.bindings);
26873
+ if (bindings === void 0) {
26874
+ return void 0;
26875
+ }
26876
+ let fetched;
26877
+ if (dto.fetched !== void 0 && dto.fetched !== null) {
26878
+ fetched = OsfqlBindingsFromApiToFront(dto.fetched);
26879
+ if (fetched === void 0) {
26880
+ return void 0;
26881
+ }
26882
+ }
26541
26883
  return {
26542
26884
  success: dto.success,
26543
- bindings: dto.bindings,
26544
- fetched: dto.fetched,
26885
+ bindings,
26886
+ fetched,
26545
26887
  producedTermIds: dto.produced_term_ids,
26546
26888
  definedSortIds: dto.defined_sort_ids,
26547
26889
  diagnostics: dto.diagnostics,
@@ -26587,15 +26929,28 @@ var OsfqlClient = class {
26587
26929
  * Execute an OSFQL program.
26588
26930
  *
26589
26931
  * @param query - The OSFQL program text (one or more statements separated by `;`).
26932
+ * @param options - Optional execution options. Set `reactive` to fire suspended
26933
+ * `AWAIT` demons whose triggers the program has just satisfied.
26590
26934
  * @returns The execution result including variable bindings, produced term IDs,
26591
26935
  * defined sort IDs, diagnostics, and statement count.
26592
26936
  * @throws {ApiError} If the request fails.
26937
+ * @throws {ReasoningLayerError} If the server returns bindings that do not satisfy the
26938
+ * published {@link OsfqlValue} contract.
26593
26939
  *
26594
26940
  * @remarks
26595
26941
  * The query is parsed, compiled, and executed against the caller's tenant-isolated
26596
26942
  * knowledge base. Results include variable bindings from MATCH queries and IDs of
26597
26943
  * any terms or sorts created by INSERT, DERIVE, or DEFINE statements.
26598
26944
  *
26945
+ * Bindings use the **tagged** {@link OsfqlValue} format with lowercase `type`
26946
+ * discriminators — not the PascalCase `ValueDto` term-CRUD format.
26947
+ *
26948
+ * `reactive` opts into **reactive (streaming) mode**: once the program has run,
26949
+ * any suspended `AWAIT` demon whose trigger is now satisfied fires
26950
+ * automatically, with no explicit `RELEASE RESIDUATIONS` statement. It defaults
26951
+ * to `false` — demons stay suspended until an explicit RELEASE — so omitting it
26952
+ * leaves the request byte-identical to before.
26953
+ *
26599
26954
  * @example
26600
26955
  * ```typescript
26601
26956
  * // Insert a record and query it back
@@ -26606,11 +26961,27 @@ var OsfqlClient = class {
26606
26961
  * console.log(result.bindings); // [{ N: { type: "string", value: "Alice" } }]
26607
26962
  * console.log(result.producedTermIds); // ["<uuid>"]
26608
26963
  * console.log(result.statementCount); // 2
26964
+ *
26965
+ * // Let an AWAIT demon fire as soon as its trigger is satisfied
26966
+ * await client.osfql.execute('AWAIT person(name: "Bob");');
26967
+ * const reactive = await client.osfql.execute(
26968
+ * 'INSERT person(name: "Bob", age: 41);',
26969
+ * { reactive: true },
26970
+ * );
26971
+ * console.log(reactive.producedTermIds); // includes the demon's own output
26609
26972
  * ```
26610
26973
  */
26611
- async execute(query) {
26612
- const response = await this.api.executeOsfql({ query });
26613
- return OsfqlResponseFromApiToFront(response.data);
26974
+ async execute(query, options) {
26975
+ const response = await this.api.executeOsfql(
26976
+ OsfqlRequestFromFrontToApi({ query, reactive: options?.reactive })
26977
+ );
26978
+ const parsed = OsfqlResponseFromApiToFront(response.data);
26979
+ if (parsed === void 0) {
26980
+ throw new ReasoningLayerError(
26981
+ "osfql/execute returned bindings that do not match the published OsfqlValue contract (expected tagged values with a lowercase `type` discriminator)"
26982
+ );
26983
+ }
26984
+ return parsed;
26614
26985
  }
26615
26986
  /**
26616
26987
  * Diagnose an OSFQL program for contradictions and inconsistencies.
@@ -26697,7 +27068,9 @@ function ConversationMessageRequestFromFrontToApi(model) {
26697
27068
  conversation_id: model.conversationId,
26698
27069
  session_id: model.sessionId,
26699
27070
  current_sort_context: model.currentSortContext,
26700
- generate_certificate: model.generateCertificate
27071
+ generate_certificate: model.generateCertificate,
27072
+ constrained_decode: model.constrainedDecode,
27073
+ model: model.model
26701
27074
  };
26702
27075
  }
26703
27076
  function DerivationSummaryDtoFromApiToFront(dto) {
@@ -26805,7 +27178,12 @@ function ConversationMessageResponseFromApiToFront(dto) {
26805
27178
  cognitiveStrategy: dto.cognitive_strategy ? CognitiveStrategyDtoFromApiToFront(dto.cognitive_strategy) : void 0,
26806
27179
  reasoningTrace: dto.reasoning_trace ? ReasoningTraceDtoFromApiToFront(dto.reasoning_trace) : void 0,
26807
27180
  validityCertificateHash: dto.validity_certificate_hash ?? void 0,
26808
- validityCertificateId: dto.validity_certificate_id ?? void 0
27181
+ validityCertificateId: dto.validity_certificate_id ?? void 0,
27182
+ validityCertificateRuleProgramHash: dto.validity_certificate_rule_program_hash ?? void 0,
27183
+ validityCertificateRuleRevision: dto.validity_certificate_rule_revision ?? void 0,
27184
+ modelId: dto.model_id ?? void 0,
27185
+ prefillMs: dto.prefill_ms ?? void 0,
27186
+ tokensPerSec: dto.tokens_per_sec ?? void 0
26809
27187
  };
26810
27188
  }
26811
27189
  function TurnDtoFromApiToFront(dto) {
@@ -30651,12 +31029,16 @@ function PropertyGraphQueryRequestFromFrontToApi(model) {
30651
31029
  };
30652
31030
  }
30653
31031
  function PropertyGraphExecuteResponseFromApiToFront(dto) {
31032
+ const bindings = OsfqlBindingsFromApiToFront(dto.bindings);
31033
+ if (bindings === void 0) {
31034
+ return void 0;
31035
+ }
30654
31036
  return {
30655
31037
  success: dto.success,
30656
31038
  language: dto.language,
30657
31039
  operation: dto.operation,
30658
31040
  osfql: dto.osfql,
30659
- bindings: dto.bindings,
31041
+ bindings,
30660
31042
  producedTermIds: dto.produced_term_ids,
30661
31043
  definedSortIds: dto.defined_sort_ids,
30662
31044
  diagnostics: dto.diagnostics,
@@ -30674,13 +31056,27 @@ function PropertyGraphTranslateResponseFromApiToFront(dto) {
30674
31056
  }
30675
31057
 
30676
31058
  // src/resources/property-graph.ts
30677
- var PropertyGraphClient = class {
31059
+ var PropertyGraphClient = class _PropertyGraphClient {
30678
31060
  /** @internal */
30679
31061
  api;
30680
31062
  /** @internal */
30681
31063
  constructor(api) {
30682
31064
  this.api = api;
30683
31065
  }
31066
+ /**
31067
+ * Parse an execution response, failing loudly on a contract violation.
31068
+ *
31069
+ * @internal
31070
+ */
31071
+ static parseExecuteResponse(dto) {
31072
+ const parsed = PropertyGraphExecuteResponseFromApiToFront(dto);
31073
+ if (parsed === void 0) {
31074
+ throw new ReasoningLayerError(
31075
+ "the property-graph endpoint returned bindings that do not match the published PropertyGraphValue contract (expected tagged values with a lowercase `type` discriminator)"
31076
+ );
31077
+ }
31078
+ return parsed;
31079
+ }
30684
31080
  /**
30685
31081
  * Execute a Cypher query.
30686
31082
  *
@@ -30688,6 +31084,8 @@ var PropertyGraphClient = class {
30688
31084
  * @returns Execution result: bindings, the OSFQL program that ran, produced term IDs,
30689
31085
  * defined sort IDs, diagnostics, compatibility notes, and the statement count.
30690
31086
  * @throws {ApiError} If the query cannot be parsed, cannot be lowered to OSFQL, or fails to execute.
31087
+ * @throws {ReasoningLayerError} If the server returns bindings that do not satisfy the
31088
+ * published {@link PropertyGraphValue} contract.
30691
31089
  *
30692
31090
  * @remarks
30693
31091
  * The query is parsed as Cypher, lowered to OSFQL, and executed against the
@@ -30707,7 +31105,7 @@ var PropertyGraphClient = class {
30707
31105
  const response = await this.api.executeCypherPost(
30708
31106
  PropertyGraphQueryRequestFromFrontToApi({ query })
30709
31107
  );
30710
- return PropertyGraphExecuteResponseFromApiToFront(response.data);
31108
+ return _PropertyGraphClient.parseExecuteResponse(response.data);
30711
31109
  }
30712
31110
  /**
30713
31111
  * Execute a GQL (ISO/IEC 39075) query.
@@ -30716,6 +31114,8 @@ var PropertyGraphClient = class {
30716
31114
  * @returns Execution result: bindings, the OSFQL program that ran, produced term IDs,
30717
31115
  * defined sort IDs, diagnostics, compatibility notes, and the statement count.
30718
31116
  * @throws {ApiError} If the query cannot be parsed, cannot be lowered to OSFQL, or fails to execute.
31117
+ * @throws {ReasoningLayerError} If the server returns bindings that do not satisfy the
31118
+ * published {@link PropertyGraphValue} contract.
30719
31119
  *
30720
31120
  * @remarks
30721
31121
  * The query is parsed as GQL, lowered to OSFQL, and executed against the
@@ -30735,7 +31135,7 @@ var PropertyGraphClient = class {
30735
31135
  const response = await this.api.executeGqlPost(
30736
31136
  PropertyGraphQueryRequestFromFrontToApi({ query })
30737
31137
  );
30738
- return PropertyGraphExecuteResponseFromApiToFront(response.data);
31138
+ return _PropertyGraphClient.parseExecuteResponse(response.data);
30739
31139
  }
30740
31140
  /**
30741
31141
  * Execute a Gremlin traversal.
@@ -30744,6 +31144,8 @@ var PropertyGraphClient = class {
30744
31144
  * @returns Execution result: bindings, the OSFQL program that ran, produced term IDs,
30745
31145
  * defined sort IDs, diagnostics, compatibility notes, and the statement count.
30746
31146
  * @throws {ApiError} If the traversal cannot be parsed, cannot be lowered to OSFQL, or fails to execute.
31147
+ * @throws {ReasoningLayerError} If the server returns bindings that do not satisfy the
31148
+ * published {@link PropertyGraphValue} contract.
30747
31149
  *
30748
31150
  * @remarks
30749
31151
  * The traversal is parsed as Gremlin, lowered to OSFQL, and executed against the
@@ -30762,7 +31164,7 @@ var PropertyGraphClient = class {
30762
31164
  const response = await this.api.executeGremlinPost(
30763
31165
  PropertyGraphQueryRequestFromFrontToApi({ query })
30764
31166
  );
30765
- return PropertyGraphExecuteResponseFromApiToFront(response.data);
31167
+ return _PropertyGraphClient.parseExecuteResponse(response.data);
30766
31168
  }
30767
31169
  /**
30768
31170
  * Translate a Cypher query to OSFQL without executing it.
@@ -30848,14 +31250,14 @@ var PropertyGraphClient = class {
30848
31250
  };
30849
31251
 
30850
31252
  // src/normalizers/sparql.ts
30851
- function isRecord(value) {
31253
+ function isRecord2(value) {
30852
31254
  return typeof value === "object" && value !== null && !Array.isArray(value);
30853
31255
  }
30854
31256
  function isString(value) {
30855
31257
  return typeof value === "string";
30856
31258
  }
30857
31259
  function headVars(head) {
30858
- if (!isRecord(head)) {
31260
+ if (!isRecord2(head)) {
30859
31261
  throw new Error('Malformed SPARQL results: "head" is not an object');
30860
31262
  }
30861
31263
  const vars = head["vars"];
@@ -30868,7 +31270,7 @@ function headVars(head) {
30868
31270
  return vars;
30869
31271
  }
30870
31272
  function SparqlRdfTermFromApiToFront(raw) {
30871
- if (!isRecord(raw)) {
31273
+ if (!isRecord2(raw)) {
30872
31274
  throw new Error("Malformed SPARQL results: a solution binding is not an object");
30873
31275
  }
30874
31276
  const termType = raw["type"];
@@ -30893,7 +31295,7 @@ function SparqlRdfTermFromApiToFront(raw) {
30893
31295
  };
30894
31296
  }
30895
31297
  if (termType === "triple") {
30896
- if (!isRecord(value)) {
31298
+ if (!isRecord2(value)) {
30897
31299
  throw new Error('Malformed SPARQL results: "triple" binding has a non-object value');
30898
31300
  }
30899
31301
  return {
@@ -30910,7 +31312,7 @@ function SparqlRdfTermFromApiToFront(raw) {
30910
31312
  );
30911
31313
  }
30912
31314
  function SparqlBindingSetFromApiToFront(raw) {
30913
- if (!isRecord(raw)) {
31315
+ if (!isRecord2(raw)) {
30914
31316
  throw new Error("Malformed SPARQL results: a solution is not an object");
30915
31317
  }
30916
31318
  const bindings = {};
@@ -30920,7 +31322,7 @@ function SparqlBindingSetFromApiToFront(raw) {
30920
31322
  return bindings;
30921
31323
  }
30922
31324
  function bindingsFromResultSet(results) {
30923
- if (!isRecord(results)) {
31325
+ if (!isRecord2(results)) {
30924
31326
  throw new Error('Malformed SPARQL results: "results" is not an object');
30925
31327
  }
30926
31328
  const bindings = results["bindings"];
@@ -30952,7 +31354,7 @@ function SparqlEntailmentRegimeFromApiToFront(entailment) {
30952
31354
  }
30953
31355
  }
30954
31356
  function SparqlQueryResultsFromApiToFront(raw) {
30955
- if (!isRecord(raw)) {
31357
+ if (!isRecord2(raw)) {
30956
31358
  throw new Error(
30957
31359
  "Malformed SPARQL results: the response body is not a SPARQL 1.1 Query Results JSON document (a CONSTRUCT or DESCRIBE query answers with an RDF graph document instead)"
30958
31360
  );
@@ -30979,7 +31381,7 @@ function GraphSparqlQueryRequestFromFrontToApi(model) {
30979
31381
  };
30980
31382
  }
30981
31383
  function GraphSparqlResultsFromApiToFront(raw) {
30982
- if (!isRecord(raw)) {
31384
+ if (!isRecord2(raw)) {
30983
31385
  throw new Error(
30984
31386
  "Malformed SPARQL results: the co-located store response is not a SPARQL 1.1 Query Results JSON document"
30985
31387
  );
@@ -31267,6 +31669,38 @@ var SparqlClient = class {
31267
31669
  };
31268
31670
 
31269
31671
  // src/normalizers/osf-diff.ts
31672
+ function TermSetSelectorFromFrontToApi(selector) {
31673
+ switch (selector.type) {
31674
+ case "document":
31675
+ return { type: "document", document_id: selector.documentId };
31676
+ case "document_version":
31677
+ return { type: "document_version", document_id: selector.documentId };
31678
+ case "collection":
31679
+ return { type: "collection", path: selector.path };
31680
+ case "term_ids":
31681
+ return { type: "term_ids", ids: selector.ids };
31682
+ case "sort":
31683
+ return {
31684
+ type: "sort",
31685
+ sort_name: selector.sortName,
31686
+ include_descendants: selector.includeDescendants
31687
+ };
31688
+ case "query":
31689
+ return { type: "query", osfql: selector.osfql };
31690
+ case "snapshot":
31691
+ return {
31692
+ type: "snapshot",
31693
+ snapshot_id: selector.snapshotId,
31694
+ filter: selector.filter === void 0 ? void 0 : TermSetSelectorFromFrontToApi(selector.filter)
31695
+ };
31696
+ case "as_of":
31697
+ return {
31698
+ type: "as_of",
31699
+ at: selector.at,
31700
+ filter: selector.filter === void 0 ? void 0 : TermSetSelectorFromFrontToApi(selector.filter)
31701
+ };
31702
+ }
31703
+ }
31270
31704
  function TemporalPointFromFrontToApi(model) {
31271
31705
  return {
31272
31706
  at: model.at,
@@ -31275,8 +31709,8 @@ function TemporalPointFromFrontToApi(model) {
31275
31709
  }
31276
31710
  function OsfDiffRequestFromFrontToApi(model) {
31277
31711
  return {
31278
- a: model.a,
31279
- b: model.b,
31712
+ a: TermSetSelectorFromFrontToApi(model.a),
31713
+ b: TermSetSelectorFromFrontToApi(model.b),
31280
31714
  include_clause_diff: model.includeClauseDiff,
31281
31715
  include_entity_diff: model.includeEntityDiff,
31282
31716
  threshold: model.threshold
@@ -31290,7 +31724,7 @@ function OsfDiffResponseFromApiToFront(dto) {
31290
31724
  function OsfDiffSequenceRequestFromFrontToApi(model) {
31291
31725
  return {
31292
31726
  document_family_id: model.documentFamilyId,
31293
- selectors: model.selectors,
31727
+ selectors: model.selectors?.map(TermSetSelectorFromFrontToApi),
31294
31728
  threshold: model.threshold
31295
31729
  };
31296
31730
  }
@@ -31301,7 +31735,7 @@ function OsfDiffSequenceResponseFromApiToFront(dto) {
31301
31735
  }
31302
31736
  function OsfDiffTemporalRequestFromFrontToApi(model) {
31303
31737
  return {
31304
- filter: model.filter,
31738
+ filter: model.filter === void 0 ? void 0 : TermSetSelectorFromFrontToApi(model.filter),
31305
31739
  from: TemporalPointFromFrontToApi(model.from),
31306
31740
  to: TemporalPointFromFrontToApi(model.to),
31307
31741
  threshold: model.threshold
@@ -31336,13 +31770,14 @@ var OsfDiffClient = class {
31336
31770
  * Entities are matched by OSF unification; `threshold` (default 0.7) is the
31337
31771
  * minimum match degree at which two entities are considered the same. Set
31338
31772
  * `includeClauseDiff` / `includeEntityDiff` to control which deltas the report
31339
- * carries. Selectors and the report are opaque wire-format JSON objects.
31773
+ * carries. Each side is a typed {@link OsfDiffSelector}; the report is an opaque
31774
+ * wire-format JSON object.
31340
31775
  *
31341
31776
  * @example
31342
31777
  * ```typescript
31343
31778
  * const result = await client.osfDiff.diff({
31344
- * a: { type: 'document', document_id: 'a1b2c3d4-...' },
31345
- * b: { type: 'document', document_id: 'e5f6a7b8-...' },
31779
+ * a: { type: 'document', documentId: 'a1b2c3d4-...' },
31780
+ * b: { type: 'document', documentId: 'e5f6a7b8-...' },
31346
31781
  * includeClauseDiff: true,
31347
31782
  * threshold: 0.8,
31348
31783
  * });
@@ -31402,7 +31837,7 @@ var OsfDiffClient = class {
31402
31837
  * const result = await client.osfDiff.diffTemporal({
31403
31838
  * from: { at: '2026-01-01T00:00:00Z' },
31404
31839
  * to: {}, // live
31405
- * filter: { type: 'document', document_id: 'a1b2c3d4-...' },
31840
+ * filter: { type: 'document', documentId: 'a1b2c3d4-...' },
31406
31841
  * });
31407
31842
  * console.log(result.report);
31408
31843
  * ```
@@ -31775,13 +32210,22 @@ function SatSolverStatsDtoFromApiToFront(dto) {
31775
32210
  }
31776
32211
  function modelFromApiToFront(raw) {
31777
32212
  if (!Array.isArray(raw)) {
31778
- return [];
32213
+ throw new ValidationError(
32214
+ "SAT solver returned a 'satisfiable' verdict without a model; the endpoint contract requires one. Refusing to report an assignment the solver did not give.",
32215
+ "model"
32216
+ );
31779
32217
  }
32218
+ const entries = raw;
31780
32219
  const model = [];
31781
- for (const entry of raw) {
31782
- if (typeof entry === "boolean") {
31783
- model.push(entry);
32220
+ for (let index = 0; index < entries.length; index += 1) {
32221
+ const entry = entries[index];
32222
+ if (typeof entry !== "boolean") {
32223
+ throw new ValidationError(
32224
+ `SAT model entry at index ${index} is ${typeof entry}, not a Boolean. The assignment vector is positional, so this entry cannot be dropped without corrupting every later variable.`,
32225
+ "model"
32226
+ );
31784
32227
  }
32228
+ model.push(entry);
31785
32229
  }
31786
32230
  return model;
31787
32231
  }
@@ -31832,12 +32276,19 @@ var SatClient = class {
31832
32276
  * Solver statistics are attached to every branch.
31833
32277
  * @throws {ApiError} If the request fails (e.g. a literal references a variable
31834
32278
  * index `>= numVars`, or a clause is empty).
32279
+ * @throws {ValidationError} If a `satisfiable` verdict arrives without a
32280
+ * well-formed Boolean model, which violates the endpoint contract.
31835
32281
  *
31836
32282
  * @remarks
31837
32283
  * Narrow on `result` to reach the model — it exists only on the `satisfiable`
31838
32284
  * branch. `maxConflicts: 0` (the default) means an unlimited budget, in which
31839
32285
  * case `unknown` cannot be returned.
31840
32286
  *
32287
+ * The model is index-aligned with the variables (`model[i]` is the value of
32288
+ * variable `i`). A `satisfiable` response whose model is missing or holds a
32289
+ * non-Boolean is reported as a {@link ValidationError} rather than silently
32290
+ * shortened — dropping an entry would shift every later variable's assignment.
32291
+ *
31841
32292
  * Plain JSON serialization: literals are `{ var, negated }` objects and the
31842
32293
  * model is a `boolean[]` indexed by variable number. No tagged `ValueDto` or
31843
32294
  * untagged `FeatureValueDto` encoding is used.
@@ -31889,12 +32340,12 @@ function EqLiteralDtoFromFrontToApi(model) {
31889
32340
  negated: model.negated
31890
32341
  };
31891
32342
  }
31892
- function isRecord2(value) {
32343
+ function isRecord3(value) {
31893
32344
  return typeof value === "object" && value !== null;
31894
32345
  }
31895
32346
  function assignmentsFromApiToFront(raw) {
31896
32347
  const assignments = {};
31897
- if (!isRecord2(raw)) {
32348
+ if (!isRecord3(raw)) {
31898
32349
  return assignments;
31899
32350
  }
31900
32351
  for (const [key, value] of Object.entries(raw)) {
@@ -32096,7 +32547,9 @@ var ChaseClient = class {
32096
32547
  * ```
32097
32548
  */
32098
32549
  async run(request) {
32099
- const response = await this.api.runChase(ChaseRunRequestFromFrontToApi(request));
32550
+ const response = await this.api.runChase(ChaseRunRequestFromFrontToApi(request), {
32551
+ headers: { [RAW_BODY_HEADER]: "1" }
32552
+ });
32100
32553
  return ChaseRunResponseFromApiToFront(response.data);
32101
32554
  }
32102
32555
  };
@@ -32226,7 +32679,7 @@ var ConformanceClient = class {
32226
32679
  };
32227
32680
 
32228
32681
  // src/normalizers/temporal.ts
32229
- function isRecord3(value) {
32682
+ function isRecord4(value) {
32230
32683
  return typeof value === "object" && value !== null && !Array.isArray(value);
32231
32684
  }
32232
32685
  function asNumber(value) {
@@ -32286,38 +32739,6 @@ function TemporalModelCheckResponseFromApiToFront(dto) {
32286
32739
  counterexample
32287
32740
  };
32288
32741
  }
32289
- function TermSetSelectorFromFrontToApi(selector) {
32290
- switch (selector.type) {
32291
- case "document":
32292
- return { type: "document", document_id: selector.documentId };
32293
- case "document_version":
32294
- return { type: "document_version", document_id: selector.documentId };
32295
- case "collection":
32296
- return { type: "collection", path: selector.path };
32297
- case "term_ids":
32298
- return { type: "term_ids", ids: selector.ids };
32299
- case "sort":
32300
- return {
32301
- type: "sort",
32302
- sort_name: selector.sortName,
32303
- include_descendants: selector.includeDescendants
32304
- };
32305
- case "query":
32306
- return { type: "query", osfql: selector.osfql };
32307
- case "snapshot":
32308
- return {
32309
- type: "snapshot",
32310
- snapshot_id: selector.snapshotId,
32311
- filter: selector.filter === void 0 ? void 0 : TermSetSelectorFromFrontToApi(selector.filter)
32312
- };
32313
- case "as_of":
32314
- return {
32315
- type: "as_of",
32316
- at: selector.at,
32317
- filter: selector.filter === void 0 ? void 0 : TermSetSelectorFromFrontToApi(selector.filter)
32318
- };
32319
- }
32320
- }
32321
32742
  function TemporalSeriesSpecFromFrontToApi(spec) {
32322
32743
  const time = spec.time.kind === "date_time_feature" ? { kind: "date_time_feature", name: spec.time.name } : { kind: "epoch_feature", name: spec.time.name, unit: spec.time.unit };
32323
32744
  const value = spec.value.kind === "feature" ? { kind: "feature", name: spec.value.name } : { kind: "count" };
@@ -32354,7 +32775,7 @@ function TemporalSeriesRequestFromFrontToApi(model) {
32354
32775
  };
32355
32776
  }
32356
32777
  function TemporalSeriesPointFromApiToFront(value) {
32357
- if (!isRecord3(value)) {
32778
+ if (!isRecord4(value)) {
32358
32779
  return void 0;
32359
32780
  }
32360
32781
  const bucketStart = asNumber(value["bucket_start"]);
@@ -32372,7 +32793,7 @@ function TemporalSeriesPointFromApiToFront(value) {
32372
32793
  };
32373
32794
  }
32374
32795
  function TemporalTrendSummaryFromApiToFront(value) {
32375
- if (!isRecord3(value)) {
32796
+ if (!isRecord4(value)) {
32376
32797
  return void 0;
32377
32798
  }
32378
32799
  const slopePerMs = asNumber(value["slope_per_ms"]);
@@ -32387,7 +32808,7 @@ function TemporalTrendSummaryFromApiToFront(value) {
32387
32808
  return { slopePerMs, intercept, first, last, delta, n };
32388
32809
  }
32389
32810
  function TemporalSeriesFromApiToFront(value) {
32390
- if (!isRecord3(value)) {
32811
+ if (!isRecord4(value)) {
32391
32812
  return void 0;
32392
32813
  }
32393
32814
  const rawPoints = value["points"];
@@ -32534,7 +32955,7 @@ var TemporalClient = class {
32534
32955
  };
32535
32956
 
32536
32957
  // src/normalizers/forecast.ts
32537
- function isRecord4(value) {
32958
+ function isRecord5(value) {
32538
32959
  return typeof value === "object" && value !== null && !Array.isArray(value);
32539
32960
  }
32540
32961
  function asNumber2(value) {
@@ -32587,7 +33008,7 @@ function ForecastRequestFromFrontToApi(model) {
32587
33008
  };
32588
33009
  }
32589
33010
  function CompetitorForecastFromApiToFront(value) {
32590
- if (!isRecord4(value)) {
33011
+ if (!isRecord5(value)) {
32591
33012
  return void 0;
32592
33013
  }
32593
33014
  const id = asString(value["id"]);
@@ -32599,7 +33020,7 @@ function CompetitorForecastFromApiToFront(value) {
32599
33020
  return { id, pWin, pTopK };
32600
33021
  }
32601
33022
  function OrderedComboFromApiToFront(value) {
32602
- if (!isRecord4(value)) {
33023
+ if (!isRecord5(value)) {
32603
33024
  return void 0;
32604
33025
  }
32605
33026
  const members = asStringArray(value["members"]);
@@ -32610,7 +33031,7 @@ function OrderedComboFromApiToFront(value) {
32610
33031
  return { members, probability };
32611
33032
  }
32612
33033
  function ForecastCoveringSetFromApiToFront(value) {
32613
- if (!isRecord4(value)) {
33034
+ if (!isRecord5(value)) {
32614
33035
  return void 0;
32615
33036
  }
32616
33037
  const members = asStringArray(value["members"]);
@@ -32623,7 +33044,7 @@ function ForecastCoveringSetFromApiToFront(value) {
32623
33044
  return { members, alpha, slice, sliceFallback };
32624
33045
  }
32625
33046
  function RankedInstrumentFromApiToFront(value) {
32626
- if (!isRecord4(value)) {
33047
+ if (!isRecord5(value)) {
32627
33048
  return void 0;
32628
33049
  }
32629
33050
  const id = asString(value["id"]);
@@ -32643,7 +33064,7 @@ function RankedInstrumentFromApiToFront(value) {
32643
33064
  return { id, score, rank, interval };
32644
33065
  }
32645
33066
  function ForecastBodyFromApiToFront(value) {
32646
- if (!isRecord4(value)) {
33067
+ if (!isRecord5(value)) {
32647
33068
  return void 0;
32648
33069
  }
32649
33070
  const shape = value["shape"];
@@ -32697,7 +33118,7 @@ function ForecastBodyFromApiToFront(value) {
32697
33118
  return void 0;
32698
33119
  }
32699
33120
  function ForecastCertificateFromApiToFront(value) {
32700
- if (!isRecord4(value)) {
33121
+ if (!isRecord5(value)) {
32701
33122
  return void 0;
32702
33123
  }
32703
33124
  const modelFingerprint = asString(value["model_fingerprint"]);
@@ -32716,7 +33137,7 @@ function ForecastCertificateFromApiToFront(value) {
32716
33137
  };
32717
33138
  }
32718
33139
  function CertifiedForecastFromApiToFront(value) {
32719
- if (!isRecord4(value)) {
33140
+ if (!isRecord5(value)) {
32720
33141
  return void 0;
32721
33142
  }
32722
33143
  const outcome = value["outcome"];
@@ -32993,7 +33414,9 @@ var DlClient = class {
32993
33414
  * ```
32994
33415
  */
32995
33416
  async satisfiable(request) {
32996
- const response = await this.api.satisfiable(DlSatisfiableRequestFromFrontToApi(request));
33417
+ const response = await this.api.satisfiable(DlSatisfiableRequestFromFrontToApi(request), {
33418
+ headers: { [RAW_BODY_HEADER]: "1" }
33419
+ });
32997
33420
  return DlSatisfiableResponseFromApiToFront(response.data);
32998
33421
  }
32999
33422
  /**
@@ -33029,7 +33452,9 @@ var DlClient = class {
33029
33452
  * ```
33030
33453
  */
33031
33454
  async subsumes(request) {
33032
- const response = await this.api.subsumes(DlSubsumesRequestFromFrontToApi(request));
33455
+ const response = await this.api.subsumes(DlSubsumesRequestFromFrontToApi(request), {
33456
+ headers: { [RAW_BODY_HEADER]: "1" }
33457
+ });
33033
33458
  return DlSubsumesResponseFromApiToFront(response.data);
33034
33459
  }
33035
33460
  };
@@ -33786,21 +34211,50 @@ var OntologyExportClient = class {
33786
34211
  constructor(api) {
33787
34212
  this.api = api;
33788
34213
  }
34214
+ /**
34215
+ * Issue a content-negotiated export request and project the response.
34216
+ *
34217
+ * @internal
34218
+ * @remarks
34219
+ * Goes through the transport directly rather than through the generated route
34220
+ * methods: `root` is repeatable server-side (`?root=a&root=b`), but utoipa
34221
+ * cannot express a repeated query parameter, so the generated routes type it as
34222
+ * a lone `root?: string` — narrower than the endpoint each route's own
34223
+ * "(repeatable)" doc comment describes. The transport's query serializer
34224
+ * already branches on `Array.isArray` and emits the repeats correctly.
34225
+ */
34226
+ async requestExport(path, options) {
34227
+ const response = await this.api.http.request({
34228
+ path,
34229
+ method: "GET",
34230
+ query: OntologyExportQueryFromFrontToApi(options),
34231
+ secure: true,
34232
+ headers: { Accept: OntologyExportAcceptFromFrontToApi(options?.format) }
34233
+ });
34234
+ const document = await response.text();
34235
+ return OntologyExportDocumentFromApiToFront(
34236
+ response.headers.get("content-type"),
34237
+ document
34238
+ );
34239
+ }
33789
34240
  /**
33790
34241
  * Export the tenant's sort lattice (or a sub-lattice) as an OWL ontology.
33791
34242
  *
33792
34243
  * @param options - Export options: the base IRI for synthesized IRIs, the root
33793
- * sort to restrict the export to, and the serialization to negotiate on.
34244
+ * sort (or sorts) to restrict the export to, and the serialization to
34245
+ * negotiate on.
33794
34246
  * @returns The exported document, verbatim, with the media type the server
33795
34247
  * answered with.
33796
34248
  * @throws {BadRequestError} If the base IRI is invalid or the query is malformed.
33797
- * @throws {NotFoundError} If the requested root sort does not exist.
34249
+ * @throws {NotFoundError} If a requested root sort does not exist.
33798
34250
  * @throws {ApiError} If the request otherwise fails.
33799
34251
  *
33800
34252
  * @remarks
33801
34253
  * Omit `root` to export the whole tenant schema. Omit `base` to let the backend
33802
34254
  * synthesize IRIs under `urn:osfkb:tenant:{tenant_id}`.
33803
34255
  *
34256
+ * `root` is repeatable: pass an array to export several sub-lattices at once.
34257
+ *
33804
34258
  * `format` selects the `Accept` header: an RDF serialization yields an RDF
33805
34259
  * document, and the default (`'json'`) yields the backend's JSON rendering as
33806
34260
  * JSON text — parse it with `JSON.parse` when you need the object.
@@ -33813,36 +34267,35 @@ var OntologyExportClient = class {
33813
34267
  * format: 'turtle',
33814
34268
  * });
33815
34269
  *
33816
- * console.log(owl.contentType); // 'text/turtle'
34270
+ * console.log(owl.contentType); // 'text/turtle; charset=utf-8'
33817
34271
  * console.log(owl.document); // '@prefix : <https://example.org/ontology#> ...'
34272
+ *
34273
+ * // Several sub-lattices in one export -> ?root=clinical_entity&root=administrative_entity
34274
+ * const both = await client.ontologyExport.exportOwl({
34275
+ * root: ['clinical_entity', 'administrative_entity'],
34276
+ * });
33818
34277
  * ```
33819
34278
  */
33820
34279
  async exportOwl(options) {
33821
- const response = await this.api.exportOntologyOwl(
33822
- OntologyExportQueryFromFrontToApi(options),
33823
- { headers: { Accept: OntologyExportAcceptFromFrontToApi(options?.format) } }
33824
- );
33825
- const document = await response.text();
33826
- return OntologyExportDocumentFromApiToFront(
33827
- response.headers.get("content-type"),
33828
- document
33829
- );
34280
+ return this.requestExport("/api/v1/ontology/export/owl", options);
33830
34281
  }
33831
34282
  /**
33832
34283
  * Export the tenant's schema constraints (or those of a sub-lattice) as SHACL
33833
34284
  * shapes.
33834
34285
  *
33835
34286
  * @param options - Export options: the base IRI for synthesized IRIs, the root
33836
- * sort to restrict the export to, and the serialization to negotiate on.
34287
+ * sort (or sorts) to restrict the export to, and the serialization to
34288
+ * negotiate on.
33837
34289
  * @returns The exported document, verbatim, with the media type the server
33838
34290
  * answered with.
33839
34291
  * @throws {BadRequestError} If the base IRI is invalid or the query is malformed.
33840
- * @throws {NotFoundError} If the requested root sort does not exist.
34292
+ * @throws {NotFoundError} If a requested root sort does not exist.
33841
34293
  * @throws {ApiError} If the request otherwise fails.
33842
34294
  *
33843
34295
  * @remarks
33844
34296
  * Each exported shape targets one sort and constrains its features. Omit `root`
33845
- * to export the whole tenant schema.
34297
+ * to export the whole tenant schema; pass an array to export the shapes of
34298
+ * several sub-lattices at once.
33846
34299
  *
33847
34300
  * `format` selects the `Accept` header: an RDF serialization yields an RDF
33848
34301
  * document, and the default (`'json'`) yields the backend's JSON rendering of
@@ -33852,20 +34305,12 @@ var OntologyExportClient = class {
33852
34305
  * ```typescript
33853
34306
  * const shacl = await client.ontologyExport.exportShacl({ format: 'turtle' });
33854
34307
  *
33855
- * console.log(shacl.contentType); // 'text/turtle'
34308
+ * console.log(shacl.contentType); // 'text/turtle; charset=utf-8'
33856
34309
  * console.log(shacl.document); // '... sh:NodeShape ...'
33857
34310
  * ```
33858
34311
  */
33859
34312
  async exportShacl(options) {
33860
- const response = await this.api.exportOntologyShacl(
33861
- OntologyExportQueryFromFrontToApi(options),
33862
- { headers: { Accept: OntologyExportAcceptFromFrontToApi(options?.format) } }
33863
- );
33864
- const document = await response.text();
33865
- return OntologyExportDocumentFromApiToFront(
33866
- response.headers.get("content-type"),
33867
- document
33868
- );
34313
+ return this.requestExport("/api/v1/ontology/export/shacl", options);
33869
34314
  }
33870
34315
  };
33871
34316