@duckcodeailabs/dql-agent 1.6.34 → 1.7.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 +14 -1
- package/dist/agent-run-engine.d.ts.map +1 -1
- package/dist/agent-run-engine.js +123 -3
- package/dist/agent-run-engine.js.map +1 -1
- package/dist/agent-run-gates.d.ts.map +1 -1
- package/dist/agent-run-gates.js +6 -0
- package/dist/agent-run-gates.js.map +1 -1
- package/dist/answer-loop.d.ts +57 -4
- package/dist/answer-loop.d.ts.map +1 -1
- package/dist/answer-loop.js +435 -44
- package/dist/answer-loop.js.map +1 -1
- package/dist/app-builder.d.ts +36 -3
- package/dist/app-builder.d.ts.map +1 -1
- package/dist/app-builder.js +285 -22
- package/dist/app-builder.js.map +1 -1
- package/dist/cascade/budgets.d.ts.map +1 -1
- package/dist/cascade/budgets.js +8 -3
- package/dist/cascade/budgets.js.map +1 -1
- package/dist/cascade/route-policy.d.ts.map +1 -1
- package/dist/cascade/route-policy.js +5 -0
- package/dist/cascade/route-policy.js.map +1 -1
- package/dist/dashboard-story.d.ts +36 -0
- package/dist/dashboard-story.d.ts.map +1 -0
- package/dist/dashboard-story.js +140 -0
- package/dist/dashboard-story.js.map +1 -0
- package/dist/domain-context.d.ts +30 -0
- package/dist/domain-context.d.ts.map +1 -0
- package/dist/domain-context.js +76 -0
- package/dist/domain-context.js.map +1 -0
- package/dist/hints/git-store.d.ts +39 -3
- package/dist/hints/git-store.d.ts.map +1 -1
- package/dist/hints/git-store.js +172 -2
- package/dist/hints/git-store.js.map +1 -1
- package/dist/hints/types.d.ts +41 -0
- package/dist/hints/types.d.ts.map +1 -1
- package/dist/hints/types.js +1 -0
- package/dist/hints/types.js.map +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -3
- package/dist/index.js.map +1 -1
- package/dist/kg/build.d.ts.map +1 -1
- package/dist/kg/build.js +220 -4
- package/dist/kg/build.js.map +1 -1
- package/dist/kg/sqlite-fts.d.ts.map +1 -1
- package/dist/kg/sqlite-fts.js +8 -3
- package/dist/kg/sqlite-fts.js.map +1 -1
- package/dist/kg/types.d.ts +9 -2
- package/dist/kg/types.d.ts.map +1 -1
- package/dist/metadata/analysis-planner.d.ts.map +1 -1
- package/dist/metadata/analysis-planner.js +134 -18
- package/dist/metadata/analysis-planner.js.map +1 -1
- package/dist/metadata/analytical-policy.d.ts +51 -0
- package/dist/metadata/analytical-policy.d.ts.map +1 -0
- package/dist/metadata/analytical-policy.js +309 -0
- package/dist/metadata/analytical-policy.js.map +1 -0
- package/dist/metadata/block-fit.js +37 -4
- package/dist/metadata/block-fit.js.map +1 -1
- package/dist/metadata/catalog.d.ts +49 -1
- package/dist/metadata/catalog.d.ts.map +1 -1
- package/dist/metadata/catalog.js +365 -54
- package/dist/metadata/catalog.js.map +1 -1
- package/dist/metadata/dbt-first-safety.d.ts +19 -0
- package/dist/metadata/dbt-first-safety.d.ts.map +1 -0
- package/dist/metadata/dbt-first-safety.js +17 -0
- package/dist/metadata/dbt-first-safety.js.map +1 -0
- package/dist/metadata/sql-context-validation.d.ts.map +1 -1
- package/dist/metadata/sql-context-validation.js +42 -2
- package/dist/metadata/sql-context-validation.js.map +1 -1
- package/dist/metadata/sql-grounding.d.ts.map +1 -1
- package/dist/metadata/sql-grounding.js +25 -2
- package/dist/metadata/sql-grounding.js.map +1 -1
- package/dist/metadata/sql-retrieval.d.ts +2 -0
- package/dist/metadata/sql-retrieval.d.ts.map +1 -1
- package/dist/metadata/sql-retrieval.js +5 -1
- package/dist/metadata/sql-retrieval.js.map +1 -1
- package/dist/propose/build-from-prompt.d.ts +34 -0
- package/dist/propose/build-from-prompt.d.ts.map +1 -1
- package/dist/propose/build-from-prompt.js +199 -19
- package/dist/propose/build-from-prompt.js.map +1 -1
- package/dist/semantic-bridge/compose.d.ts.map +1 -1
- package/dist/semantic-bridge/compose.js +169 -5
- package/dist/semantic-bridge/compose.js.map +1 -1
- package/dist/skills/loader.d.ts +19 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +107 -12
- package/dist/skills/loader.js.map +1 -1
- package/dist/synthesize.d.ts.map +1 -1
- package/dist/synthesize.js +152 -16
- package/dist/synthesize.js.map +1 -1
- package/dist/tools/registry.d.ts +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +42 -0
- package/dist/tools/registry.js.map +1 -1
- package/package.json +4 -4
package/dist/app-builder.d.ts
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
import { type AppDocument, type DashboardDocument, type DashboardTileFilterBinding, type DashboardTileParameterBinding, type DashboardTileSourceEvidence, type DashboardVizConfig } from "@duckcodeailabs/dql-core";
|
|
1
|
+
import { type AppDocument, type DashboardDocument, type DashboardSemanticQueryRef, type DashboardStoryEvidencePlan, type DashboardTileFilterBinding, type DashboardTileParameterBinding, type DashboardTileSourceEvidence, type DashboardVizConfig } from "@duckcodeailabs/dql-core";
|
|
2
2
|
import type { KGStore } from "./kg/sqlite-fts.js";
|
|
3
3
|
import type { NarrateResult } from "./narrate.js";
|
|
4
|
+
export type AppMode = "personal" | "stakeholder";
|
|
5
|
+
export interface AppRequirement {
|
|
6
|
+
id: string;
|
|
7
|
+
question: string;
|
|
8
|
+
role: "kpi" | "trend" | "breakdown" | "detail";
|
|
9
|
+
measures: string[];
|
|
10
|
+
dimensions: string[];
|
|
11
|
+
filters: string[];
|
|
12
|
+
grain?: string;
|
|
13
|
+
ranking?: {
|
|
14
|
+
direction: "top" | "bottom";
|
|
15
|
+
limit: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface RequirementCoverage {
|
|
19
|
+
requirementId: string;
|
|
20
|
+
status: "covered" | "gap";
|
|
21
|
+
source: "certified_block" | "semantic_query" | "gap";
|
|
22
|
+
tileId?: string;
|
|
23
|
+
sourceId?: string;
|
|
24
|
+
trustState: AppPlanTrustState;
|
|
25
|
+
reasons: string[];
|
|
26
|
+
}
|
|
4
27
|
export type AppBuilderSkillId = "interpret_business_intent" | "match_certified_context" | "shape_business_story" | "design_dashboard_layout" | "draft_missing_sections" | "route_review";
|
|
5
|
-
export type AppPlanTileKind = "certified_block" | "draft_placeholder" | "narrative";
|
|
28
|
+
export type AppPlanTileKind = "certified_block" | "semantic_query" | "draft_placeholder" | "narrative";
|
|
6
29
|
export type AppPlanAnalysisIntent = "executive_summary" | "metric_monitoring" | "driver_analysis" | "entity_drilldown" | "trust_review" | "data_quality" | "experiment_readout";
|
|
7
30
|
export type AppPlanTileRole = "business_summary" | "kpi" | "trend" | "breakdown" | "evidence" | "trust" | "research" | "narrative";
|
|
8
31
|
export type AppPlanTrustState = "certified" | "review_required" | "draft_ready";
|
|
@@ -46,6 +69,8 @@ export interface AppPlanTile {
|
|
|
46
69
|
kind: AppPlanTileKind;
|
|
47
70
|
description?: string;
|
|
48
71
|
blockId?: string;
|
|
72
|
+
semantic?: DashboardSemanticQueryRef;
|
|
73
|
+
requirementIds?: string[];
|
|
49
74
|
sourceNodeId?: string;
|
|
50
75
|
viz: DashboardVizConfig["type"];
|
|
51
76
|
certification: "certified" | "uncertified";
|
|
@@ -98,7 +123,12 @@ export interface AppBuilderSkill {
|
|
|
98
123
|
description: string;
|
|
99
124
|
}
|
|
100
125
|
export interface AppPlan {
|
|
101
|
-
version:
|
|
126
|
+
version: 2;
|
|
127
|
+
mode: AppMode;
|
|
128
|
+
snapshotId?: string;
|
|
129
|
+
requirements: AppRequirement[];
|
|
130
|
+
requirementCoverage: RequirementCoverage[];
|
|
131
|
+
storyEvidencePlan: DashboardStoryEvidencePlan;
|
|
102
132
|
appId: string;
|
|
103
133
|
name: string;
|
|
104
134
|
prompt: string;
|
|
@@ -158,6 +188,9 @@ export interface PlanAppFromPromptInput {
|
|
|
158
188
|
preferredBlockIds?: string[];
|
|
159
189
|
maxCertifiedTiles?: number;
|
|
160
190
|
plannerMode?: "deterministic" | "ai_assisted";
|
|
191
|
+
mode?: AppMode;
|
|
192
|
+
snapshotId?: string;
|
|
193
|
+
allowSemanticQueries?: boolean;
|
|
161
194
|
}
|
|
162
195
|
export interface AppPlanValidationIssue {
|
|
163
196
|
level: "error" | "warning";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-builder.d.ts","sourceRoot":"","sources":["../src/app-builder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-builder.d.ts","sourceRoot":"","sources":["../src/app-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/app-builder.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import { join, relative } from "node:path";
|
|
3
4
|
import { parseAppDocument, parseDashboardDocument, suggestAppId, } from "@duckcodeailabs/dql-core";
|
|
5
|
+
import { buildAnalysisQuestionPlan } from "./metadata/analysis-planner.js";
|
|
6
|
+
import { certifiedFitAllowsTier1, evaluateCertifiedBlockFit } from "./metadata/block-fit.js";
|
|
4
7
|
export const APP_BUILDER_SKILLS = [
|
|
5
8
|
{
|
|
6
9
|
id: "interpret_business_intent",
|
|
@@ -33,6 +36,163 @@ export const APP_BUILDER_SKILLS = [
|
|
|
33
36
|
description: "Keep generated analysis review-required and attach concrete next steps before stakeholder use.",
|
|
34
37
|
},
|
|
35
38
|
];
|
|
39
|
+
function appRequirementsForPrompt(prompt) {
|
|
40
|
+
const analysis = buildAnalysisQuestionPlan(prompt);
|
|
41
|
+
const measures = analysis.requestedShape.measures.length
|
|
42
|
+
? analysis.requestedShape.measures
|
|
43
|
+
: analysis.metricTerms;
|
|
44
|
+
const dimensions = analysis.requestedShape.dimensions;
|
|
45
|
+
const filters = analysis.requestedShape.filters;
|
|
46
|
+
const ranking = analysis.requestedShape.topN
|
|
47
|
+
? { direction: analysis.requestedShape.rankingDirection ?? "top", limit: analysis.requestedShape.topN.n }
|
|
48
|
+
: undefined;
|
|
49
|
+
const requirements = [{
|
|
50
|
+
id: "primary",
|
|
51
|
+
question: prompt,
|
|
52
|
+
role: ranking ? "detail" : dimensions.length ? "breakdown" : "kpi",
|
|
53
|
+
measures,
|
|
54
|
+
dimensions,
|
|
55
|
+
filters,
|
|
56
|
+
grain: analysis.requestedShape.grain,
|
|
57
|
+
...(ranking ? { ranking } : {}),
|
|
58
|
+
}];
|
|
59
|
+
const wantsTrend = analysis.mode === "trend" || /\btrend|over time|weekly|monthly|quarterly\b/i.test(prompt);
|
|
60
|
+
if (wantsTrend && !requirements.some((requirement) => requirement.role === "trend")) {
|
|
61
|
+
requirements.push({
|
|
62
|
+
id: "trend",
|
|
63
|
+
question: `${measures.join(" and ") || "primary metric"} over time`,
|
|
64
|
+
role: "trend",
|
|
65
|
+
measures,
|
|
66
|
+
dimensions: analysis.timeTerms.length ? analysis.timeTerms : ["time"],
|
|
67
|
+
filters,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
for (const dimension of dimensions.slice(0, 2)) {
|
|
71
|
+
if (requirements[0]?.dimensions.includes(dimension) && dimensions.length === 1)
|
|
72
|
+
continue;
|
|
73
|
+
requirements.push({
|
|
74
|
+
id: `by-${slugify(dimension)}`,
|
|
75
|
+
question: `${measures.join(" and ") || "primary metric"} by ${dimension}`,
|
|
76
|
+
role: "breakdown",
|
|
77
|
+
measures,
|
|
78
|
+
dimensions: [dimension],
|
|
79
|
+
filters,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return requirements;
|
|
83
|
+
}
|
|
84
|
+
function certifiedCoverageForRequirement(requirement, nodes) {
|
|
85
|
+
const plan = buildAnalysisQuestionPlan(requirement.question);
|
|
86
|
+
const ranked = nodes.map((node) => ({
|
|
87
|
+
node,
|
|
88
|
+
fit: evaluateCertifiedBlockFit({ question: requirement.question, plan, block: node }),
|
|
89
|
+
requirementFit: certifiedNodeCoversRequirement(node, requirement),
|
|
90
|
+
}));
|
|
91
|
+
const exact = ranked.find((candidate) => certifiedFitAllowsTier1(candidate.fit) && candidate.requirementFit.ok);
|
|
92
|
+
if (exact)
|
|
93
|
+
return { node: exact.node, reasons: exact.fit.reasons };
|
|
94
|
+
return {
|
|
95
|
+
reasons: Array.from(new Set(ranked.flatMap((candidate) => [
|
|
96
|
+
...(certifiedFitAllowsTier1(candidate.fit) && !candidate.requirementFit.ok ? [] : candidate.fit.reasons),
|
|
97
|
+
...candidate.requirementFit.reasons,
|
|
98
|
+
]))).slice(0, 5),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* App requirements are already structured, so they are a stronger contract than
|
|
103
|
+
* reparsing the short requirement question. This guard prevents descriptive
|
|
104
|
+
* metadata from making (for example) a product ranking look like a time trend,
|
|
105
|
+
* or an all-customer lifetime ranking look like a beverage-filtered ranking.
|
|
106
|
+
*/
|
|
107
|
+
function certifiedNodeCoversRequirement(node, requirement) {
|
|
108
|
+
const haystack = canonicalRequirementText(JSON.stringify(node));
|
|
109
|
+
const missingDimensions = requirement.dimensions.filter((dimension) => !requirementTermAliases(dimension).some((alias) => haystack.includes(` ${alias} `)));
|
|
110
|
+
const filterTerms = requirement.filters.flatMap((filter) => canonicalRequirementText(filter).trim().split(/\s+/).filter((term) => term.length > 2 && !REQUIREMENT_FILTER_STOP_WORDS.has(term)));
|
|
111
|
+
const missingFilters = filterTerms.filter((term) => !requirementTermAliases(term).some((alias) => haystack.includes(` ${alias} `)));
|
|
112
|
+
const reasons = [
|
|
113
|
+
missingDimensions.length ? `certified source does not prove dimensions: ${missingDimensions.join(", ")}` : "",
|
|
114
|
+
missingFilters.length ? `certified source does not prove filters: ${missingFilters.join(", ")}` : "",
|
|
115
|
+
].filter(Boolean);
|
|
116
|
+
return { ok: reasons.length === 0, reasons };
|
|
117
|
+
}
|
|
118
|
+
const REQUIREMENT_FILTER_STOP_WORDS = new Set([
|
|
119
|
+
"and", "for", "from", "with", "different", "type", "types", "specific", "only", "all",
|
|
120
|
+
]);
|
|
121
|
+
function canonicalRequirementText(value) {
|
|
122
|
+
return ` ${value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim()} `;
|
|
123
|
+
}
|
|
124
|
+
function requirementTermAliases(value) {
|
|
125
|
+
const term = canonicalRequirementText(value).trim();
|
|
126
|
+
if (["time", "date"].includes(term))
|
|
127
|
+
return ["time", "date", "day", "week", "month", "quarter", "year", "ordered at"];
|
|
128
|
+
if (["beverage", "beverages"].includes(term))
|
|
129
|
+
return ["beverage", "beverages", "drink", "drinks"];
|
|
130
|
+
if (["customer", "customers"].includes(term))
|
|
131
|
+
return ["customer", "customers", "customer name", "customer id"];
|
|
132
|
+
if (["product", "products"].includes(term))
|
|
133
|
+
return ["product", "products", "product name", "product id", "item", "sku"];
|
|
134
|
+
return [term];
|
|
135
|
+
}
|
|
136
|
+
function semanticTileForRequirement(kg, requirement, domain, snapshotId) {
|
|
137
|
+
if (requirement.measures.length === 0)
|
|
138
|
+
return null;
|
|
139
|
+
const hits = kg.search({
|
|
140
|
+
query: requirement.question,
|
|
141
|
+
domain: domain === "general" ? undefined : domain,
|
|
142
|
+
kinds: ["metric", "measure", "semantic_model", "dimension"],
|
|
143
|
+
limit: 24,
|
|
144
|
+
}).map((hit) => hit.node);
|
|
145
|
+
const metricNodes = hits.filter((node) => node.kind === "metric" || node.kind === "measure");
|
|
146
|
+
const modelNodes = hits.filter((node) => node.kind === "semantic_model");
|
|
147
|
+
if (metricNodes.length === 0 || modelNodes.length === 0)
|
|
148
|
+
return null;
|
|
149
|
+
const requested = new Set(requirement.measures.map((measure) => slugify(measure).replace(/-/g, "_")));
|
|
150
|
+
const metric = metricNodes.find((node) => requested.has(slugify(node.name).replace(/-/g, "_"))) ?? metricNodes[0];
|
|
151
|
+
if (!metric)
|
|
152
|
+
return null;
|
|
153
|
+
const semanticModelRefs = Array.from(new Set(modelNodes.map((node) => node.name))).slice(0, 4);
|
|
154
|
+
const id = `semantic-${requirement.id}`;
|
|
155
|
+
const fingerprintPayload = JSON.stringify({
|
|
156
|
+
metric: metric.nodeId,
|
|
157
|
+
dimensions: requirement.dimensions,
|
|
158
|
+
filters: requirement.filters,
|
|
159
|
+
models: semanticModelRefs,
|
|
160
|
+
snapshotId,
|
|
161
|
+
});
|
|
162
|
+
const semantic = {
|
|
163
|
+
id,
|
|
164
|
+
provider: metric.provenance?.toLowerCase().includes("metricflow") ? "metricflow" : "native",
|
|
165
|
+
metrics: [metric.name],
|
|
166
|
+
...(requirement.dimensions.length ? { dimensions: requirement.dimensions } : {}),
|
|
167
|
+
...(requirement.ranking ? {
|
|
168
|
+
orderBy: [{ field: metric.name, direction: requirement.ranking.direction === "bottom" ? "asc" : "desc" }],
|
|
169
|
+
limit: requirement.ranking.limit,
|
|
170
|
+
} : {}),
|
|
171
|
+
semanticModelRefs,
|
|
172
|
+
definitionFingerprint: `sha256:${createHash("sha256").update(fingerprintPayload).digest("hex")}`,
|
|
173
|
+
...(snapshotId ? { snapshotId } : {}),
|
|
174
|
+
};
|
|
175
|
+
const viz = requirement.role === "kpi"
|
|
176
|
+
? "single_value"
|
|
177
|
+
: requirement.role === "trend" ? "line" : requirement.ranking ? "bar" : "table";
|
|
178
|
+
return {
|
|
179
|
+
id,
|
|
180
|
+
title: requirement.question,
|
|
181
|
+
kind: "semantic_query",
|
|
182
|
+
semantic,
|
|
183
|
+
requirementIds: [requirement.id],
|
|
184
|
+
viz,
|
|
185
|
+
certification: "uncertified",
|
|
186
|
+
reviewStatus: "review_required",
|
|
187
|
+
trustState: "review_required",
|
|
188
|
+
rationale: "Governed semantic coverage for a requirement not fully covered by a compatible certified block.",
|
|
189
|
+
sourceEvidence: [
|
|
190
|
+
{ source: metric.nodeId, nodeId: metric.nodeId, kind: metric.kind, reason: "Reviewed semantic metric", trustState: "review_required" },
|
|
191
|
+
...modelNodes.slice(0, 4).map((node) => ({ source: node.nodeId, nodeId: node.nodeId, kind: node.kind, reason: "Semantic model used by the canonical query", trustState: "review_required" })),
|
|
192
|
+
],
|
|
193
|
+
reviewTasks: ["Review semantic definition freshness and result shape before stakeholder publication."],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
36
196
|
export function planAppFromPrompt(input) {
|
|
37
197
|
const prompt = input.prompt.trim();
|
|
38
198
|
if (!prompt)
|
|
@@ -54,7 +214,61 @@ export function planAppFromPrompt(input) {
|
|
|
54
214
|
const promptFilters = inferFilters(prompt);
|
|
55
215
|
const blockFilters = filtersFromCertifiedNodes(certifiedNodes);
|
|
56
216
|
const filters = blockFilters.length > 0 ? mergeAppFilters(blockFilters, promptFilters) : promptFilters;
|
|
57
|
-
const
|
|
217
|
+
const candidateCertifiedTiles = certifiedNodes.map((node, index) => tileFromCertifiedNode(node, index, analysisIntent, filters));
|
|
218
|
+
const requirements = appRequirementsForPrompt(prompt);
|
|
219
|
+
const coverage = [];
|
|
220
|
+
const selectedCertifiedIds = new Set();
|
|
221
|
+
const semanticTiles = [];
|
|
222
|
+
for (const requirement of requirements) {
|
|
223
|
+
const match = certifiedCoverageForRequirement(requirement, certifiedNodes);
|
|
224
|
+
if (match.node) {
|
|
225
|
+
const tileId = slugify(match.node.name) || match.node.nodeId;
|
|
226
|
+
selectedCertifiedIds.add(match.node.nodeId);
|
|
227
|
+
coverage.push({
|
|
228
|
+
requirementId: requirement.id,
|
|
229
|
+
status: "covered",
|
|
230
|
+
source: "certified_block",
|
|
231
|
+
tileId,
|
|
232
|
+
sourceId: match.node.nodeId,
|
|
233
|
+
trustState: "certified",
|
|
234
|
+
reasons: match.reasons,
|
|
235
|
+
});
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const semanticTile = input.allowSemanticQueries === false
|
|
239
|
+
? null
|
|
240
|
+
: semanticTileForRequirement(input.kg, requirement, domain, input.snapshotId);
|
|
241
|
+
if (semanticTile) {
|
|
242
|
+
semanticTiles.push(semanticTile);
|
|
243
|
+
coverage.push({
|
|
244
|
+
requirementId: requirement.id,
|
|
245
|
+
status: "covered",
|
|
246
|
+
source: "semantic_query",
|
|
247
|
+
tileId: semanticTile.id,
|
|
248
|
+
sourceId: semanticTile.semantic?.id,
|
|
249
|
+
trustState: "review_required",
|
|
250
|
+
reasons: ["No fully compatible certified block; covered by a governed semantic query."],
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
coverage.push({
|
|
255
|
+
requirementId: requirement.id,
|
|
256
|
+
status: "gap",
|
|
257
|
+
source: "gap",
|
|
258
|
+
trustState: "draft_ready",
|
|
259
|
+
reasons: match.reasons.length ? match.reasons : ["No compatible certified block or reviewed semantic definition was found."],
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Keep compatible certified context only. For legacy unshaped prompts, retain
|
|
264
|
+
// the best certified candidates so existing simple App generation stays useful.
|
|
265
|
+
// Requirement coverage is strict, while explicitly discovered certified
|
|
266
|
+
// context may still appear as supporting evidence tiles. It never closes a
|
|
267
|
+
// requirement unless the compatibility check above succeeds.
|
|
268
|
+
// Compatible blocks close requirements; other strongly related certified
|
|
269
|
+
// blocks may still appear as supporting context, but never change coverage.
|
|
270
|
+
const certifiedTiles = candidateCertifiedTiles;
|
|
271
|
+
const dashboardTiles = [...certifiedTiles, ...semanticTiles];
|
|
58
272
|
const scopedReports = inferScopedReports(prompt, domain, analysisIntent, certifiedNodes);
|
|
59
273
|
const certifiedContextSummary = summarizeCertifiedContext([
|
|
60
274
|
...certifiedNodes,
|
|
@@ -76,7 +290,18 @@ export function planAppFromPrompt(input) {
|
|
|
76
290
|
filterLabels: filters.map((filter) => filter.label),
|
|
77
291
|
});
|
|
78
292
|
return {
|
|
79
|
-
version:
|
|
293
|
+
version: 2,
|
|
294
|
+
mode: input.mode ?? "stakeholder",
|
|
295
|
+
...(input.snapshotId ? { snapshotId: input.snapshotId } : {}),
|
|
296
|
+
requirements,
|
|
297
|
+
requirementCoverage: coverage,
|
|
298
|
+
storyEvidencePlan: {
|
|
299
|
+
version: 1,
|
|
300
|
+
goal: prompt,
|
|
301
|
+
audience,
|
|
302
|
+
eligibleTileIds: dashboardTiles.map((tile) => tile.id),
|
|
303
|
+
driverTileIds: dashboardTiles.filter((tile) => tile.display?.role === "breakdown" || tile.requirementIds?.some((id) => id.startsWith("by-"))).map((tile) => tile.id),
|
|
304
|
+
},
|
|
80
305
|
appId,
|
|
81
306
|
name: appName,
|
|
82
307
|
prompt,
|
|
@@ -139,7 +364,7 @@ export function planAppFromPrompt(input) {
|
|
|
139
364
|
title: inferDashboardTitle(prompt, domain, appName),
|
|
140
365
|
description: `Certified app surface for ${audience}. Draft gaps stay in reports until reviewed.`,
|
|
141
366
|
filters,
|
|
142
|
-
tiles:
|
|
367
|
+
tiles: dashboardTiles,
|
|
143
368
|
},
|
|
144
369
|
],
|
|
145
370
|
caveats: [
|
|
@@ -154,9 +379,9 @@ export function planAppFromPrompt(input) {
|
|
|
154
379
|
],
|
|
155
380
|
coverage: {
|
|
156
381
|
certifiedTiles: certifiedTiles.length,
|
|
157
|
-
gaps:
|
|
158
|
-
ratio:
|
|
159
|
-
?
|
|
382
|
+
gaps: coverage.filter((item) => item.status === "gap").length,
|
|
383
|
+
ratio: coverage.length > 0
|
|
384
|
+
? coverage.filter((item) => item.status === "covered").length / coverage.length
|
|
160
385
|
: 0,
|
|
161
386
|
},
|
|
162
387
|
};
|
|
@@ -165,7 +390,7 @@ export function validateAppPlan(plan, kg) {
|
|
|
165
390
|
const issues = [];
|
|
166
391
|
let certifiedTiles = 0;
|
|
167
392
|
let draftTiles = 0;
|
|
168
|
-
if (plan.version !==
|
|
393
|
+
if (plan.version !== 2)
|
|
169
394
|
issues.push(error("version", "unsupported app plan version"));
|
|
170
395
|
if (!plan.appId || !/^[a-z0-9][a-z0-9_-]*$/i.test(plan.appId)) {
|
|
171
396
|
issues.push(error("appId", "appId must be folder-safe"));
|
|
@@ -207,6 +432,23 @@ export function validateAppPlan(plan, kg) {
|
|
|
207
432
|
issues.push(error(path, "certified block tiles must be visibly certified"));
|
|
208
433
|
}
|
|
209
434
|
}
|
|
435
|
+
else if (tile.kind === "semantic_query") {
|
|
436
|
+
draftTiles += 1;
|
|
437
|
+
if (!tile.semantic) {
|
|
438
|
+
issues.push(error(`${path}.semantic`, "semantic query tile requires a canonical semantic reference"));
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
if (tile.semantic.metrics.length === 0)
|
|
442
|
+
issues.push(error(`${path}.semantic.metrics`, "semantic query requires a metric"));
|
|
443
|
+
if (tile.semantic.semanticModelRefs.length === 0)
|
|
444
|
+
issues.push(error(`${path}.semantic.semanticModelRefs`, "semantic query requires reviewed model references"));
|
|
445
|
+
if (!tile.semantic.definitionFingerprint)
|
|
446
|
+
issues.push(error(`${path}.semantic.definitionFingerprint`, "semantic query requires a definition fingerprint"));
|
|
447
|
+
}
|
|
448
|
+
if (tile.certification === "certified" || tile.reviewStatus === "certified") {
|
|
449
|
+
issues.push(error(path, "semantic query tiles cannot be presented as certified blocks"));
|
|
450
|
+
}
|
|
451
|
+
}
|
|
210
452
|
else {
|
|
211
453
|
draftTiles += 1;
|
|
212
454
|
issues.push(error(path, "stakeholder dashboard tiles must be certified blocks; route generated story, trust, and analysis work through scoped reports or Copilot investigations"));
|
|
@@ -235,11 +477,20 @@ export function generateAppFromPlan(projectRoot, plan, kg, options = {}) {
|
|
|
235
477
|
if (errors.length > 0) {
|
|
236
478
|
throw new Error(`AppPlan is invalid: ${errors.map((issue) => `${issue.path}: ${issue.message}`).join("; ")}`);
|
|
237
479
|
}
|
|
238
|
-
const appDir = resolveAppPackageDir(projectRoot, plan.
|
|
480
|
+
const appDir = resolveAppPackageDir(projectRoot, plan.appId);
|
|
239
481
|
if (existsSync(appDir) && !options.overwrite) {
|
|
240
482
|
throw new Error(`App already exists: ${relative(projectRoot, appDir)}`);
|
|
241
483
|
}
|
|
242
484
|
const dashboardId = plan.pages[0]?.id || "overview";
|
|
485
|
+
const sourceNodes = plan.pages.flatMap((page) => page.tiles)
|
|
486
|
+
.flatMap((tile) => tile.sourceEvidence ?? [])
|
|
487
|
+
.map((evidence) => evidence.nodeId ? kg.getNode(evidence.nodeId) : undefined)
|
|
488
|
+
.filter((node) => Boolean(node));
|
|
489
|
+
const usedDomains = Array.from(new Set([plan.domain, ...sourceNodes.map((node) => node.domain).filter((domain) => Boolean(domain))]));
|
|
490
|
+
const requiredExports = Array.from(new Set(sourceNodes.flatMap((node) => {
|
|
491
|
+
const value = node.payload?.requiredExports;
|
|
492
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
493
|
+
})));
|
|
243
494
|
const app = {
|
|
244
495
|
version: 1,
|
|
245
496
|
id: plan.appId,
|
|
@@ -253,7 +504,10 @@ export function generateAppFromPlan(projectRoot, plan, kg, options = {}) {
|
|
|
253
504
|
"Certified tiles must reference existing certified blocks.",
|
|
254
505
|
],
|
|
255
506
|
caveats: plan.caveats,
|
|
256
|
-
visibility: "shared",
|
|
507
|
+
visibility: plan.mode === "personal" ? "private" : "shared",
|
|
508
|
+
ownerDomain: plan.domain,
|
|
509
|
+
usesDomains: usedDomains,
|
|
510
|
+
requiredExports,
|
|
257
511
|
domain: plan.domain,
|
|
258
512
|
audience: plan.audience,
|
|
259
513
|
lifecycle: plan.lifecycle,
|
|
@@ -311,16 +565,16 @@ export function generateAppFromPlan(projectRoot, plan, kg, options = {}) {
|
|
|
311
565
|
const dashboards = plan.pages.map((page, pageIndex) => ({
|
|
312
566
|
version: 1,
|
|
313
567
|
id: page.id,
|
|
314
|
-
// Story layout on the primary page when a narration was supplied.
|
|
315
568
|
...(options.narration && pageIndex === 0
|
|
316
569
|
? { sections: buildStorySections(page.tiles, options.narration) }
|
|
317
570
|
: {}),
|
|
571
|
+
...(pageIndex === 0 ? { story: plan.storyEvidencePlan } : {}),
|
|
318
572
|
metadata: {
|
|
319
573
|
title: page.title,
|
|
320
574
|
description: page.description ?? plan.planning.displayStrategy,
|
|
321
575
|
domain: plan.domain,
|
|
322
576
|
audience: plan.audience,
|
|
323
|
-
visibility: "shared",
|
|
577
|
+
visibility: plan.mode === "personal" ? "private" : "shared",
|
|
324
578
|
lifecycle: "draft",
|
|
325
579
|
tags: plan.tags,
|
|
326
580
|
businessOutcome: plan.planning.normalizedGoal,
|
|
@@ -990,16 +1244,26 @@ function filterBindingsForCertifiedNode(node, globalFilters) {
|
|
|
990
1244
|
return uniqueTileFilterBindings(bindings);
|
|
991
1245
|
}
|
|
992
1246
|
function parameterBindingsForCertifiedNode(node, filterBindings) {
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
|
|
1247
|
+
const definitions = new Map((node.parameters ?? []).map((entry) => [entry.name, entry]));
|
|
1248
|
+
const runtimePolicies = new Set(["dynamic", "optional"]);
|
|
1249
|
+
const dynamicParams = Array.from(new Set([
|
|
1250
|
+
...(node.parameters ?? []).filter((entry) => runtimePolicies.has(entry.policy)).map((entry) => entry.name),
|
|
1251
|
+
...(node.parameterPolicy ?? []).filter((entry) => runtimePolicies.has(entry.policy)).map((entry) => entry.name),
|
|
1252
|
+
]));
|
|
996
1253
|
return dynamicParams.map((param) => {
|
|
997
1254
|
const filterBinding = filterBindings.find((entry) => entry.paramNames?.includes(param) || entry.filter === param);
|
|
1255
|
+
const definition = definitions.get(param);
|
|
998
1256
|
return {
|
|
999
1257
|
param,
|
|
1000
1258
|
source: filterBinding ? "dashboard_filter" : "variable",
|
|
1001
1259
|
...(filterBinding?.filter ? { filter: filterBinding.filter } : {}),
|
|
1002
1260
|
field: filterBinding?.binding ?? param,
|
|
1261
|
+
...(definition ? {
|
|
1262
|
+
parameterType: definition.type,
|
|
1263
|
+
required: definition.required,
|
|
1264
|
+
...(definition.default !== undefined ? { default: definition.default } : {}),
|
|
1265
|
+
policy: definition.policy,
|
|
1266
|
+
} : {}),
|
|
1003
1267
|
};
|
|
1004
1268
|
});
|
|
1005
1269
|
}
|
|
@@ -1155,9 +1419,12 @@ function buildLayoutItems(tiles) {
|
|
|
1155
1419
|
trustState: tile.trustState ?? tile.display?.trustState ?? (tile.certification === "certified" ? "certified" : "draft_ready"),
|
|
1156
1420
|
reviewStatus: tile.reviewStatus,
|
|
1157
1421
|
};
|
|
1158
|
-
if (
|
|
1422
|
+
if (tile.kind === "certified_block" && tile.blockId) {
|
|
1159
1423
|
item.block = { blockId: tile.blockId };
|
|
1160
1424
|
}
|
|
1425
|
+
else if (tile.kind === "semantic_query" && tile.semantic) {
|
|
1426
|
+
item.semantic = tile.semantic;
|
|
1427
|
+
}
|
|
1161
1428
|
else {
|
|
1162
1429
|
item.text = { markdown: markdownForGeneratedPlanTile(tile) };
|
|
1163
1430
|
}
|
|
@@ -1187,7 +1454,8 @@ function markdownForGeneratedPlanTile(tile) {
|
|
|
1187
1454
|
].filter(Boolean).join("\n");
|
|
1188
1455
|
}
|
|
1189
1456
|
function isDashboardTile(tile) {
|
|
1190
|
-
return tile.kind === "certified_block" && tile.certification === "certified" && Boolean(tile.blockId)
|
|
1457
|
+
return (tile.kind === "certified_block" && tile.certification === "certified" && Boolean(tile.blockId))
|
|
1458
|
+
|| (tile.kind === "semantic_query" && Boolean(tile.semantic));
|
|
1191
1459
|
}
|
|
1192
1460
|
function appPlanReadme(plan, validation) {
|
|
1193
1461
|
const reviewDashboardItems = plan.pages.flatMap((page) => page.tiles
|
|
@@ -1688,12 +1956,7 @@ function slugify(input) {
|
|
|
1688
1956
|
.replace(/^-+|-+$/g, "")
|
|
1689
1957
|
.replace(/-{2,}/g, "-");
|
|
1690
1958
|
}
|
|
1691
|
-
function resolveAppPackageDir(projectRoot,
|
|
1692
|
-
const domainSlug = slugify(domain);
|
|
1693
|
-
const domainDir = domainSlug ? join(projectRoot, "domains", domainSlug) : "";
|
|
1694
|
-
if (domainDir && existsSync(domainDir)) {
|
|
1695
|
-
return join(domainDir, "apps", appId);
|
|
1696
|
-
}
|
|
1959
|
+
function resolveAppPackageDir(projectRoot, appId) {
|
|
1697
1960
|
return join(projectRoot, "apps", appId);
|
|
1698
1961
|
}
|
|
1699
1962
|
function normalizeToken(input) {
|