@duckcodeailabs/dql-agent 1.14.2 → 1.14.3-rc.1

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.
Files changed (145) hide show
  1. package/dist/agent-run-engine.d.ts +63 -2
  2. package/dist/agent-run-engine.d.ts.map +1 -1
  3. package/dist/agent-run-engine.js +864 -29
  4. package/dist/agent-run-engine.js.map +1 -1
  5. package/dist/agent-run-planner.d.ts +6 -0
  6. package/dist/agent-run-planner.d.ts.map +1 -1
  7. package/dist/agent-run-planner.js +2 -0
  8. package/dist/agent-run-planner.js.map +1 -1
  9. package/dist/agent-run-store.d.ts.map +1 -1
  10. package/dist/agent-run-store.js +48 -3
  11. package/dist/agent-run-store.js.map +1 -1
  12. package/dist/agentic/analyst-loop.d.ts +7 -1
  13. package/dist/agentic/analyst-loop.d.ts.map +1 -1
  14. package/dist/agentic/analyst-loop.js +163 -0
  15. package/dist/agentic/analyst-loop.js.map +1 -1
  16. package/dist/agentic/assumptions.d.ts +1 -1
  17. package/dist/agentic/assumptions.d.ts.map +1 -1
  18. package/dist/agentic/assumptions.js.map +1 -1
  19. package/dist/agentic/research-agent.d.ts.map +1 -1
  20. package/dist/agentic/research-agent.js +10 -1
  21. package/dist/agentic/research-agent.js.map +1 -1
  22. package/dist/agentic/sql-authorization.d.ts +8 -0
  23. package/dist/agentic/sql-authorization.d.ts.map +1 -1
  24. package/dist/agentic/sql-authorization.js +3 -0
  25. package/dist/agentic/sql-authorization.js.map +1 -1
  26. package/dist/analytical-compatibility.d.ts.map +1 -1
  27. package/dist/analytical-compatibility.js +8 -1
  28. package/dist/analytical-compatibility.js.map +1 -1
  29. package/dist/analytical-failure-repair.d.ts.map +1 -1
  30. package/dist/analytical-failure-repair.js +6 -2
  31. package/dist/analytical-failure-repair.js.map +1 -1
  32. package/dist/analytical-frame.d.ts +23 -1
  33. package/dist/analytical-frame.d.ts.map +1 -1
  34. package/dist/analytical-frame.js +322 -16
  35. package/dist/analytical-frame.js.map +1 -1
  36. package/dist/analytical-orchestration.d.ts +314 -3
  37. package/dist/analytical-orchestration.d.ts.map +1 -1
  38. package/dist/analytical-orchestration.js +486 -43
  39. package/dist/analytical-orchestration.js.map +1 -1
  40. package/dist/answer-loop.d.ts +64 -8
  41. package/dist/answer-loop.d.ts.map +1 -1
  42. package/dist/answer-loop.js +528 -67
  43. package/dist/answer-loop.js.map +1 -1
  44. package/dist/ask-observability/index.d.ts +11 -0
  45. package/dist/ask-observability/index.d.ts.map +1 -0
  46. package/dist/ask-observability/index.js +7 -0
  47. package/dist/ask-observability/index.js.map +1 -0
  48. package/dist/ask-observability/instrumentation.d.ts +35 -0
  49. package/dist/ask-observability/instrumentation.d.ts.map +1 -0
  50. package/dist/ask-observability/instrumentation.js +472 -0
  51. package/dist/ask-observability/instrumentation.js.map +1 -0
  52. package/dist/ask-observability/observer.d.ts +62 -0
  53. package/dist/ask-observability/observer.d.ts.map +1 -0
  54. package/dist/ask-observability/observer.js +537 -0
  55. package/dist/ask-observability/observer.js.map +1 -0
  56. package/dist/ask-observability/portable.d.ts +98 -0
  57. package/dist/ask-observability/portable.d.ts.map +1 -0
  58. package/dist/ask-observability/portable.js +527 -0
  59. package/dist/ask-observability/portable.js.map +1 -0
  60. package/dist/ask-observability/store.d.ts +130 -0
  61. package/dist/ask-observability/store.d.ts.map +1 -0
  62. package/dist/ask-observability/store.js +1114 -0
  63. package/dist/ask-observability/store.js.map +1 -0
  64. package/dist/ask-observability/types.d.ts +357 -0
  65. package/dist/ask-observability/types.d.ts.map +1 -0
  66. package/dist/ask-observability/types.js +2 -0
  67. package/dist/ask-observability/types.js.map +1 -0
  68. package/dist/ask-observability/utils.d.ts +21 -0
  69. package/dist/ask-observability/utils.d.ts.map +1 -0
  70. package/dist/ask-observability/utils.js +102 -0
  71. package/dist/ask-observability/utils.js.map +1 -0
  72. package/dist/generated-analytical-proposal.d.ts +37 -1
  73. package/dist/generated-analytical-proposal.d.ts.map +1 -1
  74. package/dist/generated-analytical-proposal.js +211 -3
  75. package/dist/generated-analytical-proposal.js.map +1 -1
  76. package/dist/governed-relational-compiler.d.ts +15 -0
  77. package/dist/governed-relational-compiler.d.ts.map +1 -1
  78. package/dist/governed-relational-compiler.js +99 -1
  79. package/dist/governed-relational-compiler.js.map +1 -1
  80. package/dist/index.d.ts +9 -7
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +6 -4
  83. package/dist/index.js.map +1 -1
  84. package/dist/intent-controller.d.ts +10 -0
  85. package/dist/intent-controller.d.ts.map +1 -1
  86. package/dist/intent-controller.js +1 -1
  87. package/dist/intent-controller.js.map +1 -1
  88. package/dist/meaning-resolution.d.ts +78 -6
  89. package/dist/meaning-resolution.d.ts.map +1 -1
  90. package/dist/meaning-resolution.js +331 -38
  91. package/dist/meaning-resolution.js.map +1 -1
  92. package/dist/metadata/analysis-planner.d.ts.map +1 -1
  93. package/dist/metadata/analysis-planner.js +21 -1
  94. package/dist/metadata/analysis-planner.js.map +1 -1
  95. package/dist/metadata/catalog.d.ts.map +1 -1
  96. package/dist/metadata/catalog.js +1 -1
  97. package/dist/metadata/catalog.js.map +1 -1
  98. package/dist/metadata/meaning-evidence.d.ts +9 -2
  99. package/dist/metadata/meaning-evidence.d.ts.map +1 -1
  100. package/dist/metadata/meaning-evidence.js +261 -11
  101. package/dist/metadata/meaning-evidence.js.map +1 -1
  102. package/dist/plan-execution-adapter.d.ts +9 -1
  103. package/dist/plan-execution-adapter.d.ts.map +1 -1
  104. package/dist/plan-execution-adapter.js +93 -13
  105. package/dist/plan-execution-adapter.js.map +1 -1
  106. package/dist/provider-egress.d.ts +24 -10
  107. package/dist/provider-egress.d.ts.map +1 -1
  108. package/dist/provider-egress.js +22 -17
  109. package/dist/provider-egress.js.map +1 -1
  110. package/dist/providers/claude.d.ts.map +1 -1
  111. package/dist/providers/claude.js +10 -9
  112. package/dist/providers/claude.js.map +1 -1
  113. package/dist/providers/dispatch.d.ts +27 -1
  114. package/dist/providers/dispatch.d.ts.map +1 -1
  115. package/dist/providers/dispatch.js +63 -1
  116. package/dist/providers/dispatch.js.map +1 -1
  117. package/dist/providers/gemini.js +10 -10
  118. package/dist/providers/gemini.js.map +1 -1
  119. package/dist/providers/index.d.ts +2 -2
  120. package/dist/providers/index.d.ts.map +1 -1
  121. package/dist/providers/index.js +1 -1
  122. package/dist/providers/index.js.map +1 -1
  123. package/dist/providers/ollama.js +15 -15
  124. package/dist/providers/ollama.js.map +1 -1
  125. package/dist/providers/openai.js +22 -22
  126. package/dist/providers/openai.js.map +1 -1
  127. package/dist/providers/types.d.ts +52 -0
  128. package/dist/providers/types.d.ts.map +1 -1
  129. package/dist/providers/types.js.map +1 -1
  130. package/dist/relationship-proof.d.ts +81 -0
  131. package/dist/relationship-proof.d.ts.map +1 -1
  132. package/dist/relationship-proof.js +228 -4
  133. package/dist/relationship-proof.js.map +1 -1
  134. package/dist/resolved-analytical-plan.d.ts +18 -4
  135. package/dist/resolved-analytical-plan.d.ts.map +1 -1
  136. package/dist/resolved-analytical-plan.js +764 -47
  137. package/dist/resolved-analytical-plan.js.map +1 -1
  138. package/dist/router.d.ts +10 -1
  139. package/dist/router.d.ts.map +1 -1
  140. package/dist/router.js +1785 -213
  141. package/dist/router.js.map +1 -1
  142. package/dist/semantic-bridge/compose.d.ts.map +1 -1
  143. package/dist/semantic-bridge/compose.js +23 -4
  144. package/dist/semantic-bridge/compose.js.map +1 -1
  145. package/package.json +4 -4
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { AnalyticalPolicyContract, AnalyticalQuestionFrameV2, MetricCapabilityContract } from '@duckcodeailabs/dql-core';
9
9
  import type { KnowledgeLens } from './domain-context.js';
10
- import { type ContextSourceCoverageV1 } from './analytical-orchestration.js';
10
+ import { type AnalyticalRequirementSetV1, type AnalyticalRequirementSeedV1, type ContextSourceCoverageV1, type SameSnapshotRoleExtensionV1 } from './analytical-orchestration.js';
11
11
  export type AgentEvidenceKind = "certified_block" | "semantic_metric" | "semantic_member" | "dql_modeling" | "dbt_model" | "dbt_source" | "sql_table" | "sql_column";
12
12
  export type AgentEvidenceTrustTier = "certified" | "semantic" | "governed_sql" | "exploratory";
13
13
  export type AgentEvidenceCompatibility = "compatible" | "partial" | "incompatible" | "unknown";
@@ -78,6 +78,12 @@ export interface AgentEvidenceCandidate {
78
78
  matchReasons: string[];
79
79
  compatibility: AgentEvidenceCompatibility;
80
80
  compatibilityFacts?: string[];
81
+ /**
82
+ * Host-authored role admission from one immutable semantic capability
83
+ * snapshot. A resolver may select this supplied card, but cannot mint or
84
+ * alter it; the selected metric capability remains the execution authority.
85
+ */
86
+ sameSnapshotRoleExtension?: SameSnapshotRoleExtensionV1;
81
87
  /** Normalized executable capability. Names alone never supply missing facts. */
82
88
  analyticalCapability?: MetricCapabilityContract;
83
89
  /** Deterministic certified-asset fit; ignored for non-certified evidence. */
@@ -86,15 +92,36 @@ export interface AgentEvidenceCandidate {
86
92
  eligible?: boolean;
87
93
  /** True only for an exact qualified/name/approved-alias match. */
88
94
  exactMatch?: boolean;
95
+ /**
96
+ * Real membership in the immutable retrieval snapshot. Multiple lanes are
97
+ * retained because fusion must not erase whether a card came from vector,
98
+ * graph, lexical, exact, or the conversation continuation boundary.
99
+ */
100
+ retrievalLanes?: Array<{
101
+ lane: 'exact' | 'lexical' | 'vector' | 'graph' | 'conversation';
102
+ rank?: number;
103
+ }>;
89
104
  }
90
105
  /**
91
106
  * Return the authored output identity that proves a certified block can answer
92
- * one requested measure. This reads only the block's own `output:` facts,
93
- * which are populated from declared/output-contract fields at indexing time.
94
- * Block names, tags, examples, definitions, and unrelated retrieved metrics
95
- * are intentionally absent: none of those is an executable output contract.
107
+ * one requested measure. This normally reads only the block's own `output:`
108
+ * facts, which are populated from declared/output-contract fields at indexing
109
+ * time. An exact block-title request may additionally carry a
110
+ * `catalog-proven-output:` fact from the snapshot-local catalog fit. That fact
111
+ * is minted only after the catalog has already bound this exact title to a
112
+ * high-confidence certified answer contract; names, tags, examples,
113
+ * definitions, and unrelated retrieved metrics are intentionally absent.
96
114
  */
97
115
  export declare function certifiedCandidateDeclaredMeasureOutput(candidate: AgentEvidenceCandidate, requested: string): string | undefined;
116
+ /**
117
+ * Return the block output that proves a requested display/grouping dimension.
118
+ * This is intentionally narrower than retrieval matching: only a declared
119
+ * output or the catalog-proven output bridge for an exact certified title may
120
+ * bind a dimension to the block executor. `customer_name` is a valid output
121
+ * for the business term `customer`; arbitrary attributes such as owner or
122
+ * sentiment are not.
123
+ */
124
+ export declare function certifiedCandidateDeclaredDimensionOutput(candidate: AgentEvidenceCandidate, requested: string): string | undefined;
98
125
  /**
99
126
  * A certified tier can freeze only when the selected block itself declares
100
127
  * every requested measure. This is deliberately stricter than retrieval
@@ -183,6 +210,32 @@ export interface MeaningResolution {
183
210
  message: string;
184
211
  candidateIds: string[];
185
212
  }>;
213
+ /** Immutable host tuple supplied before the one bounded meaning call. */
214
+ hostRequirementSeed?: AnalyticalRequirementSeedV1;
215
+ /**
216
+ * Canonical metric-capability dimensions restored from a validated,
217
+ * server-issued clarification selection. This is host continuation state,
218
+ * not a model-provided query-intent field; RAP revalidates each ID against
219
+ * the selected metric capability before it can enter the frozen plan.
220
+ */
221
+ structuredDimensionIds?: string[];
222
+ /** Content-safe record of model fields the host deliberately did not grant authority. */
223
+ overrideReceipts?: MeaningResolutionOverrideReceiptV1[];
224
+ /**
225
+ * Parse-only distinction for the bounded candidate-ID protocol. A provider
226
+ * may return a syntactically valid object with no selected IDs while omitting
227
+ * every clarification instruction. That is not itself a business
228
+ * clarification: the router may use a host-proven frozen plan, if one exists.
229
+ * An explicit provider clarification is intentionally never marked here.
230
+ */
231
+ emptyCandidateBinding?: true;
232
+ }
233
+ export interface MeaningResolutionOverrideReceiptV1 {
234
+ version: 1;
235
+ field: 'interpreted_question' | 'question_type' | 'query_intent' | 'recommended_route' | 'analytical_frame' | 'candidate_selection' | 'member_binding';
236
+ action: 'host_preserved' | 'selection_accepted';
237
+ reason: string;
238
+ candidateIds?: string[];
186
239
  }
187
240
  export interface MeaningResolutionInput {
188
241
  question: string;
@@ -192,6 +245,8 @@ export interface MeaningResolutionInput {
192
245
  }>;
193
246
  evidence: AgentRetrievalEvidence;
194
247
  candidates: AgentEvidenceCandidate[];
248
+ /** Host-owned typed request tuple; never model-authored. */
249
+ requirementSeed?: AnalyticalRequirementSeedV1;
195
250
  signal?: AbortSignal;
196
251
  }
197
252
  export type AgentMeaningResolver = (input: MeaningResolutionInput) => Promise<MeaningResolution>;
@@ -211,13 +266,30 @@ export declare function canonicalizeMetricMeasureCandidates(candidates: AgentEvi
211
266
  /** Match only explicit qualified references; ordinary names still use resolution. */
212
267
  export declare function findExplicitEvidenceReference(question: string, candidates: AgentEvidenceCandidate[]): AgentEvidenceCandidate | undefined;
213
268
  /** Validate that a resolver cannot invent or select ineligible evidence. */
214
- export declare function validateMeaningResolution(value: MeaningResolution, candidates: AgentEvidenceCandidate[], requestedMeasures?: string[]): {
269
+ export declare function validateMeaningResolution(value: MeaningResolution, candidates: AgentEvidenceCandidate[], requestedMeasures?: string[], options?: {
270
+ requirements?: AnalyticalRequirementSetV1;
271
+ }): {
215
272
  ok: true;
216
273
  resolution: MeaningResolution;
217
274
  } | {
218
275
  ok: false;
219
276
  reason: string;
220
277
  };
278
+ /**
279
+ * Merge the one model meaning response into the host-owned request seed.
280
+ *
281
+ * Candidate IDs are the only model-controlled execution-adjacent values, and
282
+ * they are still validated against the exact supplied package afterwards. The
283
+ * model's route, SQL-adjacent frame, query intent, and reworded question are
284
+ * presentation suggestions at most; accepting them as authority was how an
285
+ * omitted product category/order ID or an inherited prior filter silently
286
+ * changed the answer tuple after retrieval.
287
+ */
288
+ export declare function mergeMeaningResolutionWithRequirementSeed(input: {
289
+ seed: AnalyticalRequirementSeedV1;
290
+ resolution: MeaningResolution;
291
+ candidates: AgentEvidenceCandidate[];
292
+ }): MeaningResolution;
221
293
  export declare function routeForEvidenceCandidate(candidate: AgentEvidenceCandidate): MeaningExecutionRoute;
222
294
  export declare function questionTypeFromText(question: string): MeaningQuestionType;
223
295
  export declare function defaultQueryIntent(evidence: AgentRetrievalEvidence): MeaningQueryIntent;
@@ -1 +1 @@
1
- {"version":3,"file":"meaning-resolution.d.ts","sourceRoot":"","sources":["../src/meaning-resolution.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"meaning-resolution.d.ts","sourceRoot":"","sources":["../src/meaning-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAOL,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,2BAA2B,EACjC,MAAM,+BAA+B,CAAC;AAEvC,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,iBAAiB,GACjB,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,CAAC;AAEjB,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AAC/F,MAAM,MAAM,0BAA0B,GAAG,YAAY,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC;AAE/F;;;;;;;;GAQG;AACH,MAAM,WAAW,+BAA+B;IAC9C,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,iBAAiB,CAAC;IACxB,wFAAwF;IACxF,kBAAkB,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,CAAC;IAC7F,SAAS,EAAE,sBAAsB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mHAAmH;IACnH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,2EAA2E;IAC3E,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,+BAA+B,EAAE,CAAC;IACvD,wEAAwE;IACxE,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,0BAA0B,CAAC;IAC1C,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,2BAA2B,CAAC;IACxD,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,wBAAwB,CAAC;IAChD,6EAA6E;IAC7E,kBAAkB,CAAC,EAAE,OAAO,GAAG,eAAe,GAAG,WAAW,CAAC;IAC7D,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5G;AAED;;;;;;;;;GASG;AACH,wBAAgB,uCAAuC,CACrD,SAAS,EAAE,sBAAsB,EACjC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;;;GAOG;AACH,wBAAgB,yCAAyC,CACvD,SAAS,EAAE,sBAAsB,EACjC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAWpB;AAED;;;;;GAKG;AACH,wBAAgB,0CAA0C,CACxD,SAAS,EAAE,sBAAsB,EACjC,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,GACtC,OAAO,CAWT;AAyDD,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,UAAU,EAAE,sBAAsB,EAAE,CAAC;IACrC;;;OAGG;IACH,uBAAuB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3C;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAChD,kFAAkF;IAClF,cAAc,CAAC,EAAE;QACf,EAAE,EAAE,MAAM,CAAC;QACX,mBAAmB,EAAE,MAAM,CAAC;QAC5B,2EAA2E;QAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,aAAa,CAAC,EAAE,iBAAiB,EAAE,CAAC;QACpC,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,sEAAsE;QACtE,cAAc,CAAC,EAAE,uBAAuB,EAAE,CAAC;KAC5C,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,mBAAmB,GAC3B,YAAY,GACZ,OAAO,GACP,SAAS,GACT,OAAO,GACP,YAAY,GACZ,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,MAAM,qBAAqB,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,GAAG,SAAS,CAAC;AAC1G,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,iBAAiB;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,mBAAmB,CAAC;IAClC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,kBAAkB,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,UAAU,EAAE,iBAAiB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,8EAA8E;IAC9E,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,mFAAmF;IACnF,oBAAoB,CAAC,EAAE,SAAS,GAAG,cAAc,GAAG,gBAAgB,CAAC;IACrE,mFAAmF;IACnF,qBAAqB,CAAC,EAAE,KAAK,CAAC;QAC5B,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC,CAAC;IACH,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,2BAA2B,CAAC;IAClD;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,kCAAkC,EAAE,CAAC;IACxD;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,kCAAkC;IACjD,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,sBAAsB,GAAG,eAAe,GAAG,cAAc,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,qBAAqB,GAAG,gBAAgB,CAAC;IACvJ,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,QAAQ,EAAE,sBAAsB,CAAC;IACjC,UAAU,EAAE,sBAAsB,EAAE,CAAC;IACrC,4DAA4D;IAC5D,eAAe,CAAC,EAAE,2BAA2B,CAAC;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,MAAM,oBAAoB,GAAG,CAAC,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAgBjG;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,sBAAsB,EAChC,aAAa,SAAK,EAClB,QAAQ,SAAK,GACZ,sBAAsB,EAAE,CAyD1B;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,UAAU,EAAE,sBAAsB,EAAE,GACnC,sBAAsB,EAAE,CAY1B;AAcD,qFAAqF;AACrF,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,sBAAsB,EAAE,GACnC,sBAAsB,GAAG,SAAS,CAcpC;AAMD,4EAA4E;AAC5E,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,iBAAiB,EACxB,UAAU,EAAE,sBAAsB,EAAE,EACpC,iBAAiB,GAAE,MAAM,EAA+B,EACxD,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,0BAA0B,CAAA;CAAO,GAC1D;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA0F7E;AAuFD;;;;;;;;;GASG;AACH,wBAAgB,yCAAyC,CAAC,KAAK,EAAE;IAC/D,IAAI,EAAE,2BAA2B,CAAC;IAClC,UAAU,EAAE,iBAAiB,CAAC;IAC9B,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACtC,GAAG,iBAAiB,CA+HpB;AAsID,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,sBAAsB,GAAG,qBAAqB,CAMlG;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CAe1E;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,kBAAkB,CAUvF"}
@@ -5,13 +5,16 @@
5
5
  * package and may reference only IDs contained in it. Execution remains owned by
6
6
  * the host after it validates the selected candidates and route.
7
7
  */
8
- import { buildAnalyticalRequirementSet, evidenceCandidateRoles, selectRoleBalancedMeaningCandidates, } from './analytical-orchestration.js';
8
+ import { buildAnalyticalRequirementSet, candidateConflictsWithExplicitRankingMeasure, evidenceCandidateRoles, hasEntityAttributeTerm, isEntityAttributeCandidate, selectRoleBalancedMeaningCandidates, } from './analytical-orchestration.js';
9
9
  /**
10
10
  * Return the authored output identity that proves a certified block can answer
11
- * one requested measure. This reads only the block's own `output:` facts,
12
- * which are populated from declared/output-contract fields at indexing time.
13
- * Block names, tags, examples, definitions, and unrelated retrieved metrics
14
- * are intentionally absent: none of those is an executable output contract.
11
+ * one requested measure. This normally reads only the block's own `output:`
12
+ * facts, which are populated from declared/output-contract fields at indexing
13
+ * time. An exact block-title request may additionally carry a
14
+ * `catalog-proven-output:` fact from the snapshot-local catalog fit. That fact
15
+ * is minted only after the catalog has already bound this exact title to a
16
+ * high-confidence certified answer contract; names, tags, examples,
17
+ * definitions, and unrelated retrieved metrics are intentionally absent.
15
18
  */
16
19
  export function certifiedCandidateDeclaredMeasureOutput(candidate, requested) {
17
20
  if (candidate.kind !== 'certified_block')
@@ -20,11 +23,31 @@ export function certifiedCandidateDeclaredMeasureOutput(candidate, requested) {
20
23
  if (!requestedIdentity)
21
24
  return undefined;
22
25
  const declared = (candidate.compatibilityFacts ?? [])
23
- .flatMap((fact) => /^output:\s*(.+)$/i.exec(fact)?.[1] ?? [])
26
+ .flatMap((fact) => /^(?:output|catalog-proven-output):\s*(.+)$/i.exec(fact)?.[1] ?? [])
24
27
  .map((output) => output.trim())
25
28
  .filter(Boolean);
26
29
  return declared.find((output) => canonicalCertifiedOutputMetricIdentity(output) === requestedIdentity);
27
30
  }
31
+ /**
32
+ * Return the block output that proves a requested display/grouping dimension.
33
+ * This is intentionally narrower than retrieval matching: only a declared
34
+ * output or the catalog-proven output bridge for an exact certified title may
35
+ * bind a dimension to the block executor. `customer_name` is a valid output
36
+ * for the business term `customer`; arbitrary attributes such as owner or
37
+ * sentiment are not.
38
+ */
39
+ export function certifiedCandidateDeclaredDimensionOutput(candidate, requested) {
40
+ if (candidate.kind !== 'certified_block')
41
+ return undefined;
42
+ const requestedIdentity = canonicalCertifiedOutputDimensionIdentity(requested);
43
+ if (!requestedIdentity)
44
+ return undefined;
45
+ const declared = (candidate.compatibilityFacts ?? [])
46
+ .flatMap((fact) => /^(?:output|catalog-proven-output):\s*(.+)$/i.exec(fact)?.[1] ?? [])
47
+ .map((output) => output.trim())
48
+ .filter(Boolean);
49
+ return declared.find((output) => canonicalCertifiedOutputDimensionIdentity(output) === requestedIdentity);
50
+ }
28
51
  /**
29
52
  * A certified tier can freeze only when the selected block itself declares
30
53
  * every requested measure. This is deliberately stricter than retrieval
@@ -85,6 +108,19 @@ function canonicalCertifiedOutputMetricIdentity(value) {
85
108
  tokens.pop();
86
109
  return tokens.join('_');
87
110
  }
111
+ function canonicalCertifiedOutputDimensionIdentity(value) {
112
+ const tokens = value
113
+ .toLowerCase()
114
+ .replace(/[_./:-]+/g, ' ')
115
+ .replace(/[^a-z0-9 ]+/g, ' ')
116
+ .split(/\s+/)
117
+ .map((token) => token.endsWith('s') && token.length > 3 ? token.slice(0, -1) : token)
118
+ .filter(Boolean);
119
+ const displaySuffixes = new Set(['display', 'id', 'key', 'label', 'name', 'title']);
120
+ while (tokens.length > 1 && displaySuffixes.has(tokens.at(-1)))
121
+ tokens.pop();
122
+ return tokens.join('_');
123
+ }
88
124
  const TRUST_ORDER = {
89
125
  certified: 4,
90
126
  semantic: 3,
@@ -112,6 +148,11 @@ export function buildMeaningEvidencePackage(evidence, maxCandidates = 16, questi
112
148
  // role-aware admission code ever saw them.
113
149
  const canonicalEligible = canonicalizeMetricMeasureCandidates(evidence.candidates)
114
150
  .filter((candidate) => candidate.eligible !== false)
151
+ // Preserve the retrieval result for lifecycle/diagnostics, but do not put
152
+ // a correlated non-requested metric in the bounded meaning package. An
153
+ // explicit ranking measure is a typed requirement, not a prompt hint the
154
+ // resolver may replace with a more highly scored BCM/run-rate card.
155
+ .filter((candidate) => !candidateConflictsWithExplicitRankingMeasure(candidate, requirements))
115
156
  .sort(compareCandidates);
116
157
  const rawPinned = selectRoleBalancedMeaningCandidates({
117
158
  candidates: canonicalEligible,
@@ -124,10 +165,10 @@ export function buildMeaningEvidencePackage(evidence, maxCandidates = 16, questi
124
165
  // categorical-dimension parser also saw the token "account". An explicit
125
166
  // attribute request remains eligible.
126
167
  const requestedEntityDisplay = requirements.entityDisplayTerms.length > 0;
127
- const explicitlyRequestsAttribute = /\b(?:owner|sentiment|email)\b/i.test(question);
168
+ const explicitlyRequestsAttribute = hasEntityAttributeTerm(question);
128
169
  const hasRawPinnedEntityLabel = rawPinned.some((candidate) => evidenceCandidateRoles(candidate).includes('entity_label'));
129
170
  const pinned = requestedEntityDisplay && hasRawPinnedEntityLabel && !explicitlyRequestsAttribute
130
- ? rawPinned.filter((candidate) => !/\b(?:owner|sentiment|email)\b/i.test(candidate.name))
171
+ ? rawPinned.filter((candidate) => !isEntityAttributeCandidate(candidate))
131
172
  : rawPinned;
132
173
  const kindCounts = new Map();
133
174
  const perKindQualified = canonicalEligible
@@ -152,7 +193,7 @@ export function buildMeaningEvidencePackage(evidence, maxCandidates = 16, questi
152
193
  // An account owner/e-mail/sentiment is an attribute, never a substitute
153
194
  // for the requested account/customer display entity. Do not let it consume
154
195
  // the remaining meaning cards after that display role was successfully pinned.
155
- return !hasPinnedEntityLabel || !/\b(?:owner|sentiment|email)\b/i.test(candidate.name);
196
+ return !hasPinnedEntityLabel || !isEntityAttributeCandidate(candidate);
156
197
  });
157
198
  return [...pinned, ...safeFill]
158
199
  .slice(0, limit);
@@ -208,69 +249,92 @@ function normalizeRef(value) {
208
249
  return value.trim().toLowerCase().replace(/[`"']/g, "");
209
250
  }
210
251
  /** Validate that a resolver cannot invent or select ineligible evidence. */
211
- export function validateMeaningResolution(value, candidates, requestedMeasures = value.queryIntent.measures) {
252
+ export function validateMeaningResolution(value, candidates, requestedMeasures = value.queryIntent.measures, options = {}) {
212
253
  const byId = new Map(candidates.map((candidate) => [candidate.id, candidate]));
213
254
  const selectedConceptIds = value.selectedConceptIds.length > 0
214
255
  ? value.selectedConceptIds
215
256
  : value.recommendedExecutionId
216
257
  ? [value.recommendedExecutionId]
217
258
  : [];
218
- const referencedIds = [
259
+ // Selected/recommended IDs are execution authority and must be present in
260
+ // the bounded package the resolver received. Rejections are explanatory
261
+ // only: hosts may retain a full-snapshot rejection ledger even when its
262
+ // card was correctly pruned from the 16-card meaning package. Do not let a
263
+ // non-authoritative rejected ID invalidate an otherwise valid frozen plan.
264
+ const authoritativeIds = [
219
265
  ...value.selectedConceptIds,
220
266
  ...(value.recommendedExecutionId ? [value.recommendedExecutionId] : []),
221
- ...value.rejectedCandidates.map((candidate) => candidate.id),
222
267
  ];
223
- const invented = referencedIds.find((id) => !byId.has(id));
268
+ const invented = authoritativeIds.find((id) => !byId.has(id));
224
269
  if (invented)
225
270
  return { ok: false, reason: `The resolver referenced evidence that was not retrieved: ${invented}` };
226
- if (value.confidence !== "low" && selectedConceptIds.length === 0) {
271
+ const packageRejectedCandidates = value.rejectedCandidates.filter((candidate) => byId.has(candidate.id));
272
+ const normalizedValue = packageRejectedCandidates.length === value.rejectedCandidates.length
273
+ ? value
274
+ : { ...value, rejectedCandidates: packageRejectedCandidates };
275
+ if (normalizedValue.confidence !== "low" && selectedConceptIds.length === 0) {
227
276
  return { ok: false, reason: "A medium/high-confidence resolution must select at least one retrieved concept." };
228
277
  }
229
278
  const selected = selectedConceptIds.map((id) => byId.get(id));
230
279
  if (selected.some((candidate) => candidate.eligible === false || candidate.compatibility === "incompatible")) {
231
280
  return { ok: false, reason: "The resolver selected ineligible or incompatible evidence." };
232
281
  }
233
- const rejectedIds = new Set(value.rejectedCandidates.map((candidate) => candidate.id));
282
+ // The evidence package normally excludes a competing metric before the
283
+ // resolver sees it. Keep the same check at the model-output boundary so an
284
+ // extension, legacy caller, or malformed resolver response cannot turn an
285
+ // explicitly named ranking measure into a correlated alternative.
286
+ const explicitRankingConflict = options.requirements
287
+ ? selected.find((candidate) => candidateConflictsWithExplicitRankingMeasure(candidate, options.requirements))
288
+ : undefined;
289
+ if (explicitRankingConflict) {
290
+ return {
291
+ ok: false,
292
+ reason: `The resolver selected a metric that conflicts with the explicit ranking measure: ${explicitRankingConflict.id}`,
293
+ };
294
+ }
295
+ const rejectedIds = new Set(normalizedValue.rejectedCandidates.map((candidate) => candidate.id));
234
296
  if (selectedConceptIds.some((id) => rejectedIds.has(id))) {
235
297
  return { ok: false, reason: "The resolver both selected and rejected the same evidence." };
236
298
  }
237
- const executionId = value.recommendedExecutionId ?? value.selectedConceptIds[0];
299
+ const executionId = normalizedValue.recommendedExecutionId ?? normalizedValue.selectedConceptIds[0];
238
300
  if (executionId) {
239
301
  const execution = byId.get(executionId);
240
- if (execution.eligible === false || execution.compatibility === "incompatible") {
241
- return { ok: false, reason: "The recommended execution evidence is ineligible or incompatible." };
242
- }
243
- if (value.recommendedRoute === "certified" && execution.kind !== "certified_block") {
244
- return { ok: false, reason: "A certified route must reference a certified block." };
245
- }
246
- if (value.recommendedRoute === "certified" && execution.compatibility !== "compatible") {
247
- return { ok: false, reason: "A certified route requires a deterministically compatible block fit." };
248
- }
249
- if (value.recommendedRoute === 'certified'
250
- && !certifiedCandidateExplicitlyCoversMeasures(execution, requestedMeasures)) {
302
+ if (options.requirements && candidateConflictsWithExplicitRankingMeasure(execution, options.requirements)) {
251
303
  return {
252
304
  ok: false,
253
- reason: 'A certified route must declare every requested measure in the selected block output contract.',
305
+ reason: `The resolver selected a metric that conflicts with the explicit ranking measure: ${execution.id}`,
254
306
  };
255
307
  }
256
- if (value.recommendedRoute === "semantic" && execution.kind !== "semantic_metric" && execution.kind !== "semantic_member") {
257
- return { ok: false, reason: "A semantic route must reference semantic evidence." };
258
- }
259
- if (value.recommendedRoute === "semantic" && execution.compatibility !== "compatible") {
260
- return { ok: false, reason: "A semantic route requires deterministic measure, grain, and dimension compatibility." };
308
+ if (execution.eligible === false || execution.compatibility === "incompatible") {
309
+ return { ok: false, reason: "The recommended execution evidence is ineligible or incompatible." };
261
310
  }
311
+ // `recommendedRoute` is deliberately not validated here. The bounded
312
+ // meaning call can nominate only supplied IDs; the authoritative cascade
313
+ // subsequently evaluates the full host-owned requirement seed against
314
+ // those IDs. Rejecting a partial selected semantic metric at this boundary
315
+ // used the model-adjacent nomination as route authority and stopped the
316
+ // valid same-snapshot metric + grouping extension before the semantic
317
+ // compatibility solver could prove it. The same rule applies to a
318
+ // selected certified block: its output contract is checked by the
319
+ // certified cascade before freeze, where an incomplete block advances to
320
+ // semantic/exploratory rather than becoming a false terminal failure.
321
+ //
322
+ // Package membership, eligibility, incompatible evidence, and explicit
323
+ // ranking conflicts above remain hard boundaries; this only defers tier
324
+ // fitness to the host-owned planner.
325
+ void execution;
262
326
  }
263
- if (value.analyticalFrame) {
264
- const invalidFrameReference = firstInvalidAnalyticalFrameReference(value.analyticalFrame, candidates, executionId);
327
+ if (normalizedValue.analyticalFrame) {
328
+ const invalidFrameReference = firstInvalidAnalyticalFrameReference(normalizedValue.analyticalFrame, candidates, executionId);
265
329
  if (invalidFrameReference) {
266
330
  return { ok: false, reason: `The analytical frame referenced evidence that was not retrieved: ${invalidFrameReference}` };
267
331
  }
268
332
  }
269
333
  return {
270
334
  ok: true,
271
- resolution: selectedConceptIds === value.selectedConceptIds
272
- ? value
273
- : { ...value, selectedConceptIds },
335
+ resolution: selectedConceptIds === normalizedValue.selectedConceptIds
336
+ ? normalizedValue
337
+ : { ...normalizedValue, selectedConceptIds },
274
338
  };
275
339
  }
276
340
  function firstInvalidAnalyticalFrameReference(frame, candidates, executionId) {
@@ -362,6 +426,235 @@ function firstInvalidAnalyticalFrameReference(frame, candidates, executionId) {
362
426
  }
363
427
  return undefined;
364
428
  }
429
+ /**
430
+ * Merge the one model meaning response into the host-owned request seed.
431
+ *
432
+ * Candidate IDs are the only model-controlled execution-adjacent values, and
433
+ * they are still validated against the exact supplied package afterwards. The
434
+ * model's route, SQL-adjacent frame, query intent, and reworded question are
435
+ * presentation suggestions at most; accepting them as authority was how an
436
+ * omitted product category/order ID or an inherited prior filter silently
437
+ * changed the answer tuple after retrieval.
438
+ */
439
+ export function mergeMeaningResolutionWithRequirementSeed(input) {
440
+ const { seed, resolution, candidates } = input;
441
+ const modelSelectedConceptIds = [...new Set([
442
+ ...resolution.selectedConceptIds,
443
+ ...(resolution.recommendedExecutionId ? [resolution.recommendedExecutionId] : []),
444
+ ])];
445
+ // A model can bind only supplied IDs, but supplied is not synonymous with
446
+ // grounded in the current request. Discard a known semantic metric that
447
+ // would add a qualifier not present in the immutable seed. Keep unknown IDs
448
+ // in the result so `validateMeaningResolution` still rejects inventions at
449
+ // the boundary rather than silently laundering them away.
450
+ const omittedUngroundedMetricIds = modelSelectedConceptIds.filter((id) => {
451
+ const candidate = candidates.find((item) => item.id === id || item.qualifiedId === id);
452
+ return candidate?.kind === 'semantic_metric'
453
+ && !metricCandidateExactlyMatchesSeed(candidate, seed);
454
+ });
455
+ const selectedConceptIds = modelSelectedConceptIds.filter((id) => !omittedUngroundedMetricIds.includes(id));
456
+ // A minimal candidate-ID-only response is intentionally allowed for the
457
+ // one bounded meaning call. Do not let the order of a role-targeted member
458
+ // extension turn that member into the execution target merely because the
459
+ // model omitted the optional recommendation. A selected metric is the
460
+ // host-safe default; a member only supplies a dimension binding beside it.
461
+ const selectedMetricId = selectedConceptIds.find((id) => {
462
+ const candidate = candidates.find((item) => item.id === id || item.qualifiedId === id);
463
+ return candidate?.kind === 'semantic_metric'
464
+ // A selected metric can supersede a legacy recommendation only when it
465
+ // proves the host-owned metric wording. Token-overlap retrieval is not
466
+ // enough here: otherwise `rollover amount` silently became
467
+ // `rollover_balance_amount` merely because a pooled semantic card had
468
+ // been selected alongside a certified nomination. The cascade can
469
+ // still evaluate a partial candidate later; this guard only prevents a
470
+ // model selection from adding an unspoken metric qualifier.
471
+ && metricCandidateExactlyMatchesSeed(candidate, seed);
472
+ });
473
+ // A model may nominate a certified block in its legacy recommendation while
474
+ // selecting a supplied semantic metric. The recommendation is not route
475
+ // authority; when one selected metric exists, it is the only safe host
476
+ // execution nomination. This preserves the candidate-ID boundary without
477
+ // letting an unproved block displace the selected complete semantic tuple.
478
+ const recommendedExecutionId = selectedMetricId
479
+ ?? resolution.recommendedExecutionId
480
+ ?? selectedConceptIds[0];
481
+ const recommendedCandidate = recommendedExecutionId
482
+ ? candidates.find((candidate) => candidate.id === recommendedExecutionId || candidate.qualifiedId === recommendedExecutionId)
483
+ : undefined;
484
+ const rejectedCandidates = resolution.rejectedCandidates.filter((candidate) => candidates.some((known) => known.id === candidate.id || known.qualifiedId === candidate.id));
485
+ const queryIntent = bindSelectedMemberValuesToSeed({
486
+ seed,
487
+ selectedConceptIds,
488
+ candidates,
489
+ });
490
+ const receipts = [];
491
+ const recordHostPreserved = (field, differs, reason) => {
492
+ if (differs)
493
+ receipts.push({ version: 1, field, action: 'host_preserved', reason });
494
+ };
495
+ recordHostPreserved('interpreted_question', normalizeMeaningText(resolution.interpretedQuestion) !== normalizeMeaningText(seed.sourceQuestion), 'The source question remains host-owned; model rephrasing cannot add context.');
496
+ recordHostPreserved('question_type', resolution.questionType !== questionTypeFromText(seed.sourceQuestion), 'The host classifies the request mode before meaning resolution.');
497
+ recordHostPreserved('query_intent', !sameQueryIntent(resolution.queryIntent, seed.queryIntent), 'Explicit measures, entity/grain, dimensions, filters, ranking, outputs, and time requirements remain host-owned.');
498
+ recordHostPreserved('recommended_route', resolution.recommendedRoute !== (recommendedCandidate ? cascadeNominationForCandidate(recommendedCandidate) : 'clarify'), 'Tier selection is deterministic cascade authority, not a model recommendation.');
499
+ recordHostPreserved('analytical_frame', resolution.analyticalFrame !== undefined, 'A model frame cannot introduce identifiers, SQL semantics, trust, or a replacement route.');
500
+ if (selectedConceptIds.length > 0) {
501
+ receipts.push({
502
+ version: 1,
503
+ field: 'candidate_selection',
504
+ action: 'selection_accepted',
505
+ reason: 'The model selected supplied candidate IDs; host validation still verifies package membership and compatibility.',
506
+ candidateIds: selectedConceptIds,
507
+ });
508
+ }
509
+ if (omittedUngroundedMetricIds.length > 0) {
510
+ receipts.push({
511
+ version: 1,
512
+ field: 'candidate_selection',
513
+ action: 'host_preserved',
514
+ reason: 'A selected semantic metric would add an unspoken qualifier to the host-owned measure requirement.',
515
+ candidateIds: omittedUngroundedMetricIds,
516
+ });
517
+ }
518
+ if (!sameQueryIntent(queryIntent, seed.queryIntent)) {
519
+ receipts.push({
520
+ version: 1,
521
+ field: 'member_binding',
522
+ action: 'selection_accepted',
523
+ reason: 'A selected, supplied semantic member canonically bound an existing host filter value; no filter field or scope was added.',
524
+ candidateIds: selectedConceptIds,
525
+ });
526
+ }
527
+ return {
528
+ interpretedQuestion: seed.sourceQuestion,
529
+ questionType: questionTypeFromText(seed.sourceQuestion),
530
+ selectedConceptIds,
531
+ ...(recommendedExecutionId ? { recommendedExecutionId } : {}),
532
+ queryIntent,
533
+ rejectedCandidates,
534
+ confidence: resolution.confidence,
535
+ missingInformation: [...new Set(resolution.missingInformation)],
536
+ recommendedRoute: recommendedCandidate ? cascadeNominationForCandidate(recommendedCandidate) : 'clarify',
537
+ ...(resolution.clarifyingQuestion ? { clarifyingQuestion: resolution.clarifyingQuestion } : {}),
538
+ hostRequirementSeed: seed,
539
+ ...(receipts.length > 0 ? { overrideReceipts: receipts } : {}),
540
+ };
541
+ }
542
+ /**
543
+ * Keep the host's literal metric requirement authoritative when choosing a
544
+ * primary nominated metric. This intentionally uses exact canonical identity
545
+ * rather than retrieval-style token matching: aliases are normalized into the
546
+ * requirement seed before this boundary, so a legitimate `sales` ->
547
+ * `revenue` binding still matches while a related `rollover balance amount`
548
+ * card cannot add `balance` to an unspoken request for `rollover amount`.
549
+ */
550
+ function metricCandidateExactlyMatchesSeed(candidate, seed) {
551
+ if (seed.requirements.measures.length === 0)
552
+ return true;
553
+ const identities = [candidate.name, ...(candidate.aliases ?? []), candidate.qualifiedId ?? candidate.id]
554
+ .map((value) => canonicalMetricIdentity(value))
555
+ .filter(Boolean);
556
+ // A multi-metric tuple legitimately selects one candidate per requested
557
+ // measure. Each candidate must prove at least one host metric; requiring a
558
+ // single candidate to prove the entire tuple would drop `beverage revenue`
559
+ // beside `total revenue` before the semantic compiler can combine them.
560
+ return seed.requirements.measures.some((measure) => {
561
+ const requested = canonicalMetricIdentity(measure);
562
+ const genericBareTerm = /^(?:amount|value|count|number|total|rate|percentage|percent)$/.test(requested);
563
+ return identities.some((identity) => identity === requested
564
+ // A governed semantic metric may carry a leading accounting qualifier
565
+ // (`net revenue`) for the reader's base term (`revenue`). Keep that
566
+ // narrow suffix form for the established semantic contract, but never
567
+ // permit an inserted qualifier: `rollover balance amount` must not
568
+ // satisfy the distinct request `rollover amount`.
569
+ || (!genericBareTerm && identity.endsWith(` ${requested}`)));
570
+ });
571
+ }
572
+ function canonicalMetricIdentity(value) {
573
+ return value
574
+ .trim()
575
+ .toLowerCase()
576
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
577
+ .replace(/[._:/-]+/g, ' ')
578
+ .replace(/\s+/g, ' ')
579
+ .trim();
580
+ }
581
+ /**
582
+ * A selected semantic member can canonically correct an already-host-owned
583
+ * filter value (for example a retrieved alias/typo), but it cannot introduce
584
+ * a new filter field, member, or prior-result scope. Ambiguous member cards
585
+ * deliberately leave the seed value untouched for later clarification.
586
+ */
587
+ function bindSelectedMemberValuesToSeed(input) {
588
+ const selectedMembers = input.selectedConceptIds.flatMap((id) => {
589
+ const candidate = input.candidates.find((item) => item.id === id || item.qualifiedId === id);
590
+ return candidate?.kind === 'semantic_member' ? [candidate] : [];
591
+ });
592
+ const queryIntent = cloneSeedQueryIntent(input.seed);
593
+ return {
594
+ ...queryIntent,
595
+ filters: queryIntent.filters.map((filter) => {
596
+ const matches = selectedMembers.filter((candidate) => [candidate.name, ...(candidate.aliases ?? [])]
597
+ .map(normalizeMemberBindingText)
598
+ .includes(normalizeMemberBindingText(filter.value)));
599
+ return matches.length === 1 ? { ...filter, value: matches[0].name } : filter;
600
+ }),
601
+ };
602
+ }
603
+ function normalizeMemberBindingText(value) {
604
+ return value.trim().replace(/\s+/g, ' ').toLowerCase();
605
+ }
606
+ /**
607
+ * The model's selected candidate is a nomination for the cascade, not the
608
+ * final eligibility verdict. A partial certified card must therefore enter
609
+ * the certified tier so the deterministic output-contract check can continue
610
+ * to semantic/exploratory evidence instead of pretending it is raw SQL.
611
+ */
612
+ function cascadeNominationForCandidate(candidate) {
613
+ if (candidate.kind === 'certified_block')
614
+ return 'certified';
615
+ if (candidate.kind === 'semantic_metric' || candidate.kind === 'semantic_member')
616
+ return 'semantic';
617
+ return candidate.trustTier === 'governed_sql' ? 'governed_sql' : 'exploratory';
618
+ }
619
+ function cloneSeedQueryIntent(seed) {
620
+ return {
621
+ measures: [...seed.queryIntent.measures],
622
+ dimensions: [...seed.queryIntent.dimensions],
623
+ filters: seed.queryIntent.filters.map((filter) => ({ field: filter.field, value: filter.value })),
624
+ ...(seed.queryIntent.timeRange ? { timeRange: seed.queryIntent.timeRange } : {}),
625
+ ...(seed.queryIntent.timeGrain ? { timeGrain: seed.queryIntent.timeGrain } : {}),
626
+ ...(seed.queryIntent.order ? { order: seed.queryIntent.order } : {}),
627
+ ...(seed.queryIntent.limit !== undefined ? { limit: seed.queryIntent.limit } : {}),
628
+ ...(seed.queryIntent.fiscalCalendarId ? { fiscalCalendarId: seed.queryIntent.fiscalCalendarId } : {}),
629
+ ...(seed.queryIntent.fiscalDateRoleId ? { fiscalDateRoleId: seed.queryIntent.fiscalDateRoleId } : {}),
630
+ };
631
+ }
632
+ function sameQueryIntent(left, right) {
633
+ return JSON.stringify({
634
+ measures: left.measures,
635
+ dimensions: left.dimensions,
636
+ filters: left.filters,
637
+ timeRange: left.timeRange,
638
+ timeGrain: left.timeGrain,
639
+ order: left.order,
640
+ limit: left.limit,
641
+ fiscalCalendarId: left.fiscalCalendarId,
642
+ fiscalDateRoleId: left.fiscalDateRoleId,
643
+ }) === JSON.stringify({
644
+ measures: right.measures,
645
+ dimensions: right.dimensions,
646
+ filters: right.filters,
647
+ timeRange: right.timeRange,
648
+ timeGrain: right.timeGrain,
649
+ order: right.order,
650
+ limit: right.limit,
651
+ fiscalCalendarId: right.fiscalCalendarId,
652
+ fiscalDateRoleId: right.fiscalDateRoleId,
653
+ });
654
+ }
655
+ function normalizeMeaningText(value) {
656
+ return value.trim().replace(/\s+/g, ' ').toLowerCase();
657
+ }
365
658
  export function routeForEvidenceCandidate(candidate) {
366
659
  if (candidate.kind === "certified_block" && candidate.compatibility === "compatible")
367
660
  return "certified";