@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
@@ -1,6 +1,6 @@
1
1
  import { type AnalysisQuestionPlan } from "./analysis-planner.js";
2
2
  import { type AnalyticalPolicyContract, type MetricCapabilityContract } from "@duckcodeailabs/dql-core";
3
- import type { LocalContextPack, MetadataObject } from "./catalog.js";
3
+ import type { LocalContextPack, MetadataObject, MetadataRetrievalLaneResult } from "./catalog.js";
4
4
  import { type AgentRetrievalEvidence, type AgentRelationshipSafetyEvidence } from '../meaning-resolution.js';
5
5
  import type { KnowledgeLens } from '../domain-context.js';
6
6
  export type MetadataEvidenceClass = 'certified' | 'semantic' | 'sql';
@@ -38,6 +38,11 @@ export interface MetadataMeaningCandidate {
38
38
  /** Structured relationship facts when this card itself is a relationship. */
39
39
  relationshipSafety?: AgentRelationshipSafetyEvidence[];
40
40
  provenance?: string;
41
+ /** Actual snapshot retrieval memberships; never inferred from a display name. */
42
+ retrievalLanes?: Array<{
43
+ lane: 'exact' | 'lexical' | 'vector' | 'graph' | 'conversation';
44
+ rank?: number;
45
+ }>;
41
46
  ambiguityPeerIds: string[];
42
47
  }
43
48
  export interface MetadataMeaningEvidencePackage {
@@ -65,6 +70,8 @@ export interface AgentRetrievalEvidenceAdapterOptions {
65
70
  analyticalPolicies?: AnalyticalPolicyContract[];
66
71
  /** Same immutable context-pack objects used to prove member/value bindings. */
67
72
  contextObjects?: MetadataObject[];
73
+ /** Snapshot retrieval results used to preserve multi-lane provenance. */
74
+ retrievalLanes?: MetadataRetrievalLaneResult[];
68
75
  }
69
76
  export interface MeaningEvidenceInputCandidate {
70
77
  row: MetadataObject;
@@ -78,7 +85,7 @@ export interface MeaningEvidenceInputCandidate {
78
85
  * intentionally remain separate: certification labels an execution lane but
79
86
  * never makes an unrelated candidate more relevant to the question.
80
87
  */
81
- export declare function buildMeaningEvidencePackage(question: string, questionPlan: AnalysisQuestionPlan, ranked: MeaningEvidenceInputCandidate[]): MetadataMeaningEvidencePackage;
88
+ export declare function buildMeaningEvidencePackage(question: string, questionPlan: AnalysisQuestionPlan, ranked: MeaningEvidenceInputCandidate[], retrievalLanes?: MetadataRetrievalLaneResult[]): MetadataMeaningEvidencePackage;
82
89
  export declare function toAgentRetrievalEvidence(evidence: MetadataMeaningEvidencePackage, questionPlan: AnalysisQuestionPlan, options?: AgentRetrievalEvidenceAdapterOptions): AgentRetrievalEvidence;
83
90
  /**
84
91
  * One host-neutral compatibility projection shared by CLI, Browser Ask, MCP,
@@ -1 +1 @@
1
- {"version":3,"file":"meaning-evidence.d.ts","sourceRoot":"","sources":["../../src/metadata/meaning-evidence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"meaning-evidence.d.ts","sourceRoot":"","sources":["../../src/metadata/meaning-evidence.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { scoreMetadataObjectWithAnalysisPlan, } from "./analysis-planner.js";
2
2
  import { normalizeMetricCapabilityContract, } from "@duckcodeailabs/dql-core";
3
- import { candidateMatchesCategoricalDimensionRequirement } from '../analytical-orchestration.js';
3
+ import { candidateMatchesCategoricalDimensionRequirement, categoricalDimensionTermsMatch, } from '../analytical-orchestration.js';
4
4
  import { certifiedCandidateExplicitlyCoversMeasures, } from '../meaning-resolution.js';
5
5
  const GENERIC_MEANING_TOKENS = new Set([
6
6
  'amount', 'value', 'metric', 'measure', 'total', 'overall', 'monthly', 'daily',
@@ -14,7 +14,8 @@ const ANALYTICAL_TIME_GRAINS = new Set(['day', 'week', 'month', 'quarter', 'year
14
14
  * intentionally remain separate: certification labels an execution lane but
15
15
  * never makes an unrelated candidate more relevant to the question.
16
16
  */
17
- export function buildMeaningEvidencePackage(question, questionPlan, ranked) {
17
+ export function buildMeaningEvidencePackage(question, questionPlan, ranked, retrievalLanes = []) {
18
+ const laneMembership = laneMembershipByObjectKey(retrievalLanes);
18
19
  const questionText = normalizeText(question);
19
20
  const questionTokens = tokenSet(questionText);
20
21
  const eligible = ranked.flatMap((item) => {
@@ -50,7 +51,7 @@ export function buildMeaningEvidencePackage(question, questionPlan, ranked) {
50
51
  const qualifiedCounts = { certified: 0, semantic: 0, sql: 0 };
51
52
  const qualifiedCandidates = eligible.slice(0, MAX_QUALIFIED_CANDIDATES).map((candidate) => {
52
53
  qualifiedCounts[candidate.evidenceClass] += 1;
53
- return candidateCard(candidate.item.row, candidate.evidenceClass, qualifiedCounts[candidate.evidenceClass], candidate.relevanceScore, candidate.aliases, candidate.relevanceReasons, qualifiedPeerMap.get(candidate.item.row.objectKey) ?? []);
54
+ return candidateCard(candidate.item.row, candidate.evidenceClass, qualifiedCounts[candidate.evidenceClass], candidate.relevanceScore, candidate.aliases, candidate.relevanceReasons, qualifiedPeerMap.get(candidate.item.row.objectKey) ?? [], laneMembership.get(candidate.item.row.objectKey));
54
55
  });
55
56
  const requiredSemanticMetricKey = questionPlan.requestedShape.measures.length > 0
56
57
  ? eligible.find((candidate) => candidate.evidenceClass === 'semantic'
@@ -103,7 +104,7 @@ export function buildMeaningEvidencePackage(question, questionPlan, ranked) {
103
104
  };
104
105
  for (const candidate of selected) {
105
106
  const lane = byEvidenceClass[candidate.evidenceClass];
106
- lane.push(candidateCard(candidate.item.row, candidate.evidenceClass, lane.length + 1, candidate.relevanceScore, candidate.aliases, candidate.relevanceReasons, peerMap.get(candidate.item.row.objectKey) ?? []));
107
+ lane.push(candidateCard(candidate.item.row, candidate.evidenceClass, lane.length + 1, candidate.relevanceScore, candidate.aliases, candidate.relevanceReasons, peerMap.get(candidate.item.row.objectKey) ?? [], laneMembership.get(candidate.item.row.objectKey)));
107
108
  }
108
109
  return {
109
110
  candidates: ['certified', 'semantic', 'sql']
@@ -375,7 +376,8 @@ export function toAgentRetrievalEvidence(evidence, questionPlan, options = {}) {
375
376
  ? evidence.qualifiedCandidates
376
377
  : evidence.candidates;
377
378
  const maxRelevance = Math.max(1, ...sourceCandidates.map((candidate) => candidate.relevanceScore));
378
- const candidates = sourceCandidates.map((candidate) => agentCandidateFromMeaning(candidate, maxRelevance));
379
+ const optionLaneMembership = laneMembershipByObjectKey(options.retrievalLanes ?? []);
380
+ const candidates = sourceCandidates.map((candidate) => agentCandidateFromMeaning(candidate, maxRelevance, candidate.retrievalLanes ?? optionLaneMembership.get(candidate.objectKey)));
379
381
  const trustedBindings = trustedMemberBindingEvidence(questionPlan, candidates, options.contextObjects ?? []);
380
382
  for (const member of trustedBindings.candidates) {
381
383
  if (!candidates.some((candidate) => candidate.id === member.id))
@@ -435,7 +437,7 @@ export function toAgentRetrievalEvidence(evidence, questionPlan, options = {}) {
435
437
  },
436
438
  };
437
439
  }
438
- function agentCandidateFromMeaning(candidate, maxRelevance = 1) {
440
+ function agentCandidateFromMeaning(candidate, maxRelevance = 1, retrievalLanes) {
439
441
  return {
440
442
  id: candidate.objectKey,
441
443
  qualifiedId: candidate.qualifiedId,
@@ -467,6 +469,7 @@ function agentCandidateFromMeaning(candidate, maxRelevance = 1) {
467
469
  analyticalCapability: candidate.analyticalCapability,
468
470
  eligible: true,
469
471
  exactMatch: candidate.relevanceReasons.includes("exact name or alias"),
472
+ ...(retrievalLanes?.length ? { retrievalLanes } : {}),
470
473
  };
471
474
  }
472
475
  function trustedMemberBindingEvidence(plan, candidates, objects) {
@@ -581,6 +584,87 @@ function supplementalClarificationEvidence(plan, objects, existing) {
581
584
  exactMatch: false,
582
585
  }];
583
586
  }));
587
+ // A compact retrieval package can contain the selected semantic metric but
588
+ // not a separately indexed card for one of that metric's declared grouping
589
+ // dimensions. Retain one exact, same-snapshot extension for that field when
590
+ // the request names its categorical role. This does not infer a join or a
591
+ // business alias: the metric capability owns both the qualified dimension
592
+ // id and the MetricFlow-native grouping path, and the router later admits it
593
+ // only beside this exact metric. It is intentionally separate from the
594
+ // geography-only recovery below, which may bind a location-like field for
595
+ // the distinct business term `region` under a stricter sole-field rule.
596
+ const exactCapabilityDimensionCards = existing.flatMap((metric) => {
597
+ if (metric.kind !== 'semantic_metric')
598
+ return [];
599
+ const capability = normalizeMetricCapabilityContract(metric.analyticalCapability);
600
+ if (!capability || !capability.executionCapabilities.some((execution) => execution.route === 'semantic'))
601
+ return [];
602
+ const metricId = metric.qualifiedId ?? metric.id;
603
+ return requestedDimensions.flatMap((requestedTerm) => capability.dimensions.flatMap((dimension) => {
604
+ if (!dimension.supportedRoles.includes('group_by'))
605
+ return [];
606
+ // `existing` is the unbounded retrieval snapshot, not the compact
607
+ // meaning package. A separately indexed semantic dimension can be
608
+ // present here yet later lose its role-balanced admission to a raw/dbt
609
+ // column with the same business words. Preserve the capability-backed
610
+ // extension in that case so the router can admit it beside its exact
611
+ // metric. The final de-duplication deliberately retains this extension
612
+ // (with its metric/role proof) over a plain dimension card.
613
+ const identities = [
614
+ dimension.dimensionId,
615
+ dimension.label ?? '',
616
+ ...(dimension.aliases ?? []),
617
+ ];
618
+ if (!identities.some((identity) => categoricalDimensionTermsMatch(requestedTerm, identity)))
619
+ return [];
620
+ return [{
621
+ id: dimension.dimensionId,
622
+ qualifiedId: dimension.dimensionId,
623
+ kind: 'semantic_member',
624
+ semanticObjectType: 'dimension',
625
+ trustTier: 'semantic',
626
+ name: dimension.label ?? dimension.dimensionId.split(/[.:/]/).at(-1) ?? dimension.dimensionId,
627
+ aliases: uniqueStrings([
628
+ dimension.label ?? '',
629
+ ...(dimension.aliases ?? []),
630
+ requestedTerm,
631
+ ]),
632
+ definition: `Same-snapshot MetricFlow grouping field for ${requestedTerm}.`,
633
+ primaryEntity: dimension.entityId,
634
+ dimensions: [dimension.dimensionId],
635
+ sourceObjects: metric.sourceObjects,
636
+ relationshipEvidence: metric.relationshipEvidence,
637
+ relationshipSafety: metric.relationshipSafety,
638
+ relevanceScore: metric.relevanceScore,
639
+ matchReasons: ['same snapshot exact MetricFlow grouping extension'],
640
+ compatibility: 'compatible',
641
+ eligible: true,
642
+ exactMatch: false,
643
+ sameSnapshotRoleExtension: {
644
+ version: 1,
645
+ role: 'categorical_dimension',
646
+ requestedTerm,
647
+ metricId,
648
+ dimensionId: dimension.dimensionId,
649
+ basis: 'exact_metricflow_grouping_dimension',
650
+ },
651
+ }];
652
+ }));
653
+ });
654
+ // A location-like semantic dimension is not generally a synonym for
655
+ // "region". There is one deliberately narrow exception: when every
656
+ // current-turn requested metric proves the same one MetricFlow grouping
657
+ // dimension in this immutable snapshot. Surface that card as a typed,
658
+ // host-authored extension so the bounded meaning call can bind it; the
659
+ // selected metric capability still verifies the native grouping path and
660
+ // remains the only execution authority. This recovers the real Jaffle
661
+ // `revenue by ... region` path without guessing a raw join or widening
662
+ // lexical geography matching.
663
+ const sameSnapshotRoleExtensions = sameSnapshotGeographyRoleExtensions({
664
+ requestedMeasures,
665
+ requestedDimensions,
666
+ existing,
667
+ });
584
668
  // A bare ranking ("who are the top customers") names an ENTITY and no
585
669
  // measure, so every lane above — each keyed on a REQUESTED measure or
586
670
  // dimension term — returns nothing, and the clarification has no choices to
@@ -624,8 +708,32 @@ function supplementalClarificationEvidence(plan, objects, existing) {
624
708
  return [card];
625
709
  }).sort((left, right) => right.relevanceScore - left.relevanceScore || left.id.localeCompare(right.id));
626
710
  })();
627
- const unique = [...objectCards, ...declaredDimensionCards, ...rankingMeasureCards]
628
- .filter((candidate, index, all) => all.findIndex((other) => (other.qualifiedId ?? other.id) === (candidate.qualifiedId ?? candidate.id)) === index);
711
+ // The index may yield a generic semantic-dimension card and then this
712
+ // function may enrich that exact qualified ID with a metric-declared,
713
+ // same-snapshot role proof. Retain the enriched card: it is not a second
714
+ // candidate or a guessed relationship, but the only metadata authority that
715
+ // says this field is queryable with the selected MetricFlow metric for the
716
+ // current requested role. First-seen de-duplication discarded that proof in
717
+ // real local indexes and manufactured a false coverage gap for
718
+ // `product category` / `product_type`.
719
+ const uniqueByQualifiedId = new Map();
720
+ for (const candidate of [
721
+ ...objectCards,
722
+ ...exactCapabilityDimensionCards,
723
+ ...declaredDimensionCards,
724
+ ...sameSnapshotRoleExtensions,
725
+ ...rankingMeasureCards,
726
+ ]) {
727
+ const key = candidate.qualifiedId ?? candidate.id;
728
+ const existingCandidate = uniqueByQualifiedId.get(key);
729
+ if (!existingCandidate
730
+ || (!existingCandidate.sameSnapshotRoleExtension && candidate.sameSnapshotRoleExtension)) {
731
+ // Map replacement preserves stable first-seen ordering while retaining
732
+ // the stricter extension provenance for this one qualified object.
733
+ uniqueByQualifiedId.set(key, candidate);
734
+ }
735
+ }
736
+ const unique = [...uniqueByQualifiedId.values()];
629
737
  const roleLanes = [
630
738
  ...requestedDimensions.map((term) => ({ kind: 'dimension', term })),
631
739
  ...requestedMeasures.map((term) => ({ kind: 'metric', term })),
@@ -658,6 +766,95 @@ function supplementalClarificationEvidence(plan, objects, existing) {
658
766
  }
659
767
  return selected.slice(0, MAX_SUPPLEMENTAL_CANDIDATES);
660
768
  }
769
+ function sameSnapshotGeographyRoleExtensions(input) {
770
+ const geographyTerms = [...new Set(input.requestedDimensions
771
+ .map(normalizeText)
772
+ .filter((term) => term === 'region' || term === 'geography' || term === 'geographic'))];
773
+ if (geographyTerms.length === 0 || input.requestedMeasures.length === 0)
774
+ return [];
775
+ const existingGeography = input.existing.some((candidate) => geographyTerms.some((term) => candidateMatchesCategoricalDimensionRequirement(candidate, [term])));
776
+ if (existingGeography)
777
+ return [];
778
+ const canonicalMetricTerm = (value) => {
779
+ const normalized = normalizeText(value);
780
+ return normalized === 'sale' || normalized === 'sales' ? 'revenue' : normalized;
781
+ };
782
+ const metricMatches = (candidate, requested) => {
783
+ if (candidate.kind !== 'semantic_metric' || !candidate.analyticalCapability)
784
+ return false;
785
+ const expected = canonicalMetricTerm(requested);
786
+ return [candidate.name, ...(candidate.aliases ?? []), candidate.analyticalCapability.metricId]
787
+ .map(canonicalMetricTerm)
788
+ .some((identity) => phraseTermsMatch(expected, identity));
789
+ };
790
+ const geographicDimension = (dimension) => {
791
+ const identity = [dimension.dimensionId, dimension.entityId, dimension.label ?? '', ...(dimension.aliases ?? [])]
792
+ .map(normalizeText)
793
+ .join(' ');
794
+ return /\b(?:region|geograph(?:y|ic)|location|country|state|province|city|territory)\b/.test(identity);
795
+ };
796
+ const candidatesForMeasure = (requested) => input.existing.flatMap((candidate) => {
797
+ if (!metricMatches(candidate, requested))
798
+ return [];
799
+ const capability = candidate.analyticalCapability;
800
+ if (!capability.executionCapabilities.some((execution) => execution.route === 'semantic'))
801
+ return [];
802
+ return capability.dimensions
803
+ .filter((dimension) => dimension.supportedRoles.includes('group_by') && geographicDimension(dimension))
804
+ .map((dimension) => ({ candidate, dimension }));
805
+ });
806
+ const matchesByMeasure = input.requestedMeasures.map((requested) => ({
807
+ requested,
808
+ matches: candidatesForMeasure(requested),
809
+ }));
810
+ if (matchesByMeasure.some(({ matches }) => matches.length === 0))
811
+ return [];
812
+ const sharedDimensionIds = matchesByMeasure
813
+ .map(({ matches }) => new Set(matches.map(({ dimension }) => dimension.dimensionId)))
814
+ .reduce((shared, ids) => shared === undefined
815
+ ? ids
816
+ : new Set([...shared].filter((id) => ids.has(id))), undefined);
817
+ if (!sharedDimensionIds || sharedDimensionIds.size !== 1)
818
+ return [];
819
+ const dimensionId = [...sharedDimensionIds][0];
820
+ const witness = matchesByMeasure[0].matches.find((match) => match.dimension.dimensionId === dimensionId);
821
+ if (!witness)
822
+ return [];
823
+ const { candidate: metricCandidate, dimension } = witness;
824
+ const requestedTerm = geographyTerms[0];
825
+ return [{
826
+ id: dimensionId,
827
+ qualifiedId: dimensionId,
828
+ kind: 'semantic_member',
829
+ semanticObjectType: 'dimension',
830
+ trustTier: 'semantic',
831
+ name: dimension.label ?? dimension.dimensionId.split(/[.:/]/).at(-1) ?? dimension.dimensionId,
832
+ aliases: uniqueStrings([
833
+ dimension.label ?? '',
834
+ ...(dimension.aliases ?? []),
835
+ requestedTerm,
836
+ ]),
837
+ definition: `Same-snapshot MetricFlow grouping field for ${requestedTerm}.`,
838
+ primaryEntity: dimension.entityId,
839
+ dimensions: [dimensionId],
840
+ sourceObjects: metricCandidate.sourceObjects,
841
+ relationshipEvidence: metricCandidate.relationshipEvidence,
842
+ relationshipSafety: metricCandidate.relationshipSafety,
843
+ relevanceScore: metricCandidate.relevanceScore,
844
+ matchReasons: ['same snapshot role-targeted MetricFlow grouping extension'],
845
+ compatibility: 'compatible',
846
+ eligible: true,
847
+ exactMatch: false,
848
+ sameSnapshotRoleExtension: {
849
+ version: 1,
850
+ role: 'categorical_dimension',
851
+ requestedTerm,
852
+ metricId: metricCandidate.qualifiedId ?? metricCandidate.id,
853
+ dimensionId,
854
+ basis: 'sole_metricflow_grouping_dimension',
855
+ },
856
+ }];
857
+ }
661
858
  function expandedRequestedTerms(terms, objects) {
662
859
  const vocabulary = new Map();
663
860
  for (const object of objects) {
@@ -832,13 +1029,45 @@ export function applyContextPackCompatibility(evidence, pack, selectedEvidenceId
832
1029
  // paraphrase "What is monthly revenue?". Do not promote lexical
833
1030
  // relevance alone; require the catalog's executable fit verdict.
834
1031
  const requestedMeasures = pack.questionPlan.requestedShape.measures;
835
- const blockDeclaresRequestedMeasures = certifiedCandidateExplicitlyCoversMeasures(candidate, requestedMeasures);
1032
+ // `declaredOutputs` is preferable because it remains independently
1033
+ // visible in the block source. Some older-but-valid certified blocks
1034
+ // only expose their projection through the catalog's immutable SQL
1035
+ // contract, however. Preserve that proof *only* when the reader typed
1036
+ // the exact block title and the same snapshot's catalog has already
1037
+ // selected this precise block as a high-confidence certified answer.
1038
+ // A fuzzy alias, paraphrase, or ordinary semantic question cannot use
1039
+ // this bridge, so non-exact role and output constraints remain intact.
1040
+ const exactCertifiedTitle = typeof pack.questionPlan.question === 'string'
1041
+ && normalizeText(pack.questionPlan.question) === normalizeText(candidate.name)
1042
+ && pack.routeDecision.route === 'certified'
1043
+ && pack.routeDecision.exactObjectKey === candidate.id
1044
+ && fit?.action === 'certified_answer'
1045
+ && (fit.fit.kind === 'exact' || fit.fit.kind === 'trim_safe')
1046
+ && fit.fit.confidence === 'high';
1047
+ const compatibilityFacts = exactCertifiedTitle
1048
+ ? uniqueStrings([
1049
+ ...(candidate.compatibilityFacts ?? []),
1050
+ ...requestedMeasures.map((measure) => `catalog-proven-output: ${measure}`),
1051
+ // The catalog fit also proves this block's declared result
1052
+ // grain. Preserve it as an output only on the exact-title
1053
+ // bridge, so the immutable plan can bind `customer` to its
1054
+ // actual `customer_name` result without making a fuzzy block
1055
+ // title a display-key authority.
1056
+ ...(candidate.compatibilityFacts ?? []).flatMap((fact) => /^grain:\s*(.+)$/i.exec(fact)?.[1]
1057
+ ?.split(',')
1058
+ .map((value) => value.trim())
1059
+ .filter(Boolean)
1060
+ .map((value) => `catalog-proven-output: ${value}`) ?? []),
1061
+ ])
1062
+ : candidate.compatibilityFacts;
1063
+ const blockDeclaresRequestedMeasures = certifiedCandidateExplicitlyCoversMeasures({ ...candidate, compatibilityFacts }, requestedMeasures);
836
1064
  const completeCertifiedFit = fit?.action === 'certified_answer'
837
1065
  && (fit.fit.kind === 'exact' || fit.fit.kind === 'trim_safe')
838
1066
  && fit.fit.confidence === 'high'
839
1067
  && blockDeclaresRequestedMeasures;
840
1068
  return {
841
1069
  ...candidate,
1070
+ ...(compatibilityFacts ? { compatibilityFacts } : {}),
842
1071
  // Lexical equality to a block name/alias is useful retrieval signal,
843
1072
  // but it is not exact analytical authority. The catalog's complete
844
1073
  // certified fit is the one host-owned exception and is still checked
@@ -915,11 +1144,18 @@ function trustTierFor(object, evidenceClass) {
915
1144
  return 'governed_sql';
916
1145
  return 'exploratory';
917
1146
  }
918
- function candidateCard(object, evidenceClass, classRank, relevanceScore, aliases, relevanceReasons, ambiguityPeerIds) {
1147
+ function candidateCard(object, evidenceClass, classRank, relevanceScore, aliases, relevanceReasons, ambiguityPeerIds, retrievalLanes) {
919
1148
  const payload = object.payload ?? {};
920
1149
  const analyticalCapability = normalizeMetricCapabilityContract(payload.analyticalCapability);
921
1150
  const relationshipSafety = relationshipSafetyFromObject(object);
922
- const qualifiedId = firstString(payload.qualifiedId, payload.uniqueId, object.fullName, object.objectKey) ?? object.objectKey;
1151
+ // A dbt/runtime column inherits its parent node's `uniqueId`. That value
1152
+ // is useful lineage metadata, but it is not a column identity: using it as
1153
+ // the candidate's qualified ID collapsed every selected column on a model
1154
+ // into the model itself. The physical cascade then appeared safe but could
1155
+ // not freeze an exact output contract. Keep the parent relation in
1156
+ // `sourceRelations`; give a column its source-qualified field identity.
1157
+ const columnObject = object.objectType.endsWith('_column');
1158
+ const qualifiedId = firstString(payload.qualifiedId, ...(columnObject ? [object.fullName] : []), payload.uniqueId, object.fullName, object.objectKey) ?? object.objectKey;
923
1159
  const parameters = arrayNames(payload.parameters ?? payload.parameterPolicy);
924
1160
  const outputs = uniqueStrings([
925
1161
  ...stringArray(payload.declaredOutputs),
@@ -986,9 +1222,23 @@ function candidateCard(object, evidenceClass, classRank, relevanceScore, aliases
986
1222
  ...(analyticalCapability ? { analyticalCapability } : {}),
987
1223
  ...(relationshipSafety ? { relationshipSafety: [relationshipSafety] } : {}),
988
1224
  provenance: firstString(payload.provenance, object.sourceSystem),
1225
+ ...(retrievalLanes?.length ? { retrievalLanes } : {}),
989
1226
  ambiguityPeerIds,
990
1227
  };
991
1228
  }
1229
+ function laneMembershipByObjectKey(lanes) {
1230
+ const memberships = new Map();
1231
+ for (const lane of lanes) {
1232
+ for (const candidate of lane.candidates) {
1233
+ const next = memberships.get(candidate.objectKey) ?? [];
1234
+ if (!next.some((entry) => entry.lane === lane.lane && entry.rank === candidate.rank)) {
1235
+ next.push({ lane: lane.lane, rank: candidate.rank });
1236
+ }
1237
+ memberships.set(candidate.objectKey, next);
1238
+ }
1239
+ }
1240
+ return memberships;
1241
+ }
992
1242
  function agentEvidenceKind(candidate) {
993
1243
  if (candidate.evidenceClass === 'certified')
994
1244
  return 'certified_block';