@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.
- package/dist/agent-run-engine.d.ts +63 -2
- package/dist/agent-run-engine.d.ts.map +1 -1
- package/dist/agent-run-engine.js +864 -29
- package/dist/agent-run-engine.js.map +1 -1
- package/dist/agent-run-planner.d.ts +6 -0
- package/dist/agent-run-planner.d.ts.map +1 -1
- package/dist/agent-run-planner.js +2 -0
- package/dist/agent-run-planner.js.map +1 -1
- package/dist/agent-run-store.d.ts.map +1 -1
- package/dist/agent-run-store.js +48 -3
- package/dist/agent-run-store.js.map +1 -1
- package/dist/agentic/analyst-loop.d.ts +7 -1
- package/dist/agentic/analyst-loop.d.ts.map +1 -1
- package/dist/agentic/analyst-loop.js +163 -0
- package/dist/agentic/analyst-loop.js.map +1 -1
- package/dist/agentic/assumptions.d.ts +1 -1
- package/dist/agentic/assumptions.d.ts.map +1 -1
- package/dist/agentic/assumptions.js.map +1 -1
- package/dist/agentic/research-agent.d.ts.map +1 -1
- package/dist/agentic/research-agent.js +10 -1
- package/dist/agentic/research-agent.js.map +1 -1
- package/dist/agentic/sql-authorization.d.ts +8 -0
- package/dist/agentic/sql-authorization.d.ts.map +1 -1
- package/dist/agentic/sql-authorization.js +3 -0
- package/dist/agentic/sql-authorization.js.map +1 -1
- package/dist/analytical-compatibility.d.ts.map +1 -1
- package/dist/analytical-compatibility.js +8 -1
- package/dist/analytical-compatibility.js.map +1 -1
- package/dist/analytical-failure-repair.d.ts.map +1 -1
- package/dist/analytical-failure-repair.js +6 -2
- package/dist/analytical-failure-repair.js.map +1 -1
- package/dist/analytical-frame.d.ts +23 -1
- package/dist/analytical-frame.d.ts.map +1 -1
- package/dist/analytical-frame.js +322 -16
- package/dist/analytical-frame.js.map +1 -1
- package/dist/analytical-orchestration.d.ts +314 -3
- package/dist/analytical-orchestration.d.ts.map +1 -1
- package/dist/analytical-orchestration.js +486 -43
- package/dist/analytical-orchestration.js.map +1 -1
- package/dist/answer-loop.d.ts +64 -8
- package/dist/answer-loop.d.ts.map +1 -1
- package/dist/answer-loop.js +528 -67
- package/dist/answer-loop.js.map +1 -1
- package/dist/ask-observability/index.d.ts +11 -0
- package/dist/ask-observability/index.d.ts.map +1 -0
- package/dist/ask-observability/index.js +7 -0
- package/dist/ask-observability/index.js.map +1 -0
- package/dist/ask-observability/instrumentation.d.ts +35 -0
- package/dist/ask-observability/instrumentation.d.ts.map +1 -0
- package/dist/ask-observability/instrumentation.js +472 -0
- package/dist/ask-observability/instrumentation.js.map +1 -0
- package/dist/ask-observability/observer.d.ts +62 -0
- package/dist/ask-observability/observer.d.ts.map +1 -0
- package/dist/ask-observability/observer.js +537 -0
- package/dist/ask-observability/observer.js.map +1 -0
- package/dist/ask-observability/portable.d.ts +98 -0
- package/dist/ask-observability/portable.d.ts.map +1 -0
- package/dist/ask-observability/portable.js +527 -0
- package/dist/ask-observability/portable.js.map +1 -0
- package/dist/ask-observability/store.d.ts +130 -0
- package/dist/ask-observability/store.d.ts.map +1 -0
- package/dist/ask-observability/store.js +1114 -0
- package/dist/ask-observability/store.js.map +1 -0
- package/dist/ask-observability/types.d.ts +357 -0
- package/dist/ask-observability/types.d.ts.map +1 -0
- package/dist/ask-observability/types.js +2 -0
- package/dist/ask-observability/types.js.map +1 -0
- package/dist/ask-observability/utils.d.ts +21 -0
- package/dist/ask-observability/utils.d.ts.map +1 -0
- package/dist/ask-observability/utils.js +102 -0
- package/dist/ask-observability/utils.js.map +1 -0
- package/dist/generated-analytical-proposal.d.ts +37 -1
- package/dist/generated-analytical-proposal.d.ts.map +1 -1
- package/dist/generated-analytical-proposal.js +211 -3
- package/dist/generated-analytical-proposal.js.map +1 -1
- package/dist/governed-relational-compiler.d.ts +15 -0
- package/dist/governed-relational-compiler.d.ts.map +1 -1
- package/dist/governed-relational-compiler.js +99 -1
- package/dist/governed-relational-compiler.js.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/intent-controller.d.ts +10 -0
- package/dist/intent-controller.d.ts.map +1 -1
- package/dist/intent-controller.js +1 -1
- package/dist/intent-controller.js.map +1 -1
- package/dist/meaning-resolution.d.ts +78 -6
- package/dist/meaning-resolution.d.ts.map +1 -1
- package/dist/meaning-resolution.js +331 -38
- package/dist/meaning-resolution.js.map +1 -1
- package/dist/metadata/analysis-planner.d.ts.map +1 -1
- package/dist/metadata/analysis-planner.js +21 -1
- package/dist/metadata/analysis-planner.js.map +1 -1
- package/dist/metadata/catalog.d.ts.map +1 -1
- package/dist/metadata/catalog.js +1 -1
- package/dist/metadata/catalog.js.map +1 -1
- package/dist/metadata/meaning-evidence.d.ts +9 -2
- package/dist/metadata/meaning-evidence.d.ts.map +1 -1
- package/dist/metadata/meaning-evidence.js +261 -11
- package/dist/metadata/meaning-evidence.js.map +1 -1
- package/dist/plan-execution-adapter.d.ts +9 -1
- package/dist/plan-execution-adapter.d.ts.map +1 -1
- package/dist/plan-execution-adapter.js +93 -13
- package/dist/plan-execution-adapter.js.map +1 -1
- package/dist/provider-egress.d.ts +24 -10
- package/dist/provider-egress.d.ts.map +1 -1
- package/dist/provider-egress.js +22 -17
- package/dist/provider-egress.js.map +1 -1
- package/dist/providers/claude.d.ts.map +1 -1
- package/dist/providers/claude.js +10 -9
- package/dist/providers/claude.js.map +1 -1
- package/dist/providers/dispatch.d.ts +27 -1
- package/dist/providers/dispatch.d.ts.map +1 -1
- package/dist/providers/dispatch.js +63 -1
- package/dist/providers/dispatch.js.map +1 -1
- package/dist/providers/gemini.js +10 -10
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/ollama.js +15 -15
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai.js +22 -22
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/types.d.ts +52 -0
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/relationship-proof.d.ts +81 -0
- package/dist/relationship-proof.d.ts.map +1 -1
- package/dist/relationship-proof.js +228 -4
- package/dist/relationship-proof.js.map +1 -1
- package/dist/resolved-analytical-plan.d.ts +18 -4
- package/dist/resolved-analytical-plan.d.ts.map +1 -1
- package/dist/resolved-analytical-plan.js +764 -47
- package/dist/resolved-analytical-plan.js.map +1 -1
- package/dist/router.d.ts +10 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +1785 -213
- package/dist/router.js.map +1 -1
- package/dist/semantic-bridge/compose.d.ts.map +1 -1
- package/dist/semantic-bridge/compose.js +23 -4
- package/dist/semantic-bridge/compose.js.map +1 -1
- 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":"AAAA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAC;
|
|
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
|
|
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
|
-
|
|
628
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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';
|