@devtrack-solution/codesdd 1.2.4-rc3 → 1.2.4
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/.sdd/skills/curated/devtrack-api/SKILL.md +91 -12
- package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +3 -3
- package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +2 -0
- package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +59 -3
- package/.sdd/skills/curated/devtrack-api/references/consumer-sync-policy.md +15 -3
- package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +1898 -2
- package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +3 -1
- package/.sdd/skills/curated/devtrack-api/references/field-validation-protocol.md +40 -0
- package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +20 -2
- package/.sdd/skills/curated/devtrack-api/references/generated-artifact-invalidation.md +97 -0
- package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +30 -1
- package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +4 -3
- package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +22 -1
- package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +9 -5
- package/README.md +122 -25
- package/dist/cli/program.js +180 -11
- package/dist/commands/config.js +27 -1
- package/dist/commands/sdd/execution.js +64 -2
- package/dist/commands/sdd.js +119 -4
- package/dist/core/cli/command-matrix.d.ts +18 -0
- package/dist/core/cli/command-matrix.js +148 -0
- package/dist/core/cli-command-quality.js +2 -0
- package/dist/core/config-schema.d.ts +14 -1
- package/dist/core/config-schema.js +32 -1
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +11 -0
- package/dist/core/global-config.d.ts +13 -0
- package/dist/core/init.d.ts +2 -2
- package/dist/core/init.js +13 -14
- package/dist/core/sdd/agent-binding.d.ts +9 -9
- package/dist/core/sdd/agent-runtime-contract.d.ts +4 -4
- package/dist/core/sdd/allocator-recovery.d.ts +14 -0
- package/dist/core/sdd/allocator-recovery.js +30 -0
- package/dist/core/sdd/allocator-security.d.ts +18 -0
- package/dist/core/sdd/allocator-security.js +36 -0
- package/dist/core/sdd/api-foundation-baseline.d.ts +111 -0
- package/dist/core/sdd/api-foundation-baseline.js +151 -0
- package/dist/core/sdd/api-foundation-parity.d.ts +114 -0
- package/dist/core/sdd/api-foundation-parity.js +131 -0
- package/dist/core/sdd/api-profile-catalog.d.ts +36 -0
- package/dist/core/sdd/api-profile-catalog.js +132 -0
- package/dist/core/sdd/api-profile-dry-run-projection.d.ts +93 -0
- package/dist/core/sdd/api-profile-dry-run-projection.js +370 -0
- package/dist/core/sdd/api-profile-recipes.d.ts +82 -0
- package/dist/core/sdd/api-profile-recipes.js +484 -0
- package/dist/core/sdd/artifact-id-allocator.d.ts +368 -0
- package/dist/core/sdd/artifact-id-allocator.js +510 -0
- package/dist/core/sdd/check.d.ts +50 -1
- package/dist/core/sdd/check.js +286 -9
- package/dist/core/sdd/deepagent-contracts.d.ts +4 -4
- package/dist/core/sdd/deepagents/reversa-subagents.d.ts +3 -3
- package/dist/core/sdd/default-bootstrap-files.d.ts +1 -1
- package/dist/core/sdd/default-bootstrap-files.js +0 -2
- package/dist/core/sdd/default-skills.js +7 -5
- package/dist/core/sdd/devtrack-api-appliance.d.ts +34 -0
- package/dist/core/sdd/devtrack-api-appliance.js +138 -34
- package/dist/core/sdd/devtrack-api-architecture.d.ts +16 -0
- package/dist/core/sdd/devtrack-api-architecture.js +86 -0
- package/dist/core/sdd/docs-sync.js +3 -3
- package/dist/core/sdd/enterprise-mutating-command-gate.d.ts +27 -0
- package/dist/core/sdd/enterprise-mutating-command-gate.js +104 -0
- package/dist/core/sdd/enterprise-provenance-gates.d.ts +20 -0
- package/dist/core/sdd/enterprise-provenance-gates.js +63 -0
- package/dist/core/sdd/enterprise-provisioning-policy.d.ts +26 -0
- package/dist/core/sdd/enterprise-provisioning-policy.js +104 -0
- package/dist/core/sdd/governance-schemas.d.ts +2 -2
- package/dist/core/sdd/governance-schemas.js +11 -2
- package/dist/core/sdd/json-schema.js +4 -0
- package/dist/core/sdd/legacy-operations.js +93 -4
- package/dist/core/sdd/package-security-gates.js +2 -0
- package/dist/core/sdd/package-structure-gate.d.ts +85 -3
- package/dist/core/sdd/package-structure-gate.js +386 -8
- package/dist/core/sdd/parallel-feat-automation.d.ts +6 -6
- package/dist/core/sdd/plugin-policy.js +6 -1
- package/dist/core/sdd/plugin-registry.d.ts +3 -3
- package/dist/core/sdd/quality-validation.d.ts +5 -5
- package/dist/core/sdd/release-readiness.d.ts +49 -0
- package/dist/core/sdd/release-readiness.js +303 -8
- package/dist/core/sdd/reversa-architecture-extractor.d.ts +13 -0
- package/dist/core/sdd/reversa-architecture-extractor.js +89 -0
- package/dist/core/sdd/reversa-artifact-writer.d.ts +18 -0
- package/dist/core/sdd/reversa-artifact-writer.js +40 -0
- package/dist/core/sdd/reversa-command-policy.d.ts +136 -0
- package/dist/core/sdd/reversa-command-policy.js +361 -0
- package/dist/core/sdd/reversa-data-extractor.d.ts +11 -0
- package/dist/core/sdd/reversa-data-extractor.js +73 -0
- package/dist/core/sdd/reversa-equivalence.d.ts +20 -0
- package/dist/core/sdd/reversa-equivalence.js +34 -0
- package/dist/core/sdd/reversa-evidence.d.ts +298 -0
- package/dist/core/sdd/reversa-evidence.js +118 -0
- package/dist/core/sdd/reversa-reconstruction.d.ts +29 -0
- package/dist/core/sdd/reversa-reconstruction.js +32 -0
- package/dist/core/sdd/reversa-rules-extractor.d.ts +12 -0
- package/dist/core/sdd/reversa-rules-extractor.js +86 -0
- package/dist/core/sdd/reversa-source-safety.d.ts +19 -0
- package/dist/core/sdd/reversa-source-safety.js +105 -0
- package/dist/core/sdd/reversa-surface-scout.d.ts +13 -0
- package/dist/core/sdd/reversa-surface-scout.js +85 -0
- package/dist/core/sdd/reversa-ux-mapper.d.ts +11 -0
- package/dist/core/sdd/reversa-ux-mapper.js +73 -0
- package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +1 -1
- package/dist/core/sdd/services/archive-quality-coherence.service.d.ts +17 -0
- package/dist/core/sdd/services/archive-quality-coherence.service.js +141 -0
- package/dist/core/sdd/services/decide.service.js +1 -1
- package/dist/core/sdd/services/finalize.service.d.ts +2 -0
- package/dist/core/sdd/services/finalize.service.js +48 -2
- package/dist/core/sdd/services/historical-quality-regression.service.d.ts +35 -0
- package/dist/core/sdd/services/historical-quality-regression.service.js +228 -0
- package/dist/core/sdd/services/ingest-deposito.service.js +1 -1
- package/dist/core/sdd/services/planning-execution-coherence.service.d.ts +45 -0
- package/dist/core/sdd/services/planning-execution-coherence.service.js +225 -0
- package/dist/core/sdd/state.js +15 -5
- package/dist/core/sdd/types.d.ts +3 -3
- package/dist/core/sdd/workspace-schemas.d.ts +45 -4
- package/dist/core/sdd/workspace-schemas.js +27 -6
- package/dist/core/shared/skill-generation.d.ts +2 -0
- package/dist/core/shared/skill-generation.js +19 -2
- package/dist/core/shared/tool-detection.d.ts +19 -0
- package/dist/core/shared/tool-detection.js +89 -0
- package/package.json +6 -5
- package/schemas/sdd/5-quality.schema.json +43 -0
- package/schemas/sdd/reversa-evidence-bundle.schema.json +466 -0
- package/schemas/sdd/workspace-catalog.schema.json +511 -0
package/dist/core/sdd/check.js
CHANGED
|
@@ -11,6 +11,7 @@ import { syncSddGuideDocs, validateSddGuideDocs } from './docs-sync.js';
|
|
|
11
11
|
import { evaluateWorkspaceTraceability } from './domain/traceability.js';
|
|
12
12
|
import { detectArchiveArchivedLifecycleCollisions } from './domain/post-active-validation.js';
|
|
13
13
|
import { parseWorkspaceYamlDocument, workspaceTasksSchema, } from './workspace-schemas.js';
|
|
14
|
+
import { scanArchiveQualityCoherence } from './services/archive-quality-coherence.service.js';
|
|
14
15
|
export function checkUniqueIds(items, scope, errors) {
|
|
15
16
|
const seen = new Set();
|
|
16
17
|
for (const item of items) {
|
|
@@ -21,6 +22,7 @@ export function checkUniqueIds(items, scope, errors) {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
const FORBIDDEN_TITLE_PATTERNS = ['debate:', 'insight:', '(preencher', '(placeholder'];
|
|
25
|
+
const CLOSED_BACKLOG_STATUSES = new Set(['DONE', 'ARCHIVED']);
|
|
24
26
|
export function hasForbiddenTitleToken(title) {
|
|
25
27
|
const lowered = title.toLowerCase();
|
|
26
28
|
for (const token of FORBIDDEN_TITLE_PATTERNS) {
|
|
@@ -29,6 +31,258 @@ export function hasForbiddenTitleToken(title) {
|
|
|
29
31
|
}
|
|
30
32
|
return null;
|
|
31
33
|
}
|
|
34
|
+
export function summarizeFrontendGapHealth(gaps) {
|
|
35
|
+
let open = 0;
|
|
36
|
+
let planned = 0;
|
|
37
|
+
let inProgress = 0;
|
|
38
|
+
let resolved = 0;
|
|
39
|
+
let superseded = 0;
|
|
40
|
+
for (const gap of gaps) {
|
|
41
|
+
if (gap.status === 'OPEN')
|
|
42
|
+
open++;
|
|
43
|
+
if (gap.status === 'PLANNED')
|
|
44
|
+
planned++;
|
|
45
|
+
if (gap.status === 'IN_PROGRESS')
|
|
46
|
+
inProgress++;
|
|
47
|
+
if (gap.status === 'DONE')
|
|
48
|
+
resolved++;
|
|
49
|
+
if (gap.status === 'SUPERSEDED')
|
|
50
|
+
superseded++;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
total: gaps.length,
|
|
54
|
+
open,
|
|
55
|
+
planned,
|
|
56
|
+
in_progress: inProgress,
|
|
57
|
+
resolved,
|
|
58
|
+
superseded,
|
|
59
|
+
unresolved: gaps.length - resolved - superseded,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function summarizeLockDomainHealth(items) {
|
|
63
|
+
const lockOwners = new Map();
|
|
64
|
+
for (const item of items) {
|
|
65
|
+
for (const lock of item.lock_domains) {
|
|
66
|
+
const owners = lockOwners.get(lock) || [];
|
|
67
|
+
owners.push(item);
|
|
68
|
+
lockOwners.set(lock, owners);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const shared = [];
|
|
72
|
+
for (const [lock, owners] of lockOwners.entries()) {
|
|
73
|
+
if (owners.length <= 1)
|
|
74
|
+
continue;
|
|
75
|
+
const activeOwners = owners.filter((owner) => !CLOSED_BACKLOG_STATUSES.has(owner.status));
|
|
76
|
+
const historicalOwners = owners.filter((owner) => CLOSED_BACKLOG_STATUSES.has(owner.status));
|
|
77
|
+
const severity = activeOwners.length > 1 ? 'active' : activeOwners.length === 1 ? 'mixed' : 'historical';
|
|
78
|
+
shared.push({
|
|
79
|
+
lock,
|
|
80
|
+
severity,
|
|
81
|
+
owners: owners.map((owner) => owner.id),
|
|
82
|
+
active_owners: activeOwners.map((owner) => owner.id),
|
|
83
|
+
historical_owners: historicalOwners.map((owner) => owner.id),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
shared.sort((left, right) => left.lock.localeCompare(right.lock));
|
|
87
|
+
return {
|
|
88
|
+
shared_total: shared.length,
|
|
89
|
+
active_conflicts: shared.filter((item) => item.severity === 'active').length,
|
|
90
|
+
mixed_history: shared.filter((item) => item.severity === 'mixed').length,
|
|
91
|
+
historical: shared.filter((item) => item.severity === 'historical').length,
|
|
92
|
+
shared,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function normalizeCatalogPath(input) {
|
|
96
|
+
return input.trim().replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/+$/, '');
|
|
97
|
+
}
|
|
98
|
+
export function hasRepoMapReference(repoPath, repoMapPaths) {
|
|
99
|
+
const normalizedRepoPath = normalizeCatalogPath(repoPath);
|
|
100
|
+
if (!normalizedRepoPath)
|
|
101
|
+
return false;
|
|
102
|
+
return repoMapPaths.some((repoMapPath) => {
|
|
103
|
+
const normalizedRepoMapPath = normalizeCatalogPath(repoMapPath);
|
|
104
|
+
if (!normalizedRepoMapPath)
|
|
105
|
+
return false;
|
|
106
|
+
return (normalizedRepoMapPath === normalizedRepoPath ||
|
|
107
|
+
normalizedRepoMapPath.startsWith(`${normalizedRepoPath}/`) ||
|
|
108
|
+
normalizedRepoPath.startsWith(`${normalizedRepoMapPath}/`));
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
export function hasIntegrationContract(contractRef, knownContracts) {
|
|
112
|
+
const normalizedContractRef = contractRef.trim();
|
|
113
|
+
if (!normalizedContractRef)
|
|
114
|
+
return false;
|
|
115
|
+
if (knownContracts.has(normalizedContractRef))
|
|
116
|
+
return true;
|
|
117
|
+
for (const knownContract of knownContracts) {
|
|
118
|
+
if (knownContract.startsWith(`${normalizedContractRef}::`)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
export function auditServiceCatalogMaturity(services, backlogItems, repoMapItems, integrationContracts) {
|
|
125
|
+
const backlogIds = new Set(backlogItems.map((item) => item.id));
|
|
126
|
+
const repoMapPaths = repoMapItems.map((item) => item.path);
|
|
127
|
+
const contracts = new Set(integrationContracts.map((item) => item.trim()).filter(Boolean));
|
|
128
|
+
const byLevel = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
|
|
129
|
+
const below5 = [];
|
|
130
|
+
for (const service of services) {
|
|
131
|
+
const unmet = [];
|
|
132
|
+
const hasIdentity = Boolean(service.id.trim()) && Boolean(service.name.trim()) && Boolean((service.responsibility || '').trim());
|
|
133
|
+
if (!hasIdentity)
|
|
134
|
+
unmet.push('identity');
|
|
135
|
+
const hasOwners = service.owner_refs.length > 0 && service.owner_refs.every((ownerRef) => backlogIds.has(ownerRef));
|
|
136
|
+
if (!hasOwners)
|
|
137
|
+
unmet.push('owner_refs');
|
|
138
|
+
const hasRepoPaths = service.repo_paths.length > 0 && service.repo_paths.every((repoPath) => hasRepoMapReference(repoPath, repoMapPaths));
|
|
139
|
+
if (!hasRepoPaths)
|
|
140
|
+
unmet.push('repo_paths');
|
|
141
|
+
const hasContracts = service.contracts.length > 0 &&
|
|
142
|
+
service.contracts.every((contractRef) => hasIntegrationContract(contractRef, contracts));
|
|
143
|
+
if (!hasContracts)
|
|
144
|
+
unmet.push('contracts');
|
|
145
|
+
const hasExternalDependencies = Array.isArray(service.external_dependencies);
|
|
146
|
+
if (!hasExternalDependencies)
|
|
147
|
+
unmet.push('external_dependencies');
|
|
148
|
+
const level = !hasIdentity ? 1 : !hasOwners ? 2 : !hasRepoPaths ? 3 : !hasContracts || !hasExternalDependencies ? 4 : 5;
|
|
149
|
+
byLevel[level] += 1;
|
|
150
|
+
if (level < 5) {
|
|
151
|
+
below5.push({
|
|
152
|
+
id: service.id,
|
|
153
|
+
level,
|
|
154
|
+
unmet,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
serviceCount: services.length,
|
|
160
|
+
byLevel,
|
|
161
|
+
below5,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export async function validateAdrConsistency(adrsDir, backlogItems, errors, warnings, isStrict) {
|
|
165
|
+
const backlogStatus = new Map();
|
|
166
|
+
for (const item of backlogItems) {
|
|
167
|
+
backlogStatus.set(item.id, item.status);
|
|
168
|
+
}
|
|
169
|
+
let filenames;
|
|
170
|
+
try {
|
|
171
|
+
filenames = await fs.readdir(adrsDir);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const adrs = filenames.filter((f) => f.startsWith('ADR-') && f.endsWith('.md'));
|
|
177
|
+
for (const filename of adrs) {
|
|
178
|
+
let content;
|
|
179
|
+
try {
|
|
180
|
+
content = await fs.readFile(path.join(adrsDir, filename), 'utf-8');
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const frontmatterMatch = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
186
|
+
if (!frontmatterMatch)
|
|
187
|
+
continue;
|
|
188
|
+
let frontmatter;
|
|
189
|
+
try {
|
|
190
|
+
frontmatter = parseYaml(frontmatterMatch[1]) ?? {};
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const adrStatus = typeof frontmatter.status === 'string' ? frontmatter.status : '';
|
|
196
|
+
const featureId = typeof frontmatter.feature_id === 'string' ? frontmatter.feature_id : '';
|
|
197
|
+
const adrId = typeof frontmatter.id === 'string' ? frontmatter.id : filename;
|
|
198
|
+
if (!featureId || !adrStatus)
|
|
199
|
+
continue;
|
|
200
|
+
const featureStatus = backlogStatus.get(featureId);
|
|
201
|
+
if (!featureStatus)
|
|
202
|
+
continue;
|
|
203
|
+
const featureDone = featureStatus === 'DONE' || featureStatus === 'ARCHIVED';
|
|
204
|
+
const adrUnresolved = adrStatus === 'IN_PROGRESS' || adrStatus === 'DRAFT';
|
|
205
|
+
if (featureDone && adrUnresolved) {
|
|
206
|
+
const message = `ADR consistency gate failed: ${adrId} status is ${adrStatus} but feature ${featureId} is ${featureStatus} in backlog`;
|
|
207
|
+
if (isStrict) {
|
|
208
|
+
errors.push(message);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
warnings.push(message);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
export function validateInsightMinimums(insightTitle, insightBody, errors) {
|
|
217
|
+
if ((insightTitle || '').trim().length < 50) {
|
|
218
|
+
errors.push(`INSIGHT quality gate: title must be >=50 characters (current: ${(insightTitle || '').trim().length}). Expand the title to describe the problem and expected impact.`);
|
|
219
|
+
}
|
|
220
|
+
const bodyLower = (insightBody || '').toLowerCase();
|
|
221
|
+
const missingKeywords = [];
|
|
222
|
+
if (!/\bproblem|\bproblema|\bissue\b/.test(bodyLower))
|
|
223
|
+
missingKeywords.push('problem description');
|
|
224
|
+
if (!/\bscope|\bescopo|\bboundary\b/.test(bodyLower))
|
|
225
|
+
missingKeywords.push('scope definition');
|
|
226
|
+
if (!/\bimpact|\bimpacto|\boutcome\b/.test(bodyLower))
|
|
227
|
+
missingKeywords.push('expected impact');
|
|
228
|
+
if (missingKeywords.length > 0) {
|
|
229
|
+
errors.push(`INSIGHT quality gate: body must describe problem, scope, and impact. Missing: ${missingKeywords.join(', ')}.`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
export function validateEpicMinimums(epicBody, epicTitle, errors) {
|
|
233
|
+
const bodyClean = (epicBody || '').replace(/^---[\s\S]*?---\r?\n?/, '').trim();
|
|
234
|
+
if (bodyClean.length < 500) {
|
|
235
|
+
errors.push(`EPIC quality gate: expanded plan must be >=500 characters (current: ${bodyClean.length}). Add feature breakdown, dependency map, risk matrix, and DoD.`);
|
|
236
|
+
}
|
|
237
|
+
const featMatches = bodyClean.match(/FEAT-\d{4}/g) || [];
|
|
238
|
+
const uniqueFeats = new Set(featMatches).size;
|
|
239
|
+
if (uniqueFeats < 3) {
|
|
240
|
+
errors.push(`EPIC quality gate: must reference >=3 estimated features (current: ${uniqueFeats}). Expand the breakdown plan with concrete feature estimates.`);
|
|
241
|
+
}
|
|
242
|
+
const hasDependencyMap = /\bupstream\b|\bdownstream\b|\bdependencies\b|\bdependency map\b/i.test(bodyClean);
|
|
243
|
+
if (!hasDependencyMap) {
|
|
244
|
+
errors.push(`EPIC quality gate: must include a dependency map with upstream and downstream references.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export function validateTransitionLogConsistency(transitionLogEvents, backlogItems, errors, warnings, isStrict) {
|
|
248
|
+
if (transitionLogEvents.length === 0)
|
|
249
|
+
return;
|
|
250
|
+
const oldestEventTs = Math.min(...transitionLogEvents.map((e) => e.timestamp ? Date.parse(String(e.timestamp)) : Infinity));
|
|
251
|
+
const backlogStatus = new Map(backlogItems.map((item) => [item.id, item.status]));
|
|
252
|
+
const finalizeEvents = new Set();
|
|
253
|
+
for (const event of transitionLogEvents) {
|
|
254
|
+
const action = event.action || event.to || '';
|
|
255
|
+
if (action === 'finalized' || action === 'archived' || action === 'DONE' || action === 'ARCHIVED') {
|
|
256
|
+
finalizeEvents.add(event.entity_id);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const item of backlogItems) {
|
|
260
|
+
const isDone = item.status === 'DONE' || item.status === 'ARCHIVED';
|
|
261
|
+
if (!isDone)
|
|
262
|
+
continue;
|
|
263
|
+
if (finalizeEvents.has(item.id))
|
|
264
|
+
continue;
|
|
265
|
+
const itemDoneAt = item.done_at || item.archived_at || '';
|
|
266
|
+
if (itemDoneAt && oldestEventTs !== Infinity && Date.parse(itemDoneAt) < oldestEventTs) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const message = `Transition-log consistency: ${item.id} is ${item.status} in backlog but has no finalized event in transition-log`;
|
|
270
|
+
warnings.push(message);
|
|
271
|
+
}
|
|
272
|
+
for (const eventId of finalizeEvents) {
|
|
273
|
+
const status = backlogStatus.get(eventId);
|
|
274
|
+
if (!status) {
|
|
275
|
+
warnings.push(`Transition-log consistency: transition-log has finalized event for ${eventId} but no matching backlog item`);
|
|
276
|
+
}
|
|
277
|
+
else if (status !== 'DONE' && status !== 'ARCHIVED') {
|
|
278
|
+
const message = `Transition-log consistency: ${eventId} has finalized event in transition-log but backlog status is ${status}`;
|
|
279
|
+
if (isStrict)
|
|
280
|
+
errors.push(message);
|
|
281
|
+
else
|
|
282
|
+
warnings.push(message);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
32
286
|
export function validateDiscoveryRecords(records, errors) {
|
|
33
287
|
for (const record of records) {
|
|
34
288
|
if (record.type === 'INS' && !ID_PATTERNS.insight.test(record.id)) {
|
|
@@ -53,7 +307,6 @@ export function validateDiscoveryRecords(records, errors) {
|
|
|
53
307
|
}
|
|
54
308
|
export function validateBacklog(items, errors, warnings) {
|
|
55
309
|
const ids = new Set(items.map((item) => item.id));
|
|
56
|
-
const lockOwners = new Map();
|
|
57
310
|
for (const item of items) {
|
|
58
311
|
const forbidden = hasForbiddenTitleToken(item.title);
|
|
59
312
|
if (forbidden) {
|
|
@@ -67,15 +320,10 @@ export function validateBacklog(items, errors, warnings) {
|
|
|
67
320
|
warnings.push(`Item de backlog ${item.id} bloqueado por referencia inexistente: ${dep}`);
|
|
68
321
|
}
|
|
69
322
|
}
|
|
70
|
-
for (const lock of item.lock_domains) {
|
|
71
|
-
const owners = lockOwners.get(lock) || [];
|
|
72
|
-
owners.push(item.id);
|
|
73
|
-
lockOwners.set(lock, owners);
|
|
74
|
-
}
|
|
75
323
|
}
|
|
76
|
-
for (const
|
|
77
|
-
if (
|
|
78
|
-
warnings.push(`Lock domain "${lock}" compartilhado por: ${
|
|
324
|
+
for (const sharedLock of summarizeLockDomainHealth(items).shared) {
|
|
325
|
+
if (sharedLock.severity === 'active') {
|
|
326
|
+
warnings.push(`Lock domain "${sharedLock.lock}" compartilhado por FEATs ativas: ${sharedLock.active_owners.join(', ')}`);
|
|
79
327
|
}
|
|
80
328
|
}
|
|
81
329
|
}
|
|
@@ -739,6 +987,15 @@ export class SddCheckCommand {
|
|
|
739
987
|
validatePrivacySourceRegistry(snapshot, warnings);
|
|
740
988
|
await validatePrivacyWorkspaceChecklist(paths.activeDir, snapshot.backlog.items, warnings);
|
|
741
989
|
await validateTraceabilityWorkspaceChecklist(paths.projectRoot, paths.activeDir, snapshot.backlog.items, warnings);
|
|
990
|
+
await validateAdrConsistency(path.join(paths.coreDir, 'adrs'), snapshot.backlog.items, errors, warnings, isStrict);
|
|
991
|
+
validateTransitionLogConsistency(snapshot.transitionLog?.events || [], snapshot.backlog.items, errors, warnings, isStrict);
|
|
992
|
+
const archiveQualityCoherence = await scanArchiveQualityCoherence(paths.archivedDir);
|
|
993
|
+
for (const issue of archiveQualityCoherence.issues) {
|
|
994
|
+
errors.push(issue.message);
|
|
995
|
+
}
|
|
996
|
+
if (archiveQualityCoherence.grandfathered > 0) {
|
|
997
|
+
warnings.push(`Archive quality coherence grandfathered ${archiveQualityCoherence.grandfathered} archived FEAT workspaces (<= FEAT-0451).`);
|
|
998
|
+
}
|
|
742
999
|
const featuresMissingFrontendDeclaration = config.frontend.enabled
|
|
743
1000
|
? snapshot.backlog.items
|
|
744
1001
|
.filter((item) => item.status !== 'ARCHIVED' && item.status !== 'DONE')
|
|
@@ -780,6 +1037,22 @@ export class SddCheckCommand {
|
|
|
780
1037
|
if (snapshot.repoMap.items.length === 0) {
|
|
781
1038
|
missingArchitectureFields.push('repo-map.items vazio');
|
|
782
1039
|
}
|
|
1040
|
+
const serviceCatalogMaturityAudit = auditServiceCatalogMaturity(snapshot.serviceCatalog.services, snapshot.backlog.items, snapshot.repoMap.items, snapshot.integrationContracts.contracts);
|
|
1041
|
+
if (serviceCatalogMaturityAudit.below5.length > 0) {
|
|
1042
|
+
const sample = serviceCatalogMaturityAudit.below5
|
|
1043
|
+
.slice(0, 10)
|
|
1044
|
+
.map((entry) => `${entry.id}(L${entry.level}: ${entry.unmet.join(', ')})`)
|
|
1045
|
+
.join('; ');
|
|
1046
|
+
const remainder = serviceCatalogMaturityAudit.below5.length - Math.min(10, serviceCatalogMaturityAudit.below5.length);
|
|
1047
|
+
const suffix = remainder > 0 ? `; +${remainder} service(s)` : '';
|
|
1048
|
+
const message = `Service catalog maturity gate failed: ${serviceCatalogMaturityAudit.below5.length}/${serviceCatalogMaturityAudit.serviceCount} services are below level 5. ${sample}${suffix}`;
|
|
1049
|
+
if (isStrict) {
|
|
1050
|
+
errors.push(message);
|
|
1051
|
+
}
|
|
1052
|
+
else {
|
|
1053
|
+
warnings.push(message);
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
783
1056
|
const hasFrontendDecisionDemand = config.frontend.enabled &&
|
|
784
1057
|
((snapshot.frontendGaps?.items.length ?? 0) > 0 ||
|
|
785
1058
|
snapshot.backlog.items.some((item) => featureHasMetadataFrontendEvidence(item)));
|
|
@@ -832,6 +1105,8 @@ export class SddCheckCommand {
|
|
|
832
1105
|
const finalizeQueuePending = snapshot.finalizeQueue.items.filter((item) => item.status === 'PENDING').length;
|
|
833
1106
|
const finalizeQueueDone = snapshot.finalizeQueue.history.length +
|
|
834
1107
|
snapshot.finalizeQueue.items.filter((item) => item.status === 'DONE').length;
|
|
1108
|
+
const frontendGapsSummary = summarizeFrontendGapHealth(snapshot.frontendGaps?.items ?? []);
|
|
1109
|
+
const lockDomainHealth = summarizeLockDomainHealth(snapshot.backlog.items);
|
|
835
1110
|
return {
|
|
836
1111
|
valid: errors.length === 0,
|
|
837
1112
|
errors,
|
|
@@ -845,12 +1120,14 @@ export class SddCheckCommand {
|
|
|
845
1120
|
finalizeQueueDone,
|
|
846
1121
|
frontendEnabled: config.frontend.enabled,
|
|
847
1122
|
frontendGaps: snapshot.frontendGaps?.items.length ?? 0,
|
|
1123
|
+
frontendGapsSummary,
|
|
848
1124
|
frontendRoutes: snapshot.frontendMap?.routes.length ?? 0,
|
|
849
1125
|
progress_global: progress.progressGlobal,
|
|
850
1126
|
progress_by_radar: progress.progressByRadar,
|
|
851
1127
|
ready_for_parallel: graph.readyForParallel,
|
|
852
1128
|
blocked: graph.blocked,
|
|
853
1129
|
lock_conflicts: graph.lockConflicts,
|
|
1130
|
+
lock_domain_health: lockDomainHealth,
|
|
854
1131
|
documentation_sync: docsValidation.documentationSync,
|
|
855
1132
|
core_views_stale: coreViewsStale,
|
|
856
1133
|
missing_architecture_fields: missingArchitectureFields,
|
|
@@ -148,8 +148,8 @@ export declare const deepagentRunRequestSchema: z.ZodObject<{
|
|
|
148
148
|
kind: z.ZodEnum<{
|
|
149
149
|
event: "event";
|
|
150
150
|
schema: "schema";
|
|
151
|
-
route: "route";
|
|
152
151
|
page: "page";
|
|
152
|
+
route: "route";
|
|
153
153
|
cli_command: "cli_command";
|
|
154
154
|
public_contract: "public_contract";
|
|
155
155
|
core_flow: "core_flow";
|
|
@@ -164,8 +164,8 @@ export declare const deepagentRunRequestSchema: z.ZodObject<{
|
|
|
164
164
|
kind: z.ZodEnum<{
|
|
165
165
|
event: "event";
|
|
166
166
|
schema: "schema";
|
|
167
|
-
route: "route";
|
|
168
167
|
page: "page";
|
|
168
|
+
route: "route";
|
|
169
169
|
cli_command: "cli_command";
|
|
170
170
|
public_contract: "public_contract";
|
|
171
171
|
core_flow: "core_flow";
|
|
@@ -180,8 +180,8 @@ export declare const deepagentRunRequestSchema: z.ZodObject<{
|
|
|
180
180
|
capability_required_kinds: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
181
181
|
event: "event";
|
|
182
182
|
schema: "schema";
|
|
183
|
-
route: "route";
|
|
184
183
|
page: "page";
|
|
184
|
+
route: "route";
|
|
185
185
|
cli_command: "cli_command";
|
|
186
186
|
public_contract: "public_contract";
|
|
187
187
|
core_flow: "core_flow";
|
|
@@ -336,8 +336,8 @@ export declare const deepagentRunEvidenceSchema: z.ZodObject<{
|
|
|
336
336
|
completed: "completed";
|
|
337
337
|
blocked: "blocked";
|
|
338
338
|
failed: "failed";
|
|
339
|
-
running: "running";
|
|
340
339
|
allowed: "allowed";
|
|
340
|
+
running: "running";
|
|
341
341
|
}>;
|
|
342
342
|
model_metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
343
343
|
config_fingerprint: z.ZodString;
|
|
@@ -5,8 +5,8 @@ export declare const reversaDomainSchema: z.ZodEnum<{
|
|
|
5
5
|
rules: "rules";
|
|
6
6
|
data: "data";
|
|
7
7
|
migration: "migration";
|
|
8
|
-
"legacy-analysis": "legacy-analysis";
|
|
9
8
|
screens: "screens";
|
|
9
|
+
"legacy-analysis": "legacy-analysis";
|
|
10
10
|
microservices: "microservices";
|
|
11
11
|
"equivalence-validation": "equivalence-validation";
|
|
12
12
|
}>;
|
|
@@ -18,8 +18,8 @@ export declare const deepAgentsReversaRequestSchema: z.ZodObject<{
|
|
|
18
18
|
rules: "rules";
|
|
19
19
|
data: "data";
|
|
20
20
|
migration: "migration";
|
|
21
|
-
"legacy-analysis": "legacy-analysis";
|
|
22
21
|
screens: "screens";
|
|
22
|
+
"legacy-analysis": "legacy-analysis";
|
|
23
23
|
microservices: "microservices";
|
|
24
24
|
"equivalence-validation": "equivalence-validation";
|
|
25
25
|
}>>>;
|
|
@@ -56,8 +56,8 @@ export declare const deepAgentsReversaPlanSchema: z.ZodObject<{
|
|
|
56
56
|
rules: "rules";
|
|
57
57
|
data: "data";
|
|
58
58
|
migration: "migration";
|
|
59
|
-
"legacy-analysis": "legacy-analysis";
|
|
60
59
|
screens: "screens";
|
|
60
|
+
"legacy-analysis": "legacy-analysis";
|
|
61
61
|
microservices: "microservices";
|
|
62
62
|
"equivalence-validation": "equivalence-validation";
|
|
63
63
|
}>;
|
|
@@ -10,7 +10,7 @@ export interface SddReadmeFolders {
|
|
|
10
10
|
}
|
|
11
11
|
export declare function buildSddInternalReadme(memoryDir?: string, folders?: SddReadmeFolders): string;
|
|
12
12
|
export declare const PROMPTS_README_MD = "# Recommended SDD Prompts\n\nUse these prompts to speed up agent workflows without losing the SDD standard.\n\n## Recommended Order For Raw Material\n1. `00-start-here.md`\n2. `01-source-intake.md`\n3. `02-normalize-planning.md`\n4. `03-feature-execution.md`\n5. `04-finalize-consolidation.md`\n\nRule: prompts guide the agent, but the canonical state remains in `.sdd/state/*.yaml`.\nDo not persist project memory, workflow state, backlog, or handoff in external context stores.\n";
|
|
13
|
-
export declare const PROMPT_00_COMECE_POR_AQUI_MD = "# Start Here (First Use)\n\nIf you have never used CodeSDD, follow this order.\n\n## 1) Install And Initialize The Project\n\nIn the terminal, from your project directory:\n\n```bash\ncodesdd
|
|
13
|
+
export declare const PROMPT_00_COMECE_POR_AQUI_MD = "# Start Here (First Use)\n\nIf you have never used CodeSDD, follow this order.\n\n## 1) Install And Initialize The Project\n\nIn the terminal, from your project directory:\n\n```bash\ncodesdd sdd init-context --frontend --lang en-US --layout en-US\ncodesdd sdd check --render\ncodesdd sdd rebuild --from-disk --dry-run\ncodesdd sdd dedup --apply --dry-run\ncodesdd sdd onboard system\ncodesdd reload --tools none --lang en-US --layout en-US\n```\n\n## 2) Understand The Main Folders\n\n- `.sdd/sources/`: raw material such as PRDs, wireframes, stories, and references.\n- `.sdd/state/`: canonical YAML source of truth.\n- `.sdd/core/`: generated human-readable system overview.\n- `.sdd/planning/`: backlog, progress, and finalize queue.\n- `.sdd/active/`: active FEAT workspaces.\n- `.sdd/archived/`: finalized workspaces.\n\nCodeSDD is the only operational memory for the project. Do not use external context, memory, workflow, backlog, scratchpad, or handoff stores as active project state.\nIn initialized CodeSDD repositories, requests that imply implementation, edits, validation, execution, or finalize implicitly require CodeSDD planning unless explicitly marked read-only or outside CodeSDD.\n\n## 3) I Have PRDs, Wireframes, Or Stories. What Now?\n\n1. Place the files under `.sdd/sources/` in the appropriate subfolders.\n2. Run:\n\n```bash\ncodesdd sdd ingest-deposito --source-dir .sdd/sources --title \"Initial system planning\"\n```\n\n3. Review:\n\n```bash\ncodesdd sdd check --render\ncodesdd sdd next\n```\n\nExpected result:\n- sources indexed in `.sdd/state/source-index.yaml`\n- EPIC created or reused\n- FEATs generated in the backlog\n- first ready FEAT started automatically when possible\n\n## 4) Execute A Feature\n\n```bash\ncodesdd sdd start FEAT-0001 --flow-mode standard\ncodesdd sdd context FEAT-0001\ncodesdd sdd frontend-impact FEAT-0001 --status required --reason \"New route and UI components\"\n```\n\nImplement and update the FEAT package:\n- `1-spec.yaml`\n- `2-plan.yaml`\n- `5-quality.yaml`\n- `3-tasks.yaml`\n- `4-changelog.yaml`\n\n## 5) Finalize Without Losing Context\n\n```bash\ncodesdd sdd finalize --ref FEAT-0001\ncodesdd sdd check --render\ncodesdd sdd onboard system\n```\n\nGolden rule:\n- A FEAT is only truly complete after documentation consolidation.\n\n## 6) Short Usage Story\n\nThe team placed a PRD and a wireframe in `.sdd/sources/`.\nThey ran `codesdd sdd ingest-deposito --source-dir .sdd/sources` and got an EPIC plus ready FEATs.\nThey started the priority FEAT with `codesdd sdd start FEAT-0001`.\nBefore coding, they ran `codesdd sdd context FEAT-0001`.\nAfter implementation, they ran `codesdd sdd finalize --ref FEAT-0001`.\nResult: backlog updated, docs synchronized, and the next FEAT released without guesswork.\n\n## 7) Essential Commands\n\n- `codesdd sdd onboard system`: understand the current state.\n- `codesdd sdd ingest-deposito --source-dir .sdd/sources`: turn raw material into an executable trail.\n- `codesdd sdd rebuild --from-disk --dry-run`: preview state reconciliation from disk artifacts.\n- `codesdd sdd audit --json`: persist an audit snapshot in `.sdd/state/audit-history.yaml`.\n- `codesdd sdd metrics --since 7d`: inspect lead time, aging, and throughput.\n- `codesdd sdd dedup --apply --dry-run`: preview historical warning_links reconciliation.\n- `codesdd sdd lint feature FEAT-0001`: inspect feature scope before execution.\n- `codesdd sdd next`: see what can start now.\n- `codesdd sdd start FEAT-0001`: open feature execution.\n- `codesdd sdd context FEAT-0001`: generate focused context.\n- `codesdd sdd frontend-impact FEAT-0001 --status required|none --reason \"...\"`: declare frontend impact.\n- `codesdd sdd finalize --ref FEAT-0001`: consolidate memory and close.\n";
|
|
14
14
|
export declare const PROMPT_01_INGESTAO_DEPOSITO_MD = "# Prompt: Source Intake\n\nUse the skills:\n- source-intake-sdd\n- business-extractor-sdd\n- frontend-extractor-sdd\n- planning-normalizer-sdd\n\nObjective:\n1. Scan `.sdd/sources/`.\n2. Update `.sdd/state/source-index.yaml`.\n3. Consolidate canonical context (`architecture`, `service-catalog`, `tech-stack`, `integration-contracts`, and frontend when enabled).\n4. Generate an executable trail (EPIC plus FEATs) with source traceability.\n\nRequired output:\n- summary of sources read;\n- IDs created or updated (EPIC/FEAT/FGAP/INS when ambiguity exists);\n- recommended next CLI commands.\n";
|
|
15
15
|
export declare const PROMPT_02_NORMALIZAR_PLANEJAMENTO_MD = "# Prompt: Normalize Planning\n\nObjective:\nTurn consolidated material into an executable plan with clear dependencies.\n\nInstructions:\n1. Start from `.sdd/state/source-index.yaml` and `.sdd/core/*.md`.\n2. Propose EPICs and FEATs with clear English names.\n3. Define dependencies (`blocked_by`) and conflicts (`lock_domains`).\n4. List what can run in parallel.\n5. End with a documentation consolidation checklist per feature.\n";
|
|
16
16
|
export declare const PROMPT_03_EXECUCAO_FEATURE_MD = "# Prompt: Feature Execution\n\nObjective:\nExecute a FEAT without losing traceability.\n\nInstructions:\n1. Treat implementation, edit, validation, execution, and finalize requests as requiring CodeSDD planning unless the user explicitly marks the request as read-only or outside CodeSDD.\n2. Run `codesdd sdd next` and bind the work to the active or ready FEAT returned by CodeSDD.\n3. Run `codesdd sdd context FEAT-0001`.\n4. Update `.sdd/active/FEAT-0001/` (spec, plan, tasks, changelog).\n5. Implement.\n6. Update `.sdd/active/FEAT-0001/5-quality.yaml` with evidence or a formal exception; quality contracts are blocking by default.\n7. Update affected canonical docs.\n8. Declare frontend impact with `codesdd sdd frontend-impact FEAT-0001 ...`.\n9. Ensure architectural-impact FEATs have an ADR before finalize.\n10. Finish with `codesdd sdd finalize --ref FEAT-0001`.\n";
|
|
@@ -81,8 +81,6 @@ If you have never used CodeSDD, follow this order.
|
|
|
81
81
|
In the terminal, from your project directory:
|
|
82
82
|
|
|
83
83
|
\`\`\`bash
|
|
84
|
-
codesdd install --tools none --lang en-US --layout en-US
|
|
85
|
-
codesdd sdd init --frontend --lang en-US --layout en-US
|
|
86
84
|
codesdd sdd init-context --frontend --lang en-US --layout en-US
|
|
87
85
|
codesdd sdd check --render
|
|
88
86
|
codesdd sdd rebuild --from-disk --dry-run
|
|
@@ -73,8 +73,8 @@ const SKILL_METADATA_OVERRIDES = {
|
|
|
73
73
|
description: 'Canonical Python/Flask agentic backend skill with Clean Architecture boundaries, tenant/security authority-source rules, CodeSDD decision support (runtime-safe), production-readiness guidance, and maintainable quality gates.',
|
|
74
74
|
},
|
|
75
75
|
'devtrack-api': {
|
|
76
|
-
title: '
|
|
77
|
-
description: '
|
|
76
|
+
title: 'CodeSDD API Profiles',
|
|
77
|
+
description: 'Compatibility backend engineering and governance skill for CodeSDD API profiles using NestJS, TypeORM, DDD/Clean Architecture boundaries, Swagger/OpenAPI, .env.example, package scripts, route guards, auth/authz planning, application use cases, evidence-based validation, and safe operational delivery.',
|
|
78
78
|
},
|
|
79
79
|
'devtrack-angular': {
|
|
80
80
|
title: 'DevTrack Angular Admin',
|
|
@@ -554,8 +554,9 @@ export function buildCuratedBundlesCurationData(layout = 'en-US') {
|
|
|
554
554
|
bundle_id: 'architecture-backend',
|
|
555
555
|
canonical_path: '.sdd/skills/curated/devtrack-api/',
|
|
556
556
|
notes: [
|
|
557
|
-
'Canonical directory for the
|
|
558
|
-
'Operational default: API/backend work
|
|
557
|
+
'Canonical directory for the CodeSDD API profile compatibility skill; includes agents/ and references/.',
|
|
558
|
+
'Operational default: API/backend work selects one of minimal-rest, rest-auth-rbac, rest-crud-typeorm, evented-api, ai-agent-api, or full-foundation-compatible; devtrack-api remains compatibility-only and Python/Flask API work uses api-clean-flask-langgraph.',
|
|
559
|
+
'Tool-level API baseline: Swagger/OpenAPI, .env.example, package scripts with cleanup/cleanup:install and port-safe start/start:dev bootstrap, application use cases, route guards, and auth/authz planning are inferred minimums unless an explicit profile exception is recorded.',
|
|
559
560
|
],
|
|
560
561
|
},
|
|
561
562
|
{
|
|
@@ -620,7 +621,8 @@ export function buildCuratedBundlesMarkdown() {
|
|
|
620
621
|
lines.push('- Canonical file: `.sdd/skills/curated/api-clean-flask-langgraph/SKILL.md`.');
|
|
621
622
|
lines.push('- `devtrack-api` belongs to bundle `architecture-backend`.');
|
|
622
623
|
lines.push('- Canonical directory: `.sdd/skills/curated/devtrack-api/` (includes `agents/` and `references/`).');
|
|
623
|
-
lines.push('- Operational default: API/backend work
|
|
624
|
+
lines.push('- Operational default: API/backend work selects one of `minimal-rest`, `rest-auth-rbac`, `rest-crud-typeorm`, `evented-api`, `ai-agent-api`, or `full-foundation-compatible`; `devtrack-api` remains compatibility-only and Python/Flask API work uses `api-clean-flask-langgraph`.');
|
|
625
|
+
lines.push('- Tool-level API baseline: Swagger/OpenAPI, `.env.example`, package scripts with `cleanup`/`cleanup:install` and port-safe `start`/`start:dev` bootstrap, application use cases, route guards, and auth/authz planning are inferred minimums unless an explicit profile exception is recorded.');
|
|
624
626
|
lines.push('- `devtrack-angular` belongs to bundle `frontend-product` as the Angular Admin/backoffice skill.');
|
|
625
627
|
lines.push('- Canonical directory: `.sdd/skills/curated/devtrack-angular/` (includes `agents/` and `references/`).');
|
|
626
628
|
lines.push('- Operational default: Angular Admin/backoffice work that names admin pages, dashboards, CRUD, data grids, admin Formly, admin NGXS/state, official Angular framework patterns, permissions, reports, workflow, admin realtime, or admin chat should use `devtrack-angular` unless an explicit skill/profile overrides it.');
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type PluginArtifactManifest, type PluginRuntimeInvocationPlan } from './plugin-broker.js';
|
|
2
2
|
import { type PluginManifest } from './plugin-manifest.js';
|
|
3
3
|
import type { PluginArtifactKind, PluginArtifactMapEntry, PluginArtifactRole } from './plugin-sdk-contract.js';
|
|
4
|
+
import { CODESDD_API_PROFILE_FAMILY_ID, type CodeSddApiProfileId, type ResolvedCodeSddApiProfile } from './api-profile-catalog.js';
|
|
5
|
+
import { CODESDD_API_FOUNDATION_SHARED_BASELINE, CODESDD_API_SHARED_BASELINE_QUALITY_GATES, CODESDD_API_SHARED_BASELINE_REQUIREMENTS, type CodeSddApiSharedBaselineRequirement } from './api-foundation-baseline.js';
|
|
6
|
+
import { CODESDD_FULL_FOUNDATION_COMPATIBLE_PROFILE_ID, CODESDD_FULL_FOUNDATION_PARITY_DIMENSIONS, CODESDD_FULL_FOUNDATION_PARITY_MATRIX, CODESDD_FULL_FOUNDATION_PARITY_QUALITY_GATES, type CodeSddFullFoundationParityDimension } from './api-foundation-parity.js';
|
|
7
|
+
import { type CodeSddApiProfileDryRunProjection } from './api-profile-dry-run-projection.js';
|
|
4
8
|
export declare const DEVTRACK_API_APPLIANCE_PLUGIN_ID = "codesdd-plugin-devtrack-api";
|
|
5
9
|
export declare const DEVTRACK_API_APPLIANCE_CAPABILITIES: readonly ["scaffold.project", "generate.domain", "generate.crud", "validate.structure", "evidence.emit"];
|
|
6
10
|
declare const DEVTRACK_API_SCAFFOLD_CAPABILITY = "scaffold.project";
|
|
@@ -23,6 +27,7 @@ export interface DevTrackApiScaffoldDryRunInput {
|
|
|
23
27
|
feature_ref: string;
|
|
24
28
|
project_name: string;
|
|
25
29
|
package_name?: string;
|
|
30
|
+
api_profile?: string;
|
|
26
31
|
created_at?: string;
|
|
27
32
|
operation_id?: string;
|
|
28
33
|
requested_write_scope?: string[];
|
|
@@ -51,12 +56,41 @@ export interface DevTrackApiScaffoldEvidenceManifest {
|
|
|
51
56
|
status: 'pending';
|
|
52
57
|
}>;
|
|
53
58
|
quality_gates: string[];
|
|
59
|
+
api_profile: {
|
|
60
|
+
family_id: typeof CODESDD_API_PROFILE_FAMILY_ID;
|
|
61
|
+
selected_profile: CodeSddApiProfileId;
|
|
62
|
+
requested_profile?: string;
|
|
63
|
+
legacy_alias: boolean;
|
|
64
|
+
migration_notice?: string;
|
|
65
|
+
inherited_baseline: typeof CODESDD_API_SHARED_BASELINE_REQUIREMENTS;
|
|
66
|
+
};
|
|
67
|
+
profile_projection: CodeSddApiProfileDryRunProjection;
|
|
68
|
+
foundation_baseline: {
|
|
69
|
+
id: typeof CODESDD_API_FOUNDATION_SHARED_BASELINE.id;
|
|
70
|
+
version: typeof CODESDD_API_FOUNDATION_SHARED_BASELINE.version;
|
|
71
|
+
source: typeof CODESDD_API_FOUNDATION_SHARED_BASELINE.foundation_reference;
|
|
72
|
+
requirement_ids: typeof CODESDD_API_SHARED_BASELINE_REQUIREMENTS;
|
|
73
|
+
quality_gates: typeof CODESDD_API_SHARED_BASELINE_QUALITY_GATES;
|
|
74
|
+
requirements: CodeSddApiSharedBaselineRequirement[];
|
|
75
|
+
};
|
|
76
|
+
full_foundation_compatibility?: {
|
|
77
|
+
id: typeof CODESDD_FULL_FOUNDATION_PARITY_MATRIX.id;
|
|
78
|
+
version: typeof CODESDD_FULL_FOUNDATION_PARITY_MATRIX.version;
|
|
79
|
+
profile_id: typeof CODESDD_FULL_FOUNDATION_COMPATIBLE_PROFILE_ID;
|
|
80
|
+
source: typeof CODESDD_FULL_FOUNDATION_PARITY_MATRIX.foundation_reference;
|
|
81
|
+
dimension_ids: typeof CODESDD_FULL_FOUNDATION_PARITY_DIMENSIONS;
|
|
82
|
+
quality_gates: typeof CODESDD_FULL_FOUNDATION_PARITY_QUALITY_GATES;
|
|
83
|
+
dimensions: Array<CodeSddFullFoundationParityDimension & {
|
|
84
|
+
status: 'pending';
|
|
85
|
+
}>;
|
|
86
|
+
};
|
|
54
87
|
}
|
|
55
88
|
export type DevTrackApiScaffoldDryRunPlan = {
|
|
56
89
|
schema_version: 1;
|
|
57
90
|
status: 'planned';
|
|
58
91
|
created_at: string;
|
|
59
92
|
operation_id: string;
|
|
93
|
+
api_profile: ResolvedCodeSddApiProfile;
|
|
60
94
|
project_name: string;
|
|
61
95
|
package_name: string;
|
|
62
96
|
runtime_plan: PluginRuntimeInvocationPlan;
|