@mcoda/core 0.1.35 → 0.1.36
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/prompts/PdrPrompts.js +1 -1
- package/dist/services/planning/CreateTasksService.d.ts +37 -0
- package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
- package/dist/services/planning/CreateTasksService.js +1739 -148
- package/dist/services/planning/SdsPreflightService.js +6 -6
- package/dist/services/planning/TaskSufficiencyService.d.ts +16 -0
- package/dist/services/planning/TaskSufficiencyService.d.ts.map +1 -1
- package/dist/services/planning/TaskSufficiencyService.js +215 -17
- package/package.json +6 -6
|
@@ -566,17 +566,17 @@ export class SdsPreflightService {
|
|
|
566
566
|
if (technologies.length > 0) {
|
|
567
567
|
return [
|
|
568
568
|
"## Technology Stack",
|
|
569
|
-
`-
|
|
570
|
-
"-
|
|
571
|
-
"-
|
|
569
|
+
`- Observed source-backed technology signals: ${technologies.join(", ")}.`,
|
|
570
|
+
"- Keep the chosen stack explicit in the source docs for runtime, language, persistence, interface, and tooling layers.",
|
|
571
|
+
"- Record alternatives only when the source docs name them; do not invent default stack choices during preflight.",
|
|
572
572
|
"",
|
|
573
573
|
];
|
|
574
574
|
}
|
|
575
575
|
return [
|
|
576
576
|
"## Technology Stack",
|
|
577
|
-
"-
|
|
578
|
-
"-
|
|
579
|
-
"-
|
|
577
|
+
"- Source docs do not yet make the technology stack explicit.",
|
|
578
|
+
"- Record runtime, language, persistence, interface, and tooling decisions explicitly in the source docs without assuming defaults.",
|
|
579
|
+
"- Preflight must not invent a chosen stack baseline when the source is silent.",
|
|
580
580
|
"",
|
|
581
581
|
];
|
|
582
582
|
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { WorkspaceRepository } from "@mcoda/db";
|
|
2
2
|
import { WorkspaceResolution } from "../../workspace/WorkspaceManager.js";
|
|
3
3
|
import { JobService } from "../jobs/JobService.js";
|
|
4
|
+
export interface TaskSufficiencyPlannedGapBundle {
|
|
5
|
+
kind: "section" | "folder" | "mixed";
|
|
6
|
+
domain: string;
|
|
7
|
+
values: string[];
|
|
8
|
+
anchors: string[];
|
|
9
|
+
implementationTargets: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface TaskSufficiencyUnresolvedBundle {
|
|
12
|
+
kind: "section" | "folder" | "mixed";
|
|
13
|
+
domain: string;
|
|
14
|
+
values: string[];
|
|
15
|
+
anchors: string[];
|
|
16
|
+
}
|
|
4
17
|
export interface TaskSufficiencyAuditRequest {
|
|
5
18
|
workspace: WorkspaceResolution;
|
|
6
19
|
projectKey: string;
|
|
@@ -16,6 +29,7 @@ export interface TaskSufficiencyAuditIteration {
|
|
|
16
29
|
totalSignals: number;
|
|
17
30
|
missingSectionCount: number;
|
|
18
31
|
missingFolderCount: number;
|
|
32
|
+
unresolvedBundleCount: number;
|
|
19
33
|
createdTaskKeys: string[];
|
|
20
34
|
}
|
|
21
35
|
export interface TaskSufficiencyAuditResult {
|
|
@@ -38,6 +52,8 @@ export interface TaskSufficiencyAuditResult {
|
|
|
38
52
|
folders: number;
|
|
39
53
|
total: number;
|
|
40
54
|
};
|
|
55
|
+
plannedGapBundles: TaskSufficiencyPlannedGapBundle[];
|
|
56
|
+
unresolvedBundles: TaskSufficiencyUnresolvedBundle[];
|
|
41
57
|
iterations: TaskSufficiencyAuditIteration[];
|
|
42
58
|
reportPath: string;
|
|
43
59
|
reportHistoryPath?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskSufficiencyService.d.ts","sourceRoot":"","sources":["../../../src/services/planning/TaskSufficiencyService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAiC,MAAM,WAAW,CAAC;AAE/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"TaskSufficiencyService.d.ts","sourceRoot":"","sources":["../../../src/services/planning/TaskSufficiencyService.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,8 +20,106 @@ const sdsFilenamePattern = /(sds|software[-_ ]design|system[-_ ]design|design[-_
|
|
|
20
20
|
const sdsContentPattern = /(software design specification|system design specification|^#\s*sds\b)/im;
|
|
21
21
|
const supportRootSegments = new Set(["docs", "fixtures", "policies", "policy", "runbooks", "pdr", "rfp", "sds"]);
|
|
22
22
|
const headingNoiseTokens = new Set(["and", "for", "from", "into", "the", "with"]);
|
|
23
|
+
const runtimePathSegments = new Set([
|
|
24
|
+
"api",
|
|
25
|
+
"app",
|
|
26
|
+
"apps",
|
|
27
|
+
"bin",
|
|
28
|
+
"cli",
|
|
29
|
+
"client",
|
|
30
|
+
"clients",
|
|
31
|
+
"cmd",
|
|
32
|
+
"command",
|
|
33
|
+
"commands",
|
|
34
|
+
"engine",
|
|
35
|
+
"engines",
|
|
36
|
+
"feature",
|
|
37
|
+
"features",
|
|
38
|
+
"gateway",
|
|
39
|
+
"gateways",
|
|
40
|
+
"handler",
|
|
41
|
+
"handlers",
|
|
42
|
+
"module",
|
|
43
|
+
"modules",
|
|
44
|
+
"pipeline",
|
|
45
|
+
"pipelines",
|
|
46
|
+
"processor",
|
|
47
|
+
"processors",
|
|
48
|
+
"route",
|
|
49
|
+
"routes",
|
|
50
|
+
"server",
|
|
51
|
+
"servers",
|
|
52
|
+
"service",
|
|
53
|
+
"services",
|
|
54
|
+
"src",
|
|
55
|
+
"ui",
|
|
56
|
+
"web",
|
|
57
|
+
"worker",
|
|
58
|
+
"workers",
|
|
59
|
+
]);
|
|
60
|
+
const interfacePathSegments = new Set([
|
|
61
|
+
"contract",
|
|
62
|
+
"contracts",
|
|
63
|
+
"dto",
|
|
64
|
+
"dtos",
|
|
65
|
+
"interface",
|
|
66
|
+
"interfaces",
|
|
67
|
+
"policy",
|
|
68
|
+
"policies",
|
|
69
|
+
"proto",
|
|
70
|
+
"protocol",
|
|
71
|
+
"protocols",
|
|
72
|
+
"schema",
|
|
73
|
+
"schemas",
|
|
74
|
+
"spec",
|
|
75
|
+
"specs",
|
|
76
|
+
"type",
|
|
77
|
+
"types",
|
|
78
|
+
]);
|
|
79
|
+
const dataPathSegments = new Set([
|
|
80
|
+
"cache",
|
|
81
|
+
"caches",
|
|
82
|
+
"data",
|
|
83
|
+
"db",
|
|
84
|
+
"ledger",
|
|
85
|
+
"migration",
|
|
86
|
+
"migrations",
|
|
87
|
+
"model",
|
|
88
|
+
"models",
|
|
89
|
+
"persistence",
|
|
90
|
+
"repository",
|
|
91
|
+
"repositories",
|
|
92
|
+
"storage",
|
|
93
|
+
]);
|
|
94
|
+
const testPathSegments = new Set(["acceptance", "e2e", "integration", "spec", "specs", "test", "tests"]);
|
|
95
|
+
const opsPathSegments = new Set([
|
|
96
|
+
"deploy",
|
|
97
|
+
"deployment",
|
|
98
|
+
"deployments",
|
|
99
|
+
"helm",
|
|
100
|
+
"infra",
|
|
101
|
+
"k8s",
|
|
102
|
+
"ops",
|
|
103
|
+
"operation",
|
|
104
|
+
"operations",
|
|
105
|
+
"runbook",
|
|
106
|
+
"runbooks",
|
|
107
|
+
"script",
|
|
108
|
+
"scripts",
|
|
109
|
+
"systemd",
|
|
110
|
+
"terraform",
|
|
111
|
+
]);
|
|
112
|
+
const manifestBasenamePattern = /^(package\.json|pnpm-workspace\.yaml|pnpm-lock\.yaml|turbo\.json|tsconfig(?:\.[^.]+)?\.json|cargo\.toml|pyproject\.toml|go\.mod|go\.sum|pom\.xml|build\.gradle(?:\.kts)?|settings\.gradle(?:\.kts)?|requirements\.txt|poetry\.lock|foundry\.toml|hardhat\.config\.[^.]+)$/i;
|
|
113
|
+
const serviceArtifactBasenamePattern = /(?:\.service|\.socket|\.timer|(?:^|[.-])compose\.(?:ya?ml|json)$|docker-compose\.(?:ya?ml|json)$)$/i;
|
|
23
114
|
const normalizeText = (value) => normalizeCoverageText(value);
|
|
24
115
|
const normalizeAnchor = normalizeCoverageAnchor;
|
|
116
|
+
const toPlannedGapBundle = (entry) => ({
|
|
117
|
+
kind: entry.bundle.kind,
|
|
118
|
+
domain: entry.bundle.domain,
|
|
119
|
+
values: entry.bundle.values,
|
|
120
|
+
anchors: entry.bundle.normalizedAnchors,
|
|
121
|
+
implementationTargets: entry.implementationTargets,
|
|
122
|
+
});
|
|
25
123
|
const unique = (items) => Array.from(new Set(items.filter(Boolean)));
|
|
26
124
|
const tokenizeCoverageSignal = (value) => unique(normalizeCoverageText(value)
|
|
27
125
|
.split(/\s+/)
|
|
@@ -70,6 +168,44 @@ const implementationRootWeight = (target) => {
|
|
|
70
168
|
}
|
|
71
169
|
return score;
|
|
72
170
|
};
|
|
171
|
+
const classifyImplementationTarget = (target) => {
|
|
172
|
+
const normalized = normalizeFolderEntry(target)?.toLowerCase() ?? normalizeText(target);
|
|
173
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
174
|
+
const basename = segments[segments.length - 1] ?? normalized;
|
|
175
|
+
const isServiceArtifact = serviceArtifactBasenamePattern.test(basename);
|
|
176
|
+
if (segments.some((segment) => supportRootSegments.has(segment))) {
|
|
177
|
+
return { normalized, basename, segments, kind: "doc", isServiceArtifact };
|
|
178
|
+
}
|
|
179
|
+
if (manifestBasenamePattern.test(basename) || isServiceArtifact) {
|
|
180
|
+
return { normalized, basename, segments, kind: "manifest", isServiceArtifact };
|
|
181
|
+
}
|
|
182
|
+
if (segments.some((segment) => testPathSegments.has(segment))) {
|
|
183
|
+
return { normalized, basename, segments, kind: "test", isServiceArtifact };
|
|
184
|
+
}
|
|
185
|
+
if (segments.some((segment) => opsPathSegments.has(segment))) {
|
|
186
|
+
return { normalized, basename, segments, kind: "ops", isServiceArtifact };
|
|
187
|
+
}
|
|
188
|
+
if (segments.some((segment) => interfacePathSegments.has(segment))) {
|
|
189
|
+
return { normalized, basename, segments, kind: "interface", isServiceArtifact };
|
|
190
|
+
}
|
|
191
|
+
if (segments.some((segment) => dataPathSegments.has(segment))) {
|
|
192
|
+
return { normalized, basename, segments, kind: "data", isServiceArtifact };
|
|
193
|
+
}
|
|
194
|
+
if (segments.some((segment) => runtimePathSegments.has(segment))) {
|
|
195
|
+
return { normalized, basename, segments, kind: "runtime", isServiceArtifact };
|
|
196
|
+
}
|
|
197
|
+
return { normalized, basename, segments, kind: "unknown", isServiceArtifact };
|
|
198
|
+
};
|
|
199
|
+
const deriveSemanticTargetNeeds = (bundle) => {
|
|
200
|
+
const corpus = normalizeText([bundle.domain, ...bundle.values].join(" "));
|
|
201
|
+
return {
|
|
202
|
+
wantsVerification: /\b(verify|verification|acceptance|scenario|suite|test|tests|quality|gate|matrix)\b/.test(corpus),
|
|
203
|
+
wantsOps: /\b(rollback|recovery|replay|restart|rotation|drill|runbook|failover|release|startup|deploy|deployment|operations?|incident|compromise)\b/.test(corpus),
|
|
204
|
+
wantsInterface: /\b(contract|interface|schema|policy|policies|oracle|gateway|api|protocol)\b/.test(corpus),
|
|
205
|
+
wantsData: /\b(data|storage|cache|db|database|ledger|pipeline|metering|pricing)\b/.test(corpus),
|
|
206
|
+
wantsProvider: /\b(provider|providers|gateway|gateways|rpc|adapter|adapters|sanctions|moderation|kyt)\b/.test(corpus),
|
|
207
|
+
};
|
|
208
|
+
};
|
|
73
209
|
const inferImplementationTargets = (bundle, availablePaths, limit = 3) => {
|
|
74
210
|
const explicitTargets = bundle.values
|
|
75
211
|
.map((value) => normalizeFolderEntry(value))
|
|
@@ -79,24 +215,61 @@ const inferImplementationTargets = (bundle, availablePaths, limit = 3) => {
|
|
|
79
215
|
}
|
|
80
216
|
const anchorTokens = tokenizeCoverageSignal(normalizeText([bundle.domain, ...bundle.values].join(" ")).replace(/[-/]+/g, " "));
|
|
81
217
|
const domainNeedle = bundle.domain.replace(/[-_]+/g, " ").trim();
|
|
218
|
+
const targetNeeds = deriveSemanticTargetNeeds(bundle);
|
|
82
219
|
const scored = availablePaths
|
|
83
220
|
.map((candidate) => normalizeFolderEntry(candidate))
|
|
84
221
|
.filter((candidate) => Boolean(candidate))
|
|
85
222
|
.filter((candidate) => bundle.kind === "folder" || !candidate.startsWith("docs/"))
|
|
86
223
|
.map((candidate) => {
|
|
87
|
-
const
|
|
224
|
+
const classification = classifyImplementationTarget(candidate);
|
|
225
|
+
const normalizedCandidate = classification.normalized.replace(/\//g, " ");
|
|
88
226
|
const overlap = anchorTokens.filter((token) => normalizedCandidate.includes(token)).length;
|
|
89
227
|
const hasDomainMatch = domainNeedle.length > 0 && normalizedCandidate.includes(domainNeedle);
|
|
90
|
-
const
|
|
228
|
+
const semanticEvidence = (targetNeeds.wantsVerification && classification.kind === "test") ||
|
|
229
|
+
(targetNeeds.wantsOps && classification.kind === "ops") ||
|
|
230
|
+
(targetNeeds.wantsInterface && classification.kind === "interface") ||
|
|
231
|
+
(targetNeeds.wantsData && classification.kind === "data") ||
|
|
232
|
+
(targetNeeds.wantsProvider &&
|
|
233
|
+
(classification.kind === "interface" ||
|
|
234
|
+
classification.kind === "runtime" ||
|
|
235
|
+
classification.kind === "ops"));
|
|
236
|
+
const hasEvidence = overlap > 0 || hasDomainMatch || semanticEvidence;
|
|
91
237
|
const score = implementationRootWeight(candidate) +
|
|
92
238
|
overlap * 20 +
|
|
93
239
|
(hasDomainMatch ? 15 : 0) -
|
|
94
|
-
(candidate.startsWith("docs/") ? 25 : 0)
|
|
95
|
-
|
|
240
|
+
(candidate.startsWith("docs/") ? 25 : 0) +
|
|
241
|
+
(targetNeeds.wantsVerification && classification.kind === "test" ? 45 : 0) +
|
|
242
|
+
(targetNeeds.wantsOps && classification.kind === "ops" ? 60 : 0) +
|
|
243
|
+
(targetNeeds.wantsInterface && classification.kind === "interface" ? 55 : 0) +
|
|
244
|
+
(targetNeeds.wantsData && classification.kind === "data" ? 55 : 0) +
|
|
245
|
+
(targetNeeds.wantsProvider &&
|
|
246
|
+
(classification.kind === "interface" || classification.kind === "runtime")
|
|
247
|
+
? 35
|
|
248
|
+
: 0) -
|
|
249
|
+
(classification.kind === "manifest" ? 120 : 0) -
|
|
250
|
+
(classification.kind === "doc" ? 120 : 0);
|
|
251
|
+
return { candidate, classification, score, hasEvidence };
|
|
96
252
|
})
|
|
97
253
|
.filter((entry) => entry.hasEvidence)
|
|
98
254
|
.sort((left, right) => right.score - left.score || left.candidate.localeCompare(right.candidate));
|
|
99
|
-
|
|
255
|
+
const hasStrongCandidates = scored.some((entry) => entry.score > 0 &&
|
|
256
|
+
(entry.classification.kind === "runtime" ||
|
|
257
|
+
entry.classification.kind === "interface" ||
|
|
258
|
+
entry.classification.kind === "data" ||
|
|
259
|
+
entry.classification.kind === "test" ||
|
|
260
|
+
entry.classification.kind === "ops"));
|
|
261
|
+
const filtered = scored.filter((entry) => {
|
|
262
|
+
if (entry.score <= 0)
|
|
263
|
+
return false;
|
|
264
|
+
if (!hasStrongCandidates)
|
|
265
|
+
return true;
|
|
266
|
+
if (entry.classification.kind === "manifest")
|
|
267
|
+
return false;
|
|
268
|
+
if (entry.classification.kind === "doc")
|
|
269
|
+
return false;
|
|
270
|
+
return true;
|
|
271
|
+
});
|
|
272
|
+
return unique((filtered.length > 0 ? filtered : scored.filter((entry) => entry.score > 0)).map((entry) => entry.candidate)).slice(0, limit);
|
|
100
273
|
};
|
|
101
274
|
const summarizeImplementationTargets = (targets) => {
|
|
102
275
|
if (targets.length === 0)
|
|
@@ -137,6 +310,12 @@ const summarizeAnchorBundle = (bundle) => {
|
|
|
137
310
|
}
|
|
138
311
|
return `${bundle.normalizedAnchors[0]} (+${bundle.normalizedAnchors.length - 1} more)`;
|
|
139
312
|
};
|
|
313
|
+
const toUnresolvedBundle = (bundle) => ({
|
|
314
|
+
kind: bundle.kind,
|
|
315
|
+
domain: bundle.domain,
|
|
316
|
+
values: [...bundle.values],
|
|
317
|
+
anchors: [...bundle.normalizedAnchors],
|
|
318
|
+
});
|
|
140
319
|
const buildTargetedTestGuidance = (implementationTargets) => {
|
|
141
320
|
const guidance = new Set();
|
|
142
321
|
for (const target of implementationTargets) {
|
|
@@ -666,6 +845,7 @@ export class TaskSufficiencyService {
|
|
|
666
845
|
let totalTasksAdded = 0;
|
|
667
846
|
const totalTasksUpdated = 0;
|
|
668
847
|
let satisfied = false;
|
|
848
|
+
let latestUnresolvedBundles = [];
|
|
669
849
|
for (let iteration = 1; iteration <= maxIterations; iteration += 1) {
|
|
670
850
|
const snapshot = await this.loadProjectSnapshot(request.projectKey);
|
|
671
851
|
const coverage = this.evaluateCoverage(snapshot.corpus, sectionHeadings, folderEntries, snapshot.existingAnchors);
|
|
@@ -679,6 +859,7 @@ export class TaskSufficiencyService {
|
|
|
679
859
|
totalSignals: coverage.totalSignals,
|
|
680
860
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
681
861
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
862
|
+
unresolvedBundleCount: 0,
|
|
682
863
|
createdTaskKeys: [],
|
|
683
864
|
});
|
|
684
865
|
await this.jobService.writeCheckpoint(job.id, {
|
|
@@ -690,6 +871,7 @@ export class TaskSufficiencyService {
|
|
|
690
871
|
totalSignals: coverage.totalSignals,
|
|
691
872
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
692
873
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
874
|
+
unresolvedBundleCount: 0,
|
|
693
875
|
action: "complete",
|
|
694
876
|
},
|
|
695
877
|
});
|
|
@@ -698,6 +880,7 @@ export class TaskSufficiencyService {
|
|
|
698
880
|
const gapItems = this.buildGapItems(coverage, snapshot.existingAnchors, maxTasksPerIteration);
|
|
699
881
|
const gapBundles = this.bundleGapItems(gapItems, maxTasksPerIteration);
|
|
700
882
|
if (gapBundles.length === 0) {
|
|
883
|
+
latestUnresolvedBundles = [];
|
|
701
884
|
warnings.push(`Iteration ${iteration}: unresolved SDS gaps remain but no insertable gap items were identified.`);
|
|
702
885
|
iterations.push({
|
|
703
886
|
iteration,
|
|
@@ -705,6 +888,7 @@ export class TaskSufficiencyService {
|
|
|
705
888
|
totalSignals: coverage.totalSignals,
|
|
706
889
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
707
890
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
891
|
+
unresolvedBundleCount: 0,
|
|
708
892
|
createdTaskKeys: [],
|
|
709
893
|
});
|
|
710
894
|
break;
|
|
@@ -715,6 +899,7 @@ export class TaskSufficiencyService {
|
|
|
715
899
|
}));
|
|
716
900
|
const actionableGapBundles = plannedGapBundles.filter((entry) => entry.implementationTargets.length > 0);
|
|
717
901
|
const unresolvedGapBundles = plannedGapBundles.filter((entry) => entry.implementationTargets.length === 0);
|
|
902
|
+
latestUnresolvedBundles = unresolvedGapBundles.map((entry) => toUnresolvedBundle(entry.bundle));
|
|
718
903
|
if (unresolvedGapBundles.length > 0) {
|
|
719
904
|
warnings.push(`Iteration ${iteration}: ${unresolvedGapBundles.length} SDS gap bundle(s) remain unresolved because no concrete implementation targets were inferred (${unresolvedGapBundles
|
|
720
905
|
.map((entry) => summarizeAnchorBundle(entry.bundle))
|
|
@@ -728,6 +913,7 @@ export class TaskSufficiencyService {
|
|
|
728
913
|
totalSignals: coverage.totalSignals,
|
|
729
914
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
730
915
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
916
|
+
unresolvedBundleCount: latestUnresolvedBundles.length,
|
|
731
917
|
createdTaskKeys: [],
|
|
732
918
|
});
|
|
733
919
|
await this.jobService.writeCheckpoint(job.id, {
|
|
@@ -739,13 +925,9 @@ export class TaskSufficiencyService {
|
|
|
739
925
|
totalSignals: coverage.totalSignals,
|
|
740
926
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
741
927
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
928
|
+
unresolvedBundleCount: latestUnresolvedBundles.length,
|
|
742
929
|
action: "unresolved",
|
|
743
|
-
unresolvedGapItems:
|
|
744
|
-
kind: entry.bundle.kind,
|
|
745
|
-
domain: entry.bundle.domain,
|
|
746
|
-
values: entry.bundle.values,
|
|
747
|
-
anchors: entry.bundle.normalizedAnchors,
|
|
748
|
-
})),
|
|
930
|
+
unresolvedGapItems: latestUnresolvedBundles,
|
|
749
931
|
},
|
|
750
932
|
});
|
|
751
933
|
break;
|
|
@@ -757,6 +939,7 @@ export class TaskSufficiencyService {
|
|
|
757
939
|
totalSignals: coverage.totalSignals,
|
|
758
940
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
759
941
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
942
|
+
unresolvedBundleCount: latestUnresolvedBundles.length,
|
|
760
943
|
createdTaskKeys: [],
|
|
761
944
|
});
|
|
762
945
|
await this.jobService.writeCheckpoint(job.id, {
|
|
@@ -768,6 +951,7 @@ export class TaskSufficiencyService {
|
|
|
768
951
|
totalSignals: coverage.totalSignals,
|
|
769
952
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
770
953
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
954
|
+
unresolvedBundleCount: latestUnresolvedBundles.length,
|
|
771
955
|
action: "dry_run",
|
|
772
956
|
proposedGapItems: actionableGapBundles.map((entry) => ({
|
|
773
957
|
kind: entry.bundle.kind,
|
|
@@ -775,12 +959,7 @@ export class TaskSufficiencyService {
|
|
|
775
959
|
values: entry.bundle.values,
|
|
776
960
|
implementationTargets: entry.implementationTargets,
|
|
777
961
|
})),
|
|
778
|
-
unresolvedGapItems:
|
|
779
|
-
kind: entry.bundle.kind,
|
|
780
|
-
domain: entry.bundle.domain,
|
|
781
|
-
values: entry.bundle.values,
|
|
782
|
-
anchors: entry.bundle.normalizedAnchors,
|
|
783
|
-
})),
|
|
962
|
+
unresolvedGapItems: latestUnresolvedBundles,
|
|
784
963
|
},
|
|
785
964
|
});
|
|
786
965
|
break;
|
|
@@ -805,6 +984,7 @@ export class TaskSufficiencyService {
|
|
|
805
984
|
totalSignals: coverage.totalSignals,
|
|
806
985
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
807
986
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
987
|
+
unresolvedBundleCount: latestUnresolvedBundles.length,
|
|
808
988
|
createdTaskKeys,
|
|
809
989
|
});
|
|
810
990
|
await this.jobService.writeCheckpoint(job.id, {
|
|
@@ -816,6 +996,7 @@ export class TaskSufficiencyService {
|
|
|
816
996
|
totalSignals: coverage.totalSignals,
|
|
817
997
|
missingSectionCount: coverage.missingSectionHeadings.length,
|
|
818
998
|
missingFolderCount: coverage.missingFolderEntries.length,
|
|
999
|
+
unresolvedBundleCount: latestUnresolvedBundles.length,
|
|
819
1000
|
createdTaskKeys,
|
|
820
1001
|
addedCount: createdTaskKeys.length,
|
|
821
1002
|
},
|
|
@@ -831,6 +1012,17 @@ export class TaskSufficiencyService {
|
|
|
831
1012
|
if (!satisfied) {
|
|
832
1013
|
warnings.push(`Sufficiency target not reached (coverage=${finalCoverage.coverageRatio}, threshold=${minCoverageRatio}) after ${iterations.length} iteration(s).`);
|
|
833
1014
|
}
|
|
1015
|
+
const finalGapItemLimit = Math.max(1, finalCoverage.missingSectionHeadings.length + finalCoverage.missingFolderEntries.length);
|
|
1016
|
+
const finalGapItems = this.buildGapItems(finalCoverage, finalSnapshot.existingAnchors, finalGapItemLimit);
|
|
1017
|
+
const finalGapBundles = this.bundleGapItems(finalGapItems, finalGapItemLimit);
|
|
1018
|
+
const finalPlannedGapBundles = finalGapBundles.map((bundle) => ({
|
|
1019
|
+
bundle,
|
|
1020
|
+
implementationTargets: inferImplementationTargets(bundle, folderEntries, 3),
|
|
1021
|
+
}));
|
|
1022
|
+
const plannedGapBundles = finalPlannedGapBundles.map(toPlannedGapBundle);
|
|
1023
|
+
const unresolvedBundles = finalPlannedGapBundles
|
|
1024
|
+
.filter((entry) => entry.implementationTargets.length === 0)
|
|
1025
|
+
.map((entry) => toUnresolvedBundle(entry.bundle));
|
|
834
1026
|
const report = {
|
|
835
1027
|
projectKey: request.projectKey,
|
|
836
1028
|
sourceCommand,
|
|
@@ -862,6 +1054,8 @@ export class TaskSufficiencyService {
|
|
|
862
1054
|
missingSectionHeadings: finalCoverage.missingSectionHeadings,
|
|
863
1055
|
missingFolderEntries: finalCoverage.missingFolderEntries,
|
|
864
1056
|
},
|
|
1057
|
+
plannedGapBundles,
|
|
1058
|
+
unresolvedBundles,
|
|
865
1059
|
iterations,
|
|
866
1060
|
warnings,
|
|
867
1061
|
};
|
|
@@ -877,6 +1071,7 @@ export class TaskSufficiencyService {
|
|
|
877
1071
|
totalTasksUpdated,
|
|
878
1072
|
finalTotalSignals: finalCoverage.totalSignals,
|
|
879
1073
|
finalCoverageRatio: finalCoverage.coverageRatio,
|
|
1074
|
+
unresolvedBundleCount: unresolvedBundles.length,
|
|
880
1075
|
},
|
|
881
1076
|
});
|
|
882
1077
|
const result = {
|
|
@@ -899,6 +1094,8 @@ export class TaskSufficiencyService {
|
|
|
899
1094
|
folders: finalCoverage.missingFolderEntries.length,
|
|
900
1095
|
total: finalCoverage.missingSectionHeadings.length + finalCoverage.missingFolderEntries.length,
|
|
901
1096
|
},
|
|
1097
|
+
plannedGapBundles,
|
|
1098
|
+
unresolvedBundles,
|
|
902
1099
|
iterations,
|
|
903
1100
|
reportPath,
|
|
904
1101
|
reportHistoryPath: historyPath,
|
|
@@ -917,6 +1114,7 @@ export class TaskSufficiencyService {
|
|
|
917
1114
|
finalCoverageRatio: finalCoverage.coverageRatio,
|
|
918
1115
|
remainingSectionCount: finalCoverage.missingSectionHeadings.length,
|
|
919
1116
|
remainingFolderCount: finalCoverage.missingFolderEntries.length,
|
|
1117
|
+
unresolvedBundleCount: unresolvedBundles.length,
|
|
920
1118
|
reportPath,
|
|
921
1119
|
reportHistoryPath: historyPath,
|
|
922
1120
|
warnings,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcoda/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Core services and APIs for the mcoda CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@apidevtools/swagger-parser": "^10.1.0",
|
|
34
34
|
"yaml": "^2.4.2",
|
|
35
|
-
"@mcoda/
|
|
36
|
-
"@mcoda/
|
|
37
|
-
"@mcoda/agents": "0.1.
|
|
38
|
-
"@mcoda/
|
|
39
|
-
"@mcoda/
|
|
35
|
+
"@mcoda/db": "0.1.36",
|
|
36
|
+
"@mcoda/generators": "0.1.36",
|
|
37
|
+
"@mcoda/agents": "0.1.36",
|
|
38
|
+
"@mcoda/integrations": "0.1.36",
|
|
39
|
+
"@mcoda/shared": "0.1.36"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -p tsconfig.json",
|