@mcoda/core 0.1.8 → 0.1.11
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/CHANGELOG.md +3 -0
- package/README.md +2 -2
- package/dist/api/AgentsApi.d.ts +9 -1
- package/dist/api/AgentsApi.d.ts.map +1 -1
- package/dist/api/AgentsApi.js +201 -6
- package/dist/api/QaTasksApi.d.ts.map +1 -1
- package/dist/api/QaTasksApi.js +6 -0
- package/dist/api/TasksApi.d.ts.map +1 -1
- package/dist/api/TasksApi.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/prompts/PdrPrompts.d.ts.map +1 -1
- package/dist/prompts/PdrPrompts.js +9 -1
- package/dist/prompts/SdsPrompts.d.ts.map +1 -1
- package/dist/prompts/SdsPrompts.js +9 -0
- package/dist/services/agents/AgentRatingFormula.d.ts +27 -0
- package/dist/services/agents/AgentRatingFormula.d.ts.map +1 -0
- package/dist/services/agents/AgentRatingFormula.js +45 -0
- package/dist/services/agents/AgentRatingService.d.ts +60 -0
- package/dist/services/agents/AgentRatingService.d.ts.map +1 -0
- package/dist/services/agents/AgentRatingService.js +363 -0
- package/dist/services/agents/GatewayAgentService.d.ts +11 -0
- package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
- package/dist/services/agents/GatewayAgentService.js +525 -84
- package/dist/services/agents/GatewayHandoff.d.ts +11 -0
- package/dist/services/agents/GatewayHandoff.d.ts.map +1 -0
- package/dist/services/agents/GatewayHandoff.js +141 -0
- package/dist/services/agents/RoutingService.d.ts +1 -0
- package/dist/services/agents/RoutingService.d.ts.map +1 -1
- package/dist/services/agents/RoutingService.js +4 -4
- package/dist/services/backlog/BacklogService.d.ts +23 -0
- package/dist/services/backlog/BacklogService.d.ts.map +1 -1
- package/dist/services/backlog/BacklogService.js +62 -7
- package/dist/services/backlog/TaskOrderingHeuristics.d.ts +12 -0
- package/dist/services/backlog/TaskOrderingHeuristics.d.ts.map +1 -0
- package/dist/services/backlog/TaskOrderingHeuristics.js +56 -0
- package/dist/services/backlog/TaskOrderingService.d.ts +17 -4
- package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
- package/dist/services/backlog/TaskOrderingService.js +538 -79
- package/dist/services/docs/DocInventory.d.ts +11 -0
- package/dist/services/docs/DocInventory.d.ts.map +1 -0
- package/dist/services/docs/DocInventory.js +230 -0
- package/dist/services/docs/DocgenRunContext.d.ts +59 -0
- package/dist/services/docs/DocgenRunContext.d.ts.map +1 -0
- package/dist/services/docs/DocgenRunContext.js +4 -0
- package/dist/services/docs/DocsService.d.ts +70 -3
- package/dist/services/docs/DocsService.d.ts.map +1 -1
- package/dist/services/docs/DocsService.js +1930 -89
- package/dist/services/docs/alignment/DocAlignmentGraph.d.ts +23 -0
- package/dist/services/docs/alignment/DocAlignmentGraph.d.ts.map +1 -0
- package/dist/services/docs/alignment/DocAlignmentGraph.js +78 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts +19 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts.map +1 -0
- package/dist/services/docs/alignment/DocAlignmentPatcher.js +222 -0
- package/dist/services/docs/patch/DocPatchEngine.d.ts +57 -0
- package/dist/services/docs/patch/DocPatchEngine.d.ts.map +1 -0
- package/dist/services/docs/patch/DocPatchEngine.js +331 -0
- package/dist/services/docs/review/Glossary.d.ts +16 -0
- package/dist/services/docs/review/Glossary.d.ts.map +1 -0
- package/dist/services/docs/review/Glossary.js +47 -0
- package/dist/services/docs/review/ReviewReportRenderer.d.ts +3 -0
- package/dist/services/docs/review/ReviewReportRenderer.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewReportRenderer.js +133 -0
- package/dist/services/docs/review/ReviewReportSchema.d.ts +39 -0
- package/dist/services/docs/review/ReviewReportSchema.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewReportSchema.js +47 -0
- package/dist/services/docs/review/ReviewTypes.d.ts +76 -0
- package/dist/services/docs/review/ReviewTypes.d.ts.map +1 -0
- package/dist/services/docs/review/ReviewTypes.js +94 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts +7 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/AdminOpenApiSpecGate.js +93 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts +7 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/ApiPathConsistencyGate.js +308 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts +8 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/BuildReadyCompletenessGate.js +278 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts +8 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/DeploymentBlueprintGate.js +487 -0
- package/dist/services/docs/review/gates/NoMaybesGate.d.ts +8 -0
- package/dist/services/docs/review/gates/NoMaybesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/NoMaybesGate.js +145 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenApiCoverageGate.js +266 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.js +59 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/OpenQuestionsGate.js +200 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts +7 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrInterfacesGate.js +159 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts +8 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrOpenQuestionsGate.js +129 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts +7 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PdrOwnershipGate.js +169 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts +10 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/PlaceholderArtifactGate.js +261 -0
- package/dist/services/docs/review/gates/RfpConsentGate.d.ts +6 -0
- package/dist/services/docs/review/gates/RfpConsentGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/RfpConsentGate.js +127 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts +7 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/RfpDefinitionGate.js +173 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsAdaptersGate.js +196 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsDecisionsGate.js +89 -0
- package/dist/services/docs/review/gates/SdsOpsGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsOpsGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsOpsGate.js +162 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.js +166 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SqlRequiredTablesGate.js +273 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts +7 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/SqlSyntaxGate.js +203 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts +9 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts.map +1 -0
- package/dist/services/docs/review/gates/TerminologyNormalizationGate.js +217 -0
- package/dist/services/docs/review/glossary.json +47 -0
- package/dist/services/estimate/EstimateService.d.ts +2 -0
- package/dist/services/estimate/EstimateService.d.ts.map +1 -1
- package/dist/services/estimate/EstimateService.js +66 -18
- package/dist/services/estimate/VelocityService.d.ts +4 -0
- package/dist/services/estimate/VelocityService.d.ts.map +1 -1
- package/dist/services/estimate/VelocityService.js +179 -36
- package/dist/services/estimate/types.d.ts +1 -0
- package/dist/services/estimate/types.d.ts.map +1 -1
- package/dist/services/execution/GatewayTrioService.d.ts +200 -0
- package/dist/services/execution/GatewayTrioService.d.ts.map +1 -0
- package/dist/services/execution/GatewayTrioService.js +2492 -0
- package/dist/services/execution/QaApiRunner.d.ts +30 -0
- package/dist/services/execution/QaApiRunner.d.ts.map +1 -0
- package/dist/services/execution/QaApiRunner.js +881 -0
- package/dist/services/execution/QaFollowupService.d.ts +2 -0
- package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
- package/dist/services/execution/QaFollowupService.js +9 -2
- package/dist/services/execution/QaPlanValidator.d.ts +10 -0
- package/dist/services/execution/QaPlanValidator.d.ts.map +1 -0
- package/dist/services/execution/QaPlanValidator.js +128 -0
- package/dist/services/execution/QaProfileService.d.ts +27 -1
- package/dist/services/execution/QaProfileService.d.ts.map +1 -1
- package/dist/services/execution/QaProfileService.js +354 -7
- package/dist/services/execution/QaTasksService.d.ts +59 -1
- package/dist/services/execution/QaTasksService.d.ts.map +1 -1
- package/dist/services/execution/QaTasksService.js +3347 -318
- package/dist/services/execution/QaTestCommandBuilder.d.ts +51 -0
- package/dist/services/execution/QaTestCommandBuilder.d.ts.map +1 -0
- package/dist/services/execution/QaTestCommandBuilder.js +495 -0
- package/dist/services/execution/TaskSelectionService.d.ts +4 -2
- package/dist/services/execution/TaskSelectionService.d.ts.map +1 -1
- package/dist/services/execution/TaskSelectionService.js +144 -28
- package/dist/services/execution/TaskStateService.d.ts +19 -6
- package/dist/services/execution/TaskStateService.d.ts.map +1 -1
- package/dist/services/execution/TaskStateService.js +128 -13
- package/dist/services/execution/WorkOnTasksService.d.ts +32 -1
- package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
- package/dist/services/execution/WorkOnTasksService.js +4667 -722
- package/dist/services/jobs/JobInsightsService.d.ts +4 -0
- package/dist/services/jobs/JobInsightsService.d.ts.map +1 -1
- package/dist/services/jobs/JobInsightsService.js +51 -5
- package/dist/services/jobs/JobResumeService.d.ts.map +1 -1
- package/dist/services/jobs/JobResumeService.js +23 -10
- package/dist/services/jobs/JobService.d.ts +56 -4
- package/dist/services/jobs/JobService.d.ts.map +1 -1
- package/dist/services/jobs/JobService.js +232 -1
- package/dist/services/openapi/OpenApiService.d.ts +51 -0
- package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
- package/dist/services/openapi/OpenApiService.js +953 -106
- package/dist/services/planning/CreateTasksService.d.ts +21 -0
- package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
- package/dist/services/planning/CreateTasksService.js +569 -31
- package/dist/services/planning/RefineTasksService.d.ts +9 -0
- package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
- package/dist/services/planning/RefineTasksService.js +409 -59
- package/dist/services/review/CodeReviewService.d.ts +18 -0
- package/dist/services/review/CodeReviewService.d.ts.map +1 -1
- package/dist/services/review/CodeReviewService.js +1309 -167
- package/dist/services/review/ReviewNormalizer.d.ts +9 -0
- package/dist/services/review/ReviewNormalizer.d.ts.map +1 -0
- package/dist/services/review/ReviewNormalizer.js +147 -0
- package/dist/services/shared/AuthErrors.d.ts +3 -0
- package/dist/services/shared/AuthErrors.d.ts.map +1 -0
- package/dist/services/shared/AuthErrors.js +17 -0
- package/dist/services/shared/DocdexGuidance.d.ts +7 -0
- package/dist/services/shared/DocdexGuidance.d.ts.map +1 -0
- package/dist/services/shared/DocdexGuidance.js +12 -0
- package/dist/services/shared/ProjectGuidance.d.ts +17 -0
- package/dist/services/shared/ProjectGuidance.d.ts.map +1 -0
- package/dist/services/shared/ProjectGuidance.js +78 -0
- package/dist/services/system/ToolDenylist.d.ts +13 -0
- package/dist/services/system/ToolDenylist.d.ts.map +1 -0
- package/dist/services/system/ToolDenylist.js +85 -0
- package/dist/services/tasks/TaskCommentFormatter.d.ts +20 -0
- package/dist/services/tasks/TaskCommentFormatter.d.ts.map +1 -0
- package/dist/services/tasks/TaskCommentFormatter.js +54 -0
- package/dist/services/telemetry/TelemetryService.d.ts.map +1 -1
- package/dist/services/telemetry/TelemetryService.js +39 -7
- package/dist/workspace/WorkspaceManager.d.ts +26 -0
- package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
- package/dist/workspace/WorkspaceManager.js +206 -32
- package/package.json +6 -5
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { extractOpenApiPaths } from "../../../openapi/OpenApiService.js";
|
|
3
|
+
const isFenceLine = (line) => /^```|^~~~/.test(line.trim());
|
|
4
|
+
const buildIssue = (input) => ({
|
|
5
|
+
id: input.id,
|
|
6
|
+
gateId: "gate-pdr-interfaces-pipeline",
|
|
7
|
+
severity: "high",
|
|
8
|
+
category: "completeness",
|
|
9
|
+
artifact: "pdr",
|
|
10
|
+
message: input.message,
|
|
11
|
+
remediation: input.remediation,
|
|
12
|
+
location: input.path
|
|
13
|
+
? {
|
|
14
|
+
kind: "line_range",
|
|
15
|
+
path: input.path,
|
|
16
|
+
lineStart: input.line ?? 1,
|
|
17
|
+
lineEnd: input.line ?? 1,
|
|
18
|
+
excerpt: input.message,
|
|
19
|
+
}
|
|
20
|
+
: { kind: "heading", heading: "PDR", path: input.path },
|
|
21
|
+
metadata: input.metadata,
|
|
22
|
+
});
|
|
23
|
+
const extractSection = (lines, headingMatch) => {
|
|
24
|
+
let inFence = false;
|
|
25
|
+
let capture = false;
|
|
26
|
+
let startLine = 0;
|
|
27
|
+
const collected = [];
|
|
28
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
29
|
+
const line = lines[i] ?? "";
|
|
30
|
+
const trimmed = line.trim();
|
|
31
|
+
if (isFenceLine(trimmed)) {
|
|
32
|
+
inFence = !inFence;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (inFence)
|
|
36
|
+
continue;
|
|
37
|
+
const heading = trimmed.match(/^#{1,6}\s+(.*)$/);
|
|
38
|
+
if (heading) {
|
|
39
|
+
const title = heading[1]?.trim() ?? "";
|
|
40
|
+
if (headingMatch.test(title)) {
|
|
41
|
+
capture = true;
|
|
42
|
+
startLine = i + 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (capture)
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
if (capture) {
|
|
49
|
+
if (trimmed)
|
|
50
|
+
collected.push(trimmed);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!capture || collected.length === 0)
|
|
54
|
+
return capture ? { content: [], line: startLine } : undefined;
|
|
55
|
+
return { content: collected, line: startLine };
|
|
56
|
+
};
|
|
57
|
+
const hasApiPaths = (lines) => lines.some((line) => /\b(GET|POST|PUT|PATCH|DELETE)\b/i.test(line) || /\/[a-zA-Z0-9]/.test(line));
|
|
58
|
+
const mentionsLandingZones = (lines) => lines.some((line) => /landing zone|staging|raw|warehouse|lake/i.test(line));
|
|
59
|
+
const mentionsNormalizationOwner = (lines) => lines.some((line) => /owner|steward|responsible|ownership|govern/i.test(line));
|
|
60
|
+
const loadOpenApiPaths = async (records) => {
|
|
61
|
+
for (const record of records) {
|
|
62
|
+
try {
|
|
63
|
+
const raw = await fs.readFile(record.path, "utf8");
|
|
64
|
+
const { paths } = extractOpenApiPaths(raw);
|
|
65
|
+
if (paths.length > 0)
|
|
66
|
+
return paths;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// ignore parse issues here; OpenAPI gate handles validation.
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
};
|
|
74
|
+
export const runPdrInterfacesGate = async (input) => {
|
|
75
|
+
const pdr = input.artifacts.pdr;
|
|
76
|
+
if (!pdr) {
|
|
77
|
+
return {
|
|
78
|
+
gateId: "gate-pdr-interfaces-pipeline",
|
|
79
|
+
gateName: "PDR Interfaces & Pipeline",
|
|
80
|
+
status: "skipped",
|
|
81
|
+
issues: [],
|
|
82
|
+
notes: ["No PDR artifact available for interface/pipeline validation."],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const issues = [];
|
|
86
|
+
const notes = [];
|
|
87
|
+
try {
|
|
88
|
+
const content = await fs.readFile(pdr.path, "utf8");
|
|
89
|
+
const lines = content.split(/\r?\n/);
|
|
90
|
+
const interfacesSection = extractSection(lines, /interfaces?/i);
|
|
91
|
+
const pipelineSection = extractSection(lines, /pipeline|data flow/i);
|
|
92
|
+
if (!interfacesSection) {
|
|
93
|
+
issues.push(buildIssue({
|
|
94
|
+
id: "gate-pdr-interfaces-pipeline-missing-interfaces",
|
|
95
|
+
message: "PDR is missing an Interfaces section.",
|
|
96
|
+
remediation: "Add an Interfaces section listing system interfaces and APIs.",
|
|
97
|
+
path: pdr.path,
|
|
98
|
+
metadata: { issueType: "missing_interfaces" },
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
if (!pipelineSection) {
|
|
102
|
+
issues.push(buildIssue({
|
|
103
|
+
id: "gate-pdr-interfaces-pipeline-missing-pipeline",
|
|
104
|
+
message: "PDR is missing a data pipeline model section.",
|
|
105
|
+
remediation: "Add a Pipeline/Data Flow section describing ingestion, normalization, and storage.",
|
|
106
|
+
path: pdr.path,
|
|
107
|
+
metadata: { issueType: "missing_pipeline" },
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
if (interfacesSection && input.artifacts.openapi.length > 0) {
|
|
111
|
+
const openapiPaths = await loadOpenApiPaths(input.artifacts.openapi);
|
|
112
|
+
const hasPaths = hasApiPaths(interfacesSection.content);
|
|
113
|
+
if (openapiPaths.length > 0 && !hasPaths) {
|
|
114
|
+
issues.push(buildIssue({
|
|
115
|
+
id: "gate-pdr-interfaces-pipeline-openapi-mismatch",
|
|
116
|
+
message: "PDR interfaces section does not list any API paths while OpenAPI exists.",
|
|
117
|
+
remediation: "List the primary API endpoints in the PDR Interfaces section.",
|
|
118
|
+
path: pdr.path,
|
|
119
|
+
line: interfacesSection.line,
|
|
120
|
+
metadata: { issueType: "interfaces_missing_paths", openapiCount: openapiPaths.length },
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (pipelineSection) {
|
|
125
|
+
if (!mentionsLandingZones(pipelineSection.content)) {
|
|
126
|
+
issues.push(buildIssue({
|
|
127
|
+
id: "gate-pdr-interfaces-pipeline-missing-landing-zones",
|
|
128
|
+
message: "Pipeline section does not describe data landing zones or storage tiers.",
|
|
129
|
+
remediation: "Include raw/staging/warehouse landing zones in the pipeline description.",
|
|
130
|
+
path: pdr.path,
|
|
131
|
+
line: pipelineSection.line,
|
|
132
|
+
metadata: { issueType: "missing_landing_zones" },
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
if (!mentionsNormalizationOwner(pipelineSection.content)) {
|
|
136
|
+
issues.push(buildIssue({
|
|
137
|
+
id: "gate-pdr-interfaces-pipeline-missing-ownership",
|
|
138
|
+
message: "Pipeline section does not name ownership for normalization rules.",
|
|
139
|
+
remediation: "Specify who owns or governs normalization rules in the pipeline model.",
|
|
140
|
+
path: pdr.path,
|
|
141
|
+
line: pipelineSection.line,
|
|
142
|
+
metadata: { issueType: "missing_ownership" },
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
notes.push(`Unable to read PDR ${pdr.path}: ${error.message ?? String(error)}`);
|
|
149
|
+
}
|
|
150
|
+
const status = issues.length === 0 ? "pass" : "fail";
|
|
151
|
+
return {
|
|
152
|
+
gateId: "gate-pdr-interfaces-pipeline",
|
|
153
|
+
gateName: "PDR Interfaces & Pipeline",
|
|
154
|
+
status,
|
|
155
|
+
issues,
|
|
156
|
+
notes: notes.length ? notes : undefined,
|
|
157
|
+
metadata: { issueCount: issues.length },
|
|
158
|
+
};
|
|
159
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DocgenArtifactInventory } from "../../DocgenRunContext.js";
|
|
2
|
+
import { ReviewGateResult } from "../ReviewTypes.js";
|
|
3
|
+
export interface PdrOpenQuestionsGateInput {
|
|
4
|
+
artifacts: DocgenArtifactInventory;
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const runPdrOpenQuestionsGate: (input: PdrOpenQuestionsGateInput) => Promise<ReviewGateResult>;
|
|
8
|
+
//# sourceMappingURL=PdrOpenQuestionsGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PdrOpenQuestionsGate.d.ts","sourceRoot":"","sources":["../../../../../src/services/docs/review/gates/PdrOpenQuestionsGate.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAe,MAAM,mBAAmB,CAAC;AAElE,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,uBAAuB,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;CAClB;AAgFD,eAAO,MAAM,uBAAuB,GAClC,OAAO,yBAAyB,KAC/B,OAAO,CAAC,gBAAgB,CA+D1B,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { loadGlossary } from "../Glossary.js";
|
|
3
|
+
const GENERIC_QUESTION_PATTERNS = [
|
|
4
|
+
/what is the timeline/i,
|
|
5
|
+
/who are the stakeholders/i,
|
|
6
|
+
/what are the risks/i,
|
|
7
|
+
/what is the scope/i,
|
|
8
|
+
/what are the requirements/i,
|
|
9
|
+
/how will we measure success/i,
|
|
10
|
+
/what is the budget/i,
|
|
11
|
+
/what are the next steps/i,
|
|
12
|
+
];
|
|
13
|
+
const isFenceLine = (line) => /^```|^~~~/.test(line.trim());
|
|
14
|
+
const buildIssue = (input) => ({
|
|
15
|
+
id: input.id,
|
|
16
|
+
gateId: "gate-pdr-open-questions-quality",
|
|
17
|
+
severity: "medium",
|
|
18
|
+
category: "open_questions",
|
|
19
|
+
artifact: "pdr",
|
|
20
|
+
message: input.message,
|
|
21
|
+
remediation: input.remediation,
|
|
22
|
+
location: {
|
|
23
|
+
kind: "line_range",
|
|
24
|
+
path: input.record.path,
|
|
25
|
+
lineStart: input.line,
|
|
26
|
+
lineEnd: input.line,
|
|
27
|
+
excerpt: input.excerpt,
|
|
28
|
+
},
|
|
29
|
+
metadata: input.metadata,
|
|
30
|
+
});
|
|
31
|
+
const extractOpenQuestionLines = (lines) => {
|
|
32
|
+
const results = [];
|
|
33
|
+
let inFence = false;
|
|
34
|
+
let inSection = false;
|
|
35
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
36
|
+
const line = lines[i] ?? "";
|
|
37
|
+
const trimmed = line.trim();
|
|
38
|
+
if (!trimmed)
|
|
39
|
+
continue;
|
|
40
|
+
if (isFenceLine(trimmed)) {
|
|
41
|
+
inFence = !inFence;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (inFence)
|
|
45
|
+
continue;
|
|
46
|
+
const heading = trimmed.match(/^#{1,6}\s+(.*)$/);
|
|
47
|
+
if (heading) {
|
|
48
|
+
const title = heading[1]?.trim() ?? "";
|
|
49
|
+
if (/open questions?|open issues?|unresolved questions?/i.test(title)) {
|
|
50
|
+
inSection = true;
|
|
51
|
+
}
|
|
52
|
+
else if (inSection) {
|
|
53
|
+
inSection = false;
|
|
54
|
+
}
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (!inSection)
|
|
58
|
+
continue;
|
|
59
|
+
const question = trimmed.replace(/^[-*+]\s+/, "").replace(/^\d+\.\s+/, "");
|
|
60
|
+
if (!question)
|
|
61
|
+
continue;
|
|
62
|
+
results.push({ text: question, line: i + 1 });
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
};
|
|
66
|
+
const containsDomainTerm = (text, domainTerms) => {
|
|
67
|
+
const lower = text.toLowerCase();
|
|
68
|
+
return domainTerms.some((term) => term && lower.includes(term));
|
|
69
|
+
};
|
|
70
|
+
export const runPdrOpenQuestionsGate = async (input) => {
|
|
71
|
+
if (!input.enabled) {
|
|
72
|
+
return {
|
|
73
|
+
gateId: "gate-pdr-open-questions-quality",
|
|
74
|
+
gateName: "PDR Open Questions Quality",
|
|
75
|
+
status: "skipped",
|
|
76
|
+
issues: [],
|
|
77
|
+
notes: ["Open question quality gate disabled."],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const pdr = input.artifacts.pdr;
|
|
81
|
+
if (!pdr) {
|
|
82
|
+
return {
|
|
83
|
+
gateId: "gate-pdr-open-questions-quality",
|
|
84
|
+
gateName: "PDR Open Questions Quality",
|
|
85
|
+
status: "skipped",
|
|
86
|
+
issues: [],
|
|
87
|
+
notes: ["No PDR artifact available for open question quality checks."],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const issues = [];
|
|
91
|
+
const notes = [];
|
|
92
|
+
const glossary = loadGlossary();
|
|
93
|
+
const domainTerms = glossary.entries
|
|
94
|
+
.flatMap((entry) => [entry.term, ...(entry.aliases ?? [])])
|
|
95
|
+
.map((term) => term.toLowerCase());
|
|
96
|
+
try {
|
|
97
|
+
const content = await fs.readFile(pdr.path, "utf8");
|
|
98
|
+
const lines = content.split(/\r?\n/);
|
|
99
|
+
const questions = extractOpenQuestionLines(lines);
|
|
100
|
+
for (const question of questions) {
|
|
101
|
+
const isGeneric = GENERIC_QUESTION_PATTERNS.some((pattern) => pattern.test(question.text));
|
|
102
|
+
if (!isGeneric)
|
|
103
|
+
continue;
|
|
104
|
+
if (containsDomainTerm(question.text, domainTerms))
|
|
105
|
+
continue;
|
|
106
|
+
issues.push(buildIssue({
|
|
107
|
+
id: `gate-pdr-open-questions-quality-${question.line}`,
|
|
108
|
+
message: `Generic open question lacks project-specific context: ${question.text}`,
|
|
109
|
+
remediation: "Replace with a question tied to the project domain (use glossary terms).",
|
|
110
|
+
record: pdr,
|
|
111
|
+
line: question.line,
|
|
112
|
+
excerpt: question.text,
|
|
113
|
+
metadata: { issueType: "generic_question" },
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
notes.push(`Unable to read PDR ${pdr.path}: ${error.message ?? String(error)}`);
|
|
119
|
+
}
|
|
120
|
+
const status = issues.length === 0 ? "pass" : "fail";
|
|
121
|
+
return {
|
|
122
|
+
gateId: "gate-pdr-open-questions-quality",
|
|
123
|
+
gateName: "PDR Open Questions Quality",
|
|
124
|
+
status,
|
|
125
|
+
issues,
|
|
126
|
+
notes: notes.length ? notes : undefined,
|
|
127
|
+
metadata: { issueCount: issues.length },
|
|
128
|
+
};
|
|
129
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DocgenArtifactInventory } from "../../DocgenRunContext.js";
|
|
2
|
+
import { ReviewGateResult } from "../ReviewTypes.js";
|
|
3
|
+
export interface PdrOwnershipGateInput {
|
|
4
|
+
artifacts: DocgenArtifactInventory;
|
|
5
|
+
}
|
|
6
|
+
export declare const runPdrOwnershipGate: (input: PdrOwnershipGateInput) => Promise<ReviewGateResult>;
|
|
7
|
+
//# sourceMappingURL=PdrOwnershipGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PdrOwnershipGate.d.ts","sourceRoot":"","sources":["../../../../../src/services/docs/review/gates/PdrOwnershipGate.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAe,MAAM,mBAAmB,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,uBAAuB,CAAC;CACpC;AAuFD,eAAO,MAAM,mBAAmB,GAC9B,OAAO,qBAAqB,KAC3B,OAAO,CAAC,gBAAgB,CAoH1B,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { getGlossaryEntry, loadGlossary } from "../Glossary.js";
|
|
3
|
+
const isFenceLine = (line) => /^```|^~~~/.test(line.trim());
|
|
4
|
+
const extractSection = (lines, headingMatch) => {
|
|
5
|
+
let inFence = false;
|
|
6
|
+
let capture = false;
|
|
7
|
+
let startLine = 0;
|
|
8
|
+
const collected = [];
|
|
9
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
10
|
+
const line = lines[i] ?? "";
|
|
11
|
+
const trimmed = line.trim();
|
|
12
|
+
if (isFenceLine(trimmed)) {
|
|
13
|
+
inFence = !inFence;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
if (inFence)
|
|
17
|
+
continue;
|
|
18
|
+
const heading = trimmed.match(/^#{1,6}\s+(.*)$/);
|
|
19
|
+
if (heading) {
|
|
20
|
+
const title = heading[1]?.trim() ?? "";
|
|
21
|
+
if (headingMatch.test(title)) {
|
|
22
|
+
capture = true;
|
|
23
|
+
startLine = i + 1;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (capture)
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
if (capture && trimmed)
|
|
30
|
+
collected.push(trimmed);
|
|
31
|
+
}
|
|
32
|
+
if (!capture)
|
|
33
|
+
return undefined;
|
|
34
|
+
return { content: collected, line: startLine };
|
|
35
|
+
};
|
|
36
|
+
const buildIssue = (input) => ({
|
|
37
|
+
id: input.id,
|
|
38
|
+
gateId: "gate-pdr-ownership-consent-flow",
|
|
39
|
+
severity: "high",
|
|
40
|
+
category: "completeness",
|
|
41
|
+
artifact: "pdr",
|
|
42
|
+
message: input.message,
|
|
43
|
+
remediation: input.remediation,
|
|
44
|
+
location: input.path
|
|
45
|
+
? {
|
|
46
|
+
kind: "line_range",
|
|
47
|
+
path: input.path,
|
|
48
|
+
lineStart: input.line ?? 1,
|
|
49
|
+
lineEnd: input.line ?? 1,
|
|
50
|
+
excerpt: input.message,
|
|
51
|
+
}
|
|
52
|
+
: { kind: "heading", heading: "PDR", path: input.path },
|
|
53
|
+
metadata: input.metadata,
|
|
54
|
+
});
|
|
55
|
+
const mentionsOwnership = (lines) => lines.some((line) => /owner|steward|responsible|approval/i.test(line));
|
|
56
|
+
const mentionsCachePolicy = (lines) => lines.some((line) => /policy|cache rules?|governance|approval/i.test(line));
|
|
57
|
+
const mentionsConsentTtl = (lines) => lines.some((line) => /ttl|time[- ]to[- ]live|expiration|expiry/i.test(line));
|
|
58
|
+
const mentionsConsentRevoke = (lines) => lines.some((line) => /revoke|revocation|invalidate|rotation/i.test(line));
|
|
59
|
+
const mentionsCanonicalConsentToken = (lines, canonical) => lines.some((line) => line.toLowerCase().includes(canonical.toLowerCase()));
|
|
60
|
+
const mentionsAlias = (lines, aliases) => {
|
|
61
|
+
for (const alias of aliases) {
|
|
62
|
+
if (lines.some((line) => line.toLowerCase().includes(alias.toLowerCase()))) {
|
|
63
|
+
return alias;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
};
|
|
68
|
+
export const runPdrOwnershipGate = async (input) => {
|
|
69
|
+
const pdr = input.artifacts.pdr;
|
|
70
|
+
if (!pdr) {
|
|
71
|
+
return {
|
|
72
|
+
gateId: "gate-pdr-ownership-consent-flow",
|
|
73
|
+
gateName: "PDR Ownership & Consent Flow",
|
|
74
|
+
status: "skipped",
|
|
75
|
+
issues: [],
|
|
76
|
+
notes: ["No PDR artifact available for ownership/consent validation."],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const issues = [];
|
|
80
|
+
const notes = [];
|
|
81
|
+
const glossary = loadGlossary();
|
|
82
|
+
const consentEntry = getGlossaryEntry("consent_token", glossary);
|
|
83
|
+
const canonicalConsent = consentEntry?.term ?? "consent token";
|
|
84
|
+
const consentAliases = consentEntry?.aliases ?? [];
|
|
85
|
+
try {
|
|
86
|
+
const content = await fs.readFile(pdr.path, "utf8");
|
|
87
|
+
const lines = content.split(/\r?\n/);
|
|
88
|
+
const ownershipSection = extractSection(lines, /ownership|governance|policy/i);
|
|
89
|
+
const consentSection = extractSection(lines, /consent|token issuance|installation/i);
|
|
90
|
+
if (!ownershipSection) {
|
|
91
|
+
issues.push(buildIssue({
|
|
92
|
+
id: "gate-pdr-ownership-consent-flow-missing-ownership",
|
|
93
|
+
message: "PDR is missing an ownership/governance section.",
|
|
94
|
+
remediation: "Add a section stating ownership of policy changes and cache rules.",
|
|
95
|
+
path: pdr.path,
|
|
96
|
+
metadata: { issueType: "missing_ownership_section" },
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
if (!mentionsOwnership(ownershipSection.content) || !mentionsCachePolicy(ownershipSection.content)) {
|
|
101
|
+
issues.push(buildIssue({
|
|
102
|
+
id: "gate-pdr-ownership-consent-flow-vague-ownership",
|
|
103
|
+
message: "Ownership section does not specify policy/cache rule owners.",
|
|
104
|
+
remediation: "Name the policy owner responsible for cache rules and approvals.",
|
|
105
|
+
path: pdr.path,
|
|
106
|
+
line: ownershipSection.line,
|
|
107
|
+
metadata: { issueType: "vague_ownership" },
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (!consentSection) {
|
|
112
|
+
issues.push(buildIssue({
|
|
113
|
+
id: "gate-pdr-ownership-consent-flow-missing-consent",
|
|
114
|
+
message: "PDR is missing a consent flow section.",
|
|
115
|
+
remediation: "Add a consent flow summary covering issuance, TTL, and revocation.",
|
|
116
|
+
path: pdr.path,
|
|
117
|
+
metadata: { issueType: "missing_consent_flow" },
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
if (!mentionsConsentTtl(consentSection.content)) {
|
|
122
|
+
issues.push(buildIssue({
|
|
123
|
+
id: "gate-pdr-ownership-consent-flow-missing-ttl",
|
|
124
|
+
message: "Consent flow section does not mention token TTL/expiration.",
|
|
125
|
+
remediation: "Specify TTL or expiration behavior for the consent token.",
|
|
126
|
+
path: pdr.path,
|
|
127
|
+
line: consentSection.line,
|
|
128
|
+
metadata: { issueType: "missing_ttl" },
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
if (!mentionsConsentRevoke(consentSection.content)) {
|
|
132
|
+
issues.push(buildIssue({
|
|
133
|
+
id: "gate-pdr-ownership-consent-flow-missing-revoke",
|
|
134
|
+
message: "Consent flow section does not mention revocation behavior.",
|
|
135
|
+
remediation: "Describe how consent tokens can be revoked or invalidated.",
|
|
136
|
+
path: pdr.path,
|
|
137
|
+
line: consentSection.line,
|
|
138
|
+
metadata: { issueType: "missing_revoke" },
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
if (consentEntry) {
|
|
142
|
+
const usesCanonical = mentionsCanonicalConsentToken(consentSection.content, canonicalConsent);
|
|
143
|
+
const alias = mentionsAlias(consentSection.content, consentAliases);
|
|
144
|
+
if (!usesCanonical && alias) {
|
|
145
|
+
issues.push(buildIssue({
|
|
146
|
+
id: "gate-pdr-ownership-consent-flow-noncanonical-term",
|
|
147
|
+
message: `Consent flow uses non-canonical term "${alias}" instead of "${canonicalConsent}".`,
|
|
148
|
+
remediation: `Replace "${alias}" with "${canonicalConsent}" to align with glossary terms.`,
|
|
149
|
+
path: pdr.path,
|
|
150
|
+
line: consentSection.line,
|
|
151
|
+
metadata: { issueType: "noncanonical_term", alias, canonicalConsent },
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
notes.push(`Unable to read PDR ${pdr.path}: ${error.message ?? String(error)}`);
|
|
159
|
+
}
|
|
160
|
+
const status = issues.length === 0 ? "pass" : "fail";
|
|
161
|
+
return {
|
|
162
|
+
gateId: "gate-pdr-ownership-consent-flow",
|
|
163
|
+
gateName: "PDR Ownership & Consent Flow",
|
|
164
|
+
status,
|
|
165
|
+
issues,
|
|
166
|
+
notes: notes.length ? notes : undefined,
|
|
167
|
+
metadata: { issueCount: issues.length },
|
|
168
|
+
};
|
|
169
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { DocgenArtifactInventory } from "../../DocgenRunContext.js";
|
|
2
|
+
import { ReviewGateResult } from "../ReviewTypes.js";
|
|
3
|
+
export type PlaceholderArtifactType = "placeholder" | "template_artifact";
|
|
4
|
+
export interface PlaceholderArtifactGateInput {
|
|
5
|
+
artifacts: DocgenArtifactInventory;
|
|
6
|
+
allowlist?: string[];
|
|
7
|
+
denylist?: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare const runPlaceholderArtifactGate: (input: PlaceholderArtifactGateInput) => Promise<ReviewGateResult>;
|
|
10
|
+
//# sourceMappingURL=PlaceholderArtifactGate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlaceholderArtifactGate.d.ts","sourceRoot":"","sources":["../../../../../src/services/docs/review/gates/PlaceholderArtifactGate.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAA+B,MAAM,mBAAmB,CAAC;AAElF,MAAM,MAAM,uBAAuB,GAAG,aAAa,GAAG,mBAAmB,CAAC;AAE1E,MAAM,WAAW,4BAA4B;IAC3C,SAAS,EAAE,uBAAuB,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AA8LD,eAAO,MAAM,0BAA0B,GACrC,OAAO,4BAA4B,KAClC,OAAO,CAAC,gBAAgB,CAmG1B,CAAC"}
|