@devtrack-solution/codesdd 1.2.3 → 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.
Files changed (213) hide show
  1. package/.sdd/skills/curated/devtrack-api/SKILL.md +98 -12
  2. package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +10 -0
  3. package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +10 -0
  4. package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +10 -0
  5. package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +10 -0
  6. package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +10 -0
  7. package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +5 -3
  8. package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +12 -0
  9. package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +61 -5
  10. package/.sdd/skills/curated/devtrack-api/references/consumer-sync-policy.md +15 -3
  11. package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +1951 -0
  12. package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +16 -14
  13. package/.sdd/skills/curated/devtrack-api/references/field-validation-protocol.md +40 -0
  14. package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +19 -2
  15. package/.sdd/skills/curated/devtrack-api/references/generated-artifact-invalidation.md +97 -0
  16. package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +30 -1
  17. package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +42 -0
  18. package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +22 -1
  19. package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +9 -7
  20. package/README.md +280 -29
  21. package/dist/applications/sdd/index.d.ts +16 -0
  22. package/dist/applications/sdd/index.js +16 -0
  23. package/dist/cli/program.js +180 -11
  24. package/dist/commands/config.js +197 -10
  25. package/dist/commands/sdd/execution.js +408 -16
  26. package/dist/commands/sdd/plugin.js +5 -0
  27. package/dist/commands/sdd/shared.d.ts +1 -0
  28. package/dist/commands/sdd/shared.js +10 -0
  29. package/dist/commands/sdd.js +157 -7
  30. package/dist/core/cli/command-matrix.d.ts +18 -0
  31. package/dist/core/cli/command-matrix.js +157 -0
  32. package/dist/core/cli-command-quality.js +11 -0
  33. package/dist/core/completions/command-registry.js +45 -0
  34. package/dist/core/config-schema.d.ts +31 -1
  35. package/dist/core/config-schema.js +79 -5
  36. package/dist/core/config.d.ts +1 -0
  37. package/dist/core/config.js +11 -0
  38. package/dist/core/global-config.d.ts +29 -0
  39. package/dist/core/init.d.ts +2 -2
  40. package/dist/core/init.js +13 -14
  41. package/dist/core/sdd/agent-binding.d.ts +19 -19
  42. package/dist/core/sdd/agent-runtime-contract.d.ts +204 -0
  43. package/dist/core/sdd/agent-runtime-contract.js +200 -0
  44. package/dist/core/sdd/allocator-recovery.d.ts +14 -0
  45. package/dist/core/sdd/allocator-recovery.js +30 -0
  46. package/dist/core/sdd/allocator-security.d.ts +18 -0
  47. package/dist/core/sdd/allocator-security.js +36 -0
  48. package/dist/core/sdd/api-foundation-baseline.d.ts +111 -0
  49. package/dist/core/sdd/api-foundation-baseline.js +151 -0
  50. package/dist/core/sdd/api-foundation-parity.d.ts +114 -0
  51. package/dist/core/sdd/api-foundation-parity.js +131 -0
  52. package/dist/core/sdd/api-profile-catalog.d.ts +36 -0
  53. package/dist/core/sdd/api-profile-catalog.js +132 -0
  54. package/dist/core/sdd/api-profile-dry-run-projection.d.ts +93 -0
  55. package/dist/core/sdd/api-profile-dry-run-projection.js +370 -0
  56. package/dist/core/sdd/api-profile-recipes.d.ts +82 -0
  57. package/dist/core/sdd/api-profile-recipes.js +484 -0
  58. package/dist/core/sdd/artifact-id-allocator.d.ts +368 -0
  59. package/dist/core/sdd/artifact-id-allocator.js +510 -0
  60. package/dist/core/sdd/check.d.ts +52 -1
  61. package/dist/core/sdd/check.js +326 -11
  62. package/dist/core/sdd/coordination/coordination-adapters.d.ts +15 -8
  63. package/dist/core/sdd/coordination/coordination-adapters.js +43 -15
  64. package/dist/core/sdd/coordination/index.d.ts +1 -0
  65. package/dist/core/sdd/coordination/index.js +1 -0
  66. package/dist/core/sdd/coordination/redis-runtime.d.ts +131 -0
  67. package/dist/core/sdd/coordination/redis-runtime.js +698 -0
  68. package/dist/core/sdd/deepagent-contracts.d.ts +99 -5
  69. package/dist/core/sdd/deepagent-contracts.js +62 -0
  70. package/dist/core/sdd/deepagents/reversa-subagents.d.ts +3 -3
  71. package/dist/core/sdd/default-bootstrap-files.d.ts +2 -2
  72. package/dist/core/sdd/default-bootstrap-files.js +14 -10
  73. package/dist/core/sdd/default-skills.js +115 -9
  74. package/dist/core/sdd/devtrack-api-appliance.d.ts +42 -1
  75. package/dist/core/sdd/devtrack-api-appliance.js +159 -32
  76. package/dist/core/sdd/devtrack-api-architecture.d.ts +16 -0
  77. package/dist/core/sdd/devtrack-api-architecture.js +86 -0
  78. package/dist/core/sdd/docs-sync.js +24 -18
  79. package/dist/core/sdd/domain/capability-diff.d.ts +63 -0
  80. package/dist/core/sdd/domain/capability-diff.js +200 -0
  81. package/dist/core/sdd/domain/change-safety-guardrails.d.ts +74 -0
  82. package/dist/core/sdd/domain/change-safety-guardrails.js +333 -0
  83. package/dist/core/sdd/domain/semantic-intent-classifier.d.ts +29 -0
  84. package/dist/core/sdd/domain/semantic-intent-classifier.js +117 -0
  85. package/dist/core/sdd/enterprise-mutating-command-gate.d.ts +27 -0
  86. package/dist/core/sdd/enterprise-mutating-command-gate.js +104 -0
  87. package/dist/core/sdd/enterprise-provenance-gates.d.ts +20 -0
  88. package/dist/core/sdd/enterprise-provenance-gates.js +63 -0
  89. package/dist/core/sdd/enterprise-provisioning-policy.d.ts +26 -0
  90. package/dist/core/sdd/enterprise-provisioning-policy.js +104 -0
  91. package/dist/core/sdd/foundation-artifact-map-validator.d.ts +16 -0
  92. package/dist/core/sdd/foundation-artifact-map-validator.js +71 -0
  93. package/dist/core/sdd/foundation-layer-manifest.d.ts +24 -0
  94. package/dist/core/sdd/foundation-layer-manifest.js +117 -0
  95. package/dist/core/sdd/governance-schemas.d.ts +2 -2
  96. package/dist/core/sdd/governance-schemas.js +11 -2
  97. package/dist/core/sdd/intent-guard.d.ts +22 -0
  98. package/dist/core/sdd/intent-guard.js +67 -0
  99. package/dist/core/sdd/json-schema.js +13 -1
  100. package/dist/core/sdd/legacy-operations.js +169 -5
  101. package/dist/core/sdd/migrate-workspace.js +39 -0
  102. package/dist/core/sdd/package-security-gates.d.ts +21 -0
  103. package/dist/core/sdd/package-security-gates.js +121 -0
  104. package/dist/core/sdd/package-structure-gate.d.ts +85 -3
  105. package/dist/core/sdd/package-structure-gate.js +384 -11
  106. package/dist/core/sdd/parallel-feat-automation.d.ts +185 -7
  107. package/dist/core/sdd/parallel-feat-automation.js +212 -0
  108. package/dist/core/sdd/plugin-broker.d.ts +223 -4
  109. package/dist/core/sdd/plugin-broker.js +10 -0
  110. package/dist/core/sdd/plugin-cli.d.ts +30 -0
  111. package/dist/core/sdd/plugin-cli.js +70 -3
  112. package/dist/core/sdd/plugin-evidence.d.ts +73 -0
  113. package/dist/core/sdd/plugin-manifest.d.ts +69 -1
  114. package/dist/core/sdd/plugin-manifest.js +10 -0
  115. package/dist/core/sdd/plugin-policy-pack.d.ts +1 -1
  116. package/dist/core/sdd/plugin-policy.js +6 -1
  117. package/dist/core/sdd/plugin-registry.d.ts +138 -2
  118. package/dist/core/sdd/plugin-sdk-contract.d.ts +363 -0
  119. package/dist/core/sdd/plugin-sdk-contract.js +268 -0
  120. package/dist/core/sdd/plugin-skill-binding.d.ts +1 -1
  121. package/dist/core/sdd/quality-validation.d.ts +89 -16
  122. package/dist/core/sdd/release-readiness.d.ts +68 -0
  123. package/dist/core/sdd/release-readiness.js +767 -0
  124. package/dist/core/sdd/reversa-architecture-extractor.d.ts +13 -0
  125. package/dist/core/sdd/reversa-architecture-extractor.js +89 -0
  126. package/dist/core/sdd/reversa-artifact-writer.d.ts +18 -0
  127. package/dist/core/sdd/reversa-artifact-writer.js +40 -0
  128. package/dist/core/sdd/reversa-command-policy.d.ts +136 -0
  129. package/dist/core/sdd/reversa-command-policy.js +361 -0
  130. package/dist/core/sdd/reversa-data-extractor.d.ts +11 -0
  131. package/dist/core/sdd/reversa-data-extractor.js +73 -0
  132. package/dist/core/sdd/reversa-equivalence.d.ts +20 -0
  133. package/dist/core/sdd/reversa-equivalence.js +34 -0
  134. package/dist/core/sdd/reversa-evidence.d.ts +298 -0
  135. package/dist/core/sdd/reversa-evidence.js +118 -0
  136. package/dist/core/sdd/reversa-reconstruction.d.ts +29 -0
  137. package/dist/core/sdd/reversa-reconstruction.js +32 -0
  138. package/dist/core/sdd/reversa-rules-extractor.d.ts +12 -0
  139. package/dist/core/sdd/reversa-rules-extractor.js +86 -0
  140. package/dist/core/sdd/reversa-source-safety.d.ts +19 -0
  141. package/dist/core/sdd/reversa-source-safety.js +105 -0
  142. package/dist/core/sdd/reversa-surface-scout.d.ts +13 -0
  143. package/dist/core/sdd/reversa-surface-scout.js +85 -0
  144. package/dist/core/sdd/reversa-ux-mapper.d.ts +11 -0
  145. package/dist/core/sdd/reversa-ux-mapper.js +73 -0
  146. package/dist/core/sdd/runtime-boundary-contract.d.ts +45 -0
  147. package/dist/core/sdd/runtime-boundary-contract.js +90 -0
  148. package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +150 -0
  149. package/dist/core/sdd/sdk-agent-plugin-quality-gates.js +258 -0
  150. package/dist/core/sdd/services/agent-run.service.d.ts +38 -6
  151. package/dist/core/sdd/services/agent-run.service.js +73 -1
  152. package/dist/core/sdd/services/archive-quality-coherence.service.d.ts +17 -0
  153. package/dist/core/sdd/services/archive-quality-coherence.service.js +141 -0
  154. package/dist/core/sdd/services/capability-diff.service.d.ts +18 -0
  155. package/dist/core/sdd/services/capability-diff.service.js +26 -0
  156. package/dist/core/sdd/services/change-safety-preflight.service.d.ts +17 -0
  157. package/dist/core/sdd/services/change-safety-preflight.service.js +17 -0
  158. package/dist/core/sdd/services/context.service.d.ts +43 -340
  159. package/dist/core/sdd/services/context.service.js +323 -9
  160. package/dist/core/sdd/services/decide.service.js +1 -1
  161. package/dist/core/sdd/services/finalize.service.d.ts +27 -0
  162. package/dist/core/sdd/services/finalize.service.js +226 -18
  163. package/dist/core/sdd/services/frontend-impact.service.d.ts +1 -1
  164. package/dist/core/sdd/services/historical-quality-regression.service.d.ts +35 -0
  165. package/dist/core/sdd/services/historical-quality-regression.service.js +228 -0
  166. package/dist/core/sdd/services/ingest-deposito.service.js +1 -1
  167. package/dist/core/sdd/services/planning-execution-coherence.service.d.ts +45 -0
  168. package/dist/core/sdd/services/planning-execution-coherence.service.js +225 -0
  169. package/dist/core/sdd/services/semantic-intent-classifier.service.d.ts +6 -0
  170. package/dist/core/sdd/services/semantic-intent-classifier.service.js +7 -0
  171. package/dist/core/sdd/state.d.ts +1 -0
  172. package/dist/core/sdd/state.js +266 -34
  173. package/dist/core/sdd/store/sdd-stores.js +2 -2
  174. package/dist/core/sdd/structural-health.d.ts +13 -13
  175. package/dist/core/sdd/types.d.ts +30 -15
  176. package/dist/core/sdd/types.js +4 -0
  177. package/dist/core/sdd/views.js +17 -0
  178. package/dist/core/sdd/workspace-schemas.d.ts +428 -7
  179. package/dist/core/sdd/workspace-schemas.js +223 -70
  180. package/dist/core/shared/skill-generation.d.ts +2 -0
  181. package/dist/core/shared/skill-generation.js +19 -2
  182. package/dist/core/shared/tool-detection.d.ts +19 -0
  183. package/dist/core/shared/tool-detection.js +89 -0
  184. package/dist/domains/sdd/index.d.ts +6 -0
  185. package/dist/domains/sdd/index.js +6 -0
  186. package/dist/infrastructures/sdd/index.d.ts +7 -0
  187. package/dist/infrastructures/sdd/index.js +6 -0
  188. package/dist/presentations/cli/sdd/index.d.ts +3 -0
  189. package/dist/presentations/cli/sdd/index.js +3 -0
  190. package/dist/shared/sdd/index.d.ts +3 -0
  191. package/dist/shared/sdd/index.js +2 -0
  192. package/package.json +14 -10
  193. package/schemas/sdd/2-plan.schema.json +207 -2
  194. package/schemas/sdd/5-quality.schema.json +324 -25
  195. package/schemas/sdd/agent-runtime-command-plan.schema.json +212 -0
  196. package/schemas/sdd/agent-runtime-opencode-run-evidence.schema.json +270 -0
  197. package/schemas/sdd/codesdd-plugin.schema.json +171 -0
  198. package/schemas/sdd/deepagent-run-request.schema.json +316 -0
  199. package/schemas/sdd/parallel-feat-automation-plan.schema.json +89 -0
  200. package/schemas/sdd/parallel-feat-scheduler-request.schema.json +116 -0
  201. package/schemas/sdd/parallel-feat-scheduler-result.schema.json +404 -0
  202. package/schemas/sdd/plugin-artifact-manifest.schema.json +109 -0
  203. package/schemas/sdd/plugin-artifact-map.schema.json +223 -0
  204. package/schemas/sdd/plugin-evidence-manifest.schema.json +109 -0
  205. package/schemas/sdd/plugin-language-runtime.schema.json +103 -0
  206. package/schemas/sdd/plugin-package-governance.schema.json +74 -0
  207. package/schemas/sdd/plugin-registry.schema.json +171 -0
  208. package/schemas/sdd/plugin-runtime-invocation-plan.schema.json +109 -0
  209. package/schemas/sdd/quality-evidence-bundle.schema.json +109 -0
  210. package/schemas/sdd/reversa-evidence-bundle.schema.json +466 -0
  211. package/schemas/sdd/sdk-agent-plugin-quality-gate-input.schema.json +168 -0
  212. package/schemas/sdd/sdk-agent-plugin-quality-gate-report.schema.json +160 -0
  213. package/schemas/sdd/workspace-catalog.schema.json +5298 -1409
@@ -10,12 +10,78 @@ import { normalizeArchivedFeatureActiveReferences, validatePostActiveFeaturePlac
10
10
  import { loadStateSnapshot, nowIso, saveStateTransaction } from "../state.js";
11
11
  import { syncSddGuideDocs } from "../docs-sync.js";
12
12
  import { mergeArchitectureNode, mergeFrontendDecisionRecord, mergeRepoMapRecord, mergeServiceRecord, mergeTechStackRecord, stableUniqueStrings, upsertByKey } from "../merge-catalog.js";
13
- import { getRuntime, persistAndRender, relProjectPath, coreDocRef, activeDocNamesForLayout, activeDocCandidateNames, unresolvedDependencies, updateDependencyMetadata, gitChangedFiles, detectFrontendImpactEvidence, maybeCreateAutomaticFrontendGap, buildFinalizeQueue, evaluateFeatureQuality, buildAdrMarkdown, applyLoggedTransition, gateSatisfied, pathExists, RADAR_TO_DISCOVERY_STATUS } from "../legacy-operations.js";
13
+ import { getRuntime, persistAndRender, relProjectPath, coreDocRef, activeDocNamesForLayout, activeDocCandidateNames, unresolvedDependencies, updateDependencyMetadata, gitChangedFiles, detectFrontendImpactEvidence, maybeCreateAutomaticFrontendGap, buildFinalizeQueue, evaluateFeatureQuality, buildAdrMarkdown, applyLoggedTransition, gateSatisfied, pathExists, computeReadyFeatures, extractFeatureNumber, buildDependentsMap, scoreReadyItem, RADAR_TO_DISCOVERY_STATUS } from "../legacy-operations.js";
14
14
  import { SddWriteTransaction } from "../write-manifest.js";
15
15
  import { withStateLock } from "../state-lock.js";
16
16
  import { activeWorkspaceDeclaresMandatoryAdrImpact } from "../adr-policy.js";
17
17
  import { normalizeFeatRef } from "../entity-reference.js";
18
18
  import { parseWorkspaceYamlDocument, stringifyWorkspaceYamlDocument, } from "../workspace-schemas.js";
19
+ function recordFinalizeHistory(history, item) {
20
+ const index = history.findIndex((entry) => entry.feature_id === item.feature_id);
21
+ if (index >= 0) {
22
+ history[index] = item;
23
+ return;
24
+ }
25
+ history.push(item);
26
+ history.sort((a, b) => a.feature_id.localeCompare(b.feature_id));
27
+ }
28
+ function moveCompletedFinalizeItemsToHistory(state) {
29
+ const activeItems = [];
30
+ for (const item of state.items) {
31
+ if (item.status === 'DONE') {
32
+ recordFinalizeHistory(state.history, {
33
+ feature_id: item.feature_id,
34
+ status: 'DONE',
35
+ summary: item.summary,
36
+ created_at: item.created_at,
37
+ completed_at: item.completed_at || item.created_at || '',
38
+ });
39
+ }
40
+ else {
41
+ activeItems.push(item);
42
+ }
43
+ }
44
+ state.items = activeItems;
45
+ }
46
+ export function reconcileAdrMarkdownForFinalize(existingAdr, now) {
47
+ return existingAdr
48
+ .replace(/^status:\s*IN_PROGRESS\b/m, 'status: DONE')
49
+ .replace(/^status:\s*DRAFT\b/m, 'status: DONE')
50
+ .replace(/^decision_status:\s*PROPOSED\b/m, 'decision_status: ACCEPTED')
51
+ .replace(/^updated_at:\s*["']?[\dTZ:.-]+["']?\s*$/m, `updated_at: ${now}`);
52
+ }
53
+ function buildPostFinalizeReplan(items, finalized, unlocked, generatedAt) {
54
+ const rank = 'impact';
55
+ const computed = computeReadyFeatures(items, { rank });
56
+ const dependentsMap = buildDependentsMap(items);
57
+ const ready = computed.ready
58
+ .map((item) => {
59
+ const scored = scoreReadyItem(item, items, dependentsMap, rank);
60
+ return {
61
+ id: item.id,
62
+ title: item.title,
63
+ recommended_skills: item.recommended_skills.slice(0, 3),
64
+ score: scored.score,
65
+ reasons: scored.reasons,
66
+ };
67
+ })
68
+ .sort((left, right) => {
69
+ if (right.score !== left.score)
70
+ return right.score - left.score;
71
+ return extractFeatureNumber(left.id) - extractFeatureNumber(right.id);
72
+ })
73
+ .slice(0, 10);
74
+ return {
75
+ rank,
76
+ generated_at: generatedAt,
77
+ finalized,
78
+ unlocked,
79
+ ready,
80
+ waves: computed.waves,
81
+ blocked_count: computed.blocked.length,
82
+ conflicts_count: computed.conflicts.length,
83
+ };
84
+ }
19
85
  export class FinalizeService {
20
86
  stores;
21
87
  constructor(stores) {
@@ -25,6 +91,7 @@ export class FinalizeService {
25
91
  const { config, paths } = await getRuntime(projectRoot);
26
92
  return withStateLock(paths.stateDir, async () => {
27
93
  const snapshot = await loadStateSnapshot(paths, config);
94
+ moveCompletedFinalizeItemsToHistory(snapshot.finalizeQueue);
28
95
  snapshot.finalizeQueue.items = await buildFinalizeQueue(paths, snapshot.backlog.items, snapshot.finalizeQueue.items);
29
96
  const pending = snapshot.finalizeQueue.items.filter((item) => item.status === 'PENDING');
30
97
  const inferredRef = options?.allReady
@@ -47,6 +114,7 @@ export class FinalizeService {
47
114
  finalized: [],
48
115
  unblocked: [],
49
116
  pending: pending.length,
117
+ post_finalize_replan: buildPostFinalizeReplan(snapshot.backlog.items, [], [], nowIso()),
50
118
  updated_core_docs: [],
51
119
  updated_readme: false,
52
120
  updated_agent_guide: false,
@@ -275,19 +343,14 @@ export class FinalizeService {
275
343
  continue;
276
344
  }
277
345
  const queue = snapshot.finalizeQueue.items.find((item) => item.feature_id === featureId);
278
- if (queue) {
279
- queue.status = 'DONE';
280
- queue.completed_at = now;
281
- }
282
- else {
283
- snapshot.finalizeQueue.items.push({
284
- feature_id: featureId,
285
- status: 'DONE',
286
- summary: `Finalizado manualmente: ${featureId}`,
287
- created_at: now,
288
- completed_at: now,
289
- });
290
- }
346
+ snapshot.finalizeQueue.items = snapshot.finalizeQueue.items.filter((item) => item.feature_id !== featureId);
347
+ recordFinalizeHistory(snapshot.finalizeQueue.history, {
348
+ feature_id: featureId,
349
+ status: 'DONE',
350
+ summary: queue?.summary || `Finalizado manualmente: ${featureId}`,
351
+ created_at: queue?.created_at || now,
352
+ completed_at: now,
353
+ });
291
354
  if ((feature.origin_type === 'radar' || feature.origin_type === 'epic') && feature.origin_ref) {
292
355
  const siblings = snapshot.backlog.items.filter((item) => (item.origin_type === 'radar' || item.origin_type === 'epic') && item.origin_ref === feature.origin_ref);
293
356
  if (siblings.every((item) => item.status === 'DONE' || item.status === 'ARCHIVED')) {
@@ -395,7 +458,13 @@ export class FinalizeService {
395
458
  if (!options?.noAdr && !feature.requires_adr) {
396
459
  const adrPath = path.join(paths.coreDir, 'adrs', `ADR-${feature.id}.md`);
397
460
  const tx = new SddWriteTransaction();
398
- tx.writeFile(adrPath, buildAdrMarkdown(feature, unlockedByFeature, now));
461
+ try {
462
+ const existingAdr = await fs.readFile(adrPath, 'utf-8');
463
+ tx.writeFile(adrPath, reconcileAdrMarkdownForFinalize(existingAdr, now));
464
+ }
465
+ catch {
466
+ tx.writeFile(adrPath, buildAdrMarkdown(feature, unlockedByFeature, now));
467
+ }
399
468
  await tx.commit(paths.projectRoot, paths.memoryRoot, 'finalize.service (ADR)');
400
469
  }
401
470
  await fs.mkdir(paths.archivedDir, { recursive: true });
@@ -421,6 +490,7 @@ export class FinalizeService {
421
490
  });
422
491
  }
423
492
  updateDependencyMetadata(snapshot.backlog.items);
493
+ const postFinalizeReplan = buildPostFinalizeReplan(snapshot.backlog.items, finalized, Array.from(unblocked).sort(), now);
424
494
  const stateUpdates = {
425
495
  discoveryIndex: snapshot.discoveryIndex,
426
496
  backlog: snapshot.backlog,
@@ -454,6 +524,7 @@ export class FinalizeService {
454
524
  finalized,
455
525
  unblocked: Array.from(unblocked).sort(),
456
526
  pending: remaining,
527
+ post_finalize_replan: postFinalizeReplan,
457
528
  updated_core_docs: Array.from(updatedCoreDocs).sort(),
458
529
  updated_readme: syncResult.updatedReadme,
459
530
  updated_agent_guide: syncResult.updatedAgentGuide || syncResult.updatedRootAgents,
@@ -643,6 +714,7 @@ export async function evaluateWorkspaceQualityFeedback(paths, config, feature) {
643
714
  }
644
715
  const missingTargets = missingCoverageTargets(document);
645
716
  const missingSkills = missingSkillEvidence(document);
717
+ const criticalProvenanceReasons = missingCriticalEvidenceProvenance(document);
646
718
  const matrixReasons = evaluateQualityWitnessMatrix(document);
647
719
  const reasons = [];
648
720
  const maxRounds = document.remediation_policy.max_rounds;
@@ -670,6 +742,9 @@ export async function evaluateWorkspaceQualityFeedback(paths, config, feature) {
670
742
  if (missingSkills.length > 0) {
671
743
  reasons.push(`required skill evidence missing for ${missingSkills.join(', ')}`);
672
744
  }
745
+ if (criticalProvenanceReasons.length > 0) {
746
+ reasons.push(...criticalProvenanceReasons);
747
+ }
673
748
  if (matrixReasons.length > 0) {
674
749
  reasons.push(`quality-witness matrix blocked finalize: ${matrixReasons.join(' | ')}`);
675
750
  }
@@ -825,19 +900,65 @@ export function computeIntegrityAxis(document) {
825
900
  integritySignalScore(security.sensitive_data_exposure_review),
826
901
  integritySignalScore(security.incident_response_review),
827
902
  ].reduce((acc, value) => acc + value, 0) / 3);
828
- const raw = round2(skillScore * 0.7 + securityScore * 0.3);
903
+ const runtimeQuality = computeRuntimeQualityAxis(document);
904
+ const raw = round2(skillScore * 0.55 + securityScore * 0.25 + runtimeQuality.raw_score * 0.2);
829
905
  return {
830
906
  raw_score: raw,
831
- rationale: `skill_evidence=${skillScore.toFixed(2)} security_integrity=${securityScore.toFixed(2)}`,
907
+ rationale: `skill_evidence=${skillScore.toFixed(2)} security_integrity=${securityScore.toFixed(2)} runtime_quality=${runtimeQuality.raw_score.toFixed(2)} (${runtimeQuality.rationale})`,
908
+ };
909
+ }
910
+ export function computeRuntimeQualityAxis(document) {
911
+ const gates = document.runtime_quality_gates;
912
+ const performance = gates?.performance ?? [];
913
+ const flakiness = gates?.flakiness ?? [];
914
+ const entries = [
915
+ ...performance.map((entry) => ({ kind: 'performance', gate: entry.gate, evidence: entry.evidence_ref, score: runtimePerformanceScore(entry) })),
916
+ ...flakiness.map((entry) => ({ kind: 'flakiness', gate: entry.gate, evidence: entry.evidence_ref, score: runtimeFlakinessScore(entry) })),
917
+ ];
918
+ if (entries.length === 0) {
919
+ return {
920
+ raw_score: 100,
921
+ rationale: 'runtime quality telemetry not provided; neutral score applied',
922
+ };
923
+ }
924
+ const scores = entries.map((entry) => {
925
+ if (entry.gate === 'fail')
926
+ return Math.min(entry.score, 70);
927
+ if (entry.gate === 'warn')
928
+ return Math.min(entry.score, 85);
929
+ return entry.score;
930
+ });
931
+ const worst = Math.min(...scores);
932
+ const failed = entries.filter((entry) => entry.gate === 'fail').map((entry) => `${entry.kind}:${entry.evidence ?? 'runtime evidence'}`);
933
+ const warned = entries.filter((entry) => entry.gate === 'warn').map((entry) => `${entry.kind}:${entry.evidence ?? 'runtime evidence'}`);
934
+ const notes = [...failed.map((value) => `${value} failed`), ...warned.map((value) => `${value} warned`)];
935
+ return {
936
+ raw_score: worst,
937
+ rationale: `runtime quality gate scored ${worst.toFixed(2)}${notes.length > 0 ? `; ${notes.join('; ')}` : ''}`,
832
938
  };
833
939
  }
940
+ function runtimePerformanceScore(entry) {
941
+ if (entry.actual !== undefined && entry.threshold !== undefined && entry.threshold > 0) {
942
+ return clampPercent((entry.threshold / Math.max(entry.actual, 1)) * 100);
943
+ }
944
+ return entry.gate === 'pass' ? 100 : entry.gate === 'warn' ? 85 : 70;
945
+ }
946
+ function runtimeFlakinessScore(entry) {
947
+ let failureRate = entry.failure_rate_percent;
948
+ if (failureRate === undefined && entry.attempts !== undefined && entry.failures !== undefined && entry.attempts > 0) {
949
+ failureRate = clampPercent((entry.failures / entry.attempts) * 100);
950
+ }
951
+ if (failureRate === undefined) {
952
+ return entry.gate === 'pass' ? 100 : entry.gate === 'warn' ? 85 : 70;
953
+ }
954
+ return clampPercent(100 - failureRate);
955
+ }
834
956
  const LEGACY_NAMING_PATTERNS = [
835
957
  /\bcoachsdd\b/u,
836
958
  /\bcoach\s+sdd\b/u,
837
959
  /\bcoach-sdd\b/u,
838
960
  /\bcoach_sdd\b/u,
839
961
  /\bsdd\s+coach\b/u,
840
- /\.codesdd\b/u,
841
962
  ];
842
963
  export function computeNamingAxis(feature, document) {
843
964
  let score = 100;
@@ -861,6 +982,10 @@ export function computeNamingAxis(feature, document) {
861
982
  };
862
983
  }
863
984
  export function computeTokenAxis(document) {
985
+ const structuredTelemetry = document.token_budget_gates?.telemetry ?? [];
986
+ if (structuredTelemetry.length > 0) {
987
+ return computeStructuredTokenAxis(document);
988
+ }
864
989
  const tokenEntries = document.evidence_log.filter((entry) => {
865
990
  const label = `${entry.kind} ${entry.result}`.toLowerCase();
866
991
  return label.includes('token');
@@ -893,6 +1018,59 @@ export function computeTokenAxis(document) {
893
1018
  rationale: 'token evidence found but no numeric percentage; conservative score applied',
894
1019
  };
895
1020
  }
1021
+ export function computeStructuredTokenAxis(document) {
1022
+ const gates = document.token_budget_gates;
1023
+ const telemetry = gates?.telemetry ?? [];
1024
+ const requireNumeric = gates?.require_numeric_efficiency ?? true;
1025
+ const failBelow = gates?.fail_below_percent ?? 95;
1026
+ const scores = [];
1027
+ const reasons = [];
1028
+ let hardFailure = false;
1029
+ for (const entry of telemetry) {
1030
+ let score = entry.efficiency_percent;
1031
+ if (score === undefined && entry.budget_chars !== undefined && entry.actual_chars !== undefined) {
1032
+ score = entry.actual_chars === 0 ? 100 : clampPercent((entry.budget_chars / entry.actual_chars) * 100);
1033
+ }
1034
+ if (score === undefined && entry.actual_chars !== undefined && gates?.max_context_chars !== undefined) {
1035
+ score = entry.actual_chars === 0 ? 100 : clampPercent((gates.max_context_chars / entry.actual_chars) * 100);
1036
+ }
1037
+ if (score === undefined) {
1038
+ if (requireNumeric) {
1039
+ scores.push(70);
1040
+ reasons.push(`${entry.evidence_ref ?? 'token telemetry'} lacks numeric efficiency`);
1041
+ }
1042
+ continue;
1043
+ }
1044
+ const normalized = clampPercent(score);
1045
+ scores.push(normalized);
1046
+ if (entry.gate === 'fail' || normalized < failBelow) {
1047
+ hardFailure = true;
1048
+ reasons.push(`${entry.evidence_ref ?? 'token telemetry'} below ${failBelow}%`);
1049
+ }
1050
+ else if (entry.gate === 'warn') {
1051
+ reasons.push(`${entry.evidence_ref ?? 'token telemetry'} warned at ${normalized.toFixed(2)}%`);
1052
+ }
1053
+ }
1054
+ if (scores.length === 0) {
1055
+ return {
1056
+ raw_score: requireNumeric ? 70 : 100,
1057
+ rationale: requireNumeric
1058
+ ? 'token budget gate requires numeric efficiency but no numeric telemetry was provided'
1059
+ : 'token budget telemetry provided without numeric scoring requirement',
1060
+ };
1061
+ }
1062
+ const worst = Math.min(...scores);
1063
+ if (hardFailure) {
1064
+ return {
1065
+ raw_score: Math.min(worst, 70),
1066
+ rationale: `token budget gate failed: ${reasons.join('; ')}`,
1067
+ };
1068
+ }
1069
+ return {
1070
+ raw_score: worst,
1071
+ rationale: `token budget gate satisfied (${worst.toFixed(2)}% worst-case efficiency)${reasons.length > 0 ? `; ${reasons.join('; ')}` : ''}`,
1072
+ };
1073
+ }
896
1074
  export function extractCoveragePerformance(document, kind) {
897
1075
  const target = kind === 'unit' ? document.coverage_targets.unit : document.coverage_targets.integration;
898
1076
  const relevant = document.evidence_log.filter((entry) => {
@@ -1003,4 +1181,34 @@ export function missingSkillEvidence(document) {
1003
1181
  .filter(Boolean));
1004
1182
  return required.filter((skillId) => !provided.has(skillId.toLowerCase()));
1005
1183
  }
1184
+ export function missingCriticalEvidenceProvenance(document) {
1185
+ const reasons = [];
1186
+ document.evidence_log.forEach((entry, index) => {
1187
+ if (entry.critical !== true) {
1188
+ return;
1189
+ }
1190
+ const provenance = entry.provenance;
1191
+ if (!provenance) {
1192
+ reasons.push(`critical evidence_log[${index}] (${entry.kind}) missing provenance (command, exit_code, timestamp_iso, commit_sha, artifact_path, artifact_hash)`);
1193
+ return;
1194
+ }
1195
+ const missingFields = [];
1196
+ if (!provenance.command?.trim())
1197
+ missingFields.push('command');
1198
+ if (!Number.isInteger(provenance.exit_code))
1199
+ missingFields.push('exit_code');
1200
+ if (!provenance.timestamp_iso?.trim())
1201
+ missingFields.push('timestamp_iso');
1202
+ if (!provenance.commit_sha?.trim())
1203
+ missingFields.push('commit_sha');
1204
+ if (!provenance.artifact_path?.trim())
1205
+ missingFields.push('artifact_path');
1206
+ if (!provenance.artifact_hash?.trim())
1207
+ missingFields.push('artifact_hash');
1208
+ if (missingFields.length > 0) {
1209
+ reasons.push(`critical evidence_log[${index}] (${entry.kind}) missing provenance fields: ${missingFields.join(', ')}`);
1210
+ }
1211
+ });
1212
+ return reasons;
1213
+ }
1006
1214
  //# sourceMappingURL=finalize.service.js.map
@@ -10,7 +10,7 @@ export declare class FrontendImpactService {
10
10
  render?: boolean;
11
11
  }): Promise<{
12
12
  feature_id: string;
13
- frontend_impact_status: "unknown" | "none" | "required";
13
+ frontend_impact_status: "none" | "unknown" | "required";
14
14
  frontend_impact_reason: string;
15
15
  frontend_impact_declared_at: string;
16
16
  frontend_surface_tokens: string[];
@@ -0,0 +1,35 @@
1
+ export type HistoricalQualityRegressionMode = 'recent-window' | 'full-history';
2
+ export type HistoricalQualityRegressionIssueCode = 'ACCEPTANCE_NOT_MET' | 'OPEN_RISK' | 'PLACEHOLDER_EVIDENCE' | 'MISSING_ADR' | 'FRONTEND_IMPACT_UNKNOWN' | 'MISSING_DONE_AT' | 'MISSING_ARCHIVED_AT' | 'STATE_CORE_DIVERGENCE';
3
+ export interface HistoricalQualityRegressionIssue {
4
+ feature_id: string;
5
+ code: HistoricalQualityRegressionIssueCode;
6
+ message: string;
7
+ quality_path?: string;
8
+ backlog_path?: string;
9
+ adr_path?: string;
10
+ }
11
+ export interface HistoricalQualityRegressionReport {
12
+ generated_at: string;
13
+ mode: HistoricalQualityRegressionMode;
14
+ recent_window_size: number | null;
15
+ scanned: number;
16
+ considered: number;
17
+ analyzed: number;
18
+ grandfathered: number;
19
+ issue_count: number;
20
+ grandfathering: {
21
+ enabled: boolean;
22
+ max_feat_id: number;
23
+ policy: string;
24
+ };
25
+ issues: HistoricalQualityRegressionIssue[];
26
+ }
27
+ export interface HistoricalQualityRegressionOptions {
28
+ mode?: HistoricalQualityRegressionMode;
29
+ recentWindowSize?: number;
30
+ grandfatherMaxFeat?: number;
31
+ }
32
+ export declare class HistoricalQualityRegressionService {
33
+ execute(projectRoot: string, options?: HistoricalQualityRegressionOptions): Promise<HistoricalQualityRegressionReport>;
34
+ }
35
+ //# sourceMappingURL=historical-quality-regression.service.d.ts.map
@@ -0,0 +1,228 @@
1
+ import { existsSync, promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import { parseWorkspaceYamlDocument } from '../workspace-schemas.js';
5
+ const PLACEHOLDER_PATTERNS = [
6
+ /\(fill in/i,
7
+ /\(placeholder/i,
8
+ /\btodo\b/i,
9
+ /\btbd\b/i,
10
+ /\bpending\b/i,
11
+ /\bmust implement\b/i,
12
+ /\bto be executed\b/i,
13
+ /\bplanned\b/i,
14
+ /\bwill be\b/i,
15
+ /\bto do\b/i,
16
+ ];
17
+ const DEFAULT_RECENT_WINDOW_SIZE = 25;
18
+ const DEFAULT_GRANDFATHER_MAX_FEAT = 451;
19
+ function featNumericId(featureId) {
20
+ const match = featureId.match(/^FEAT-(\d{4,})$/);
21
+ if (!match)
22
+ return null;
23
+ return Number.parseInt(match[1] || '', 10);
24
+ }
25
+ function hasPlaceholderSignal(text) {
26
+ return PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(text));
27
+ }
28
+ function hasPlaceholderEvidence(document) {
29
+ const evidenceTexts = [
30
+ ...document.evidence_log.flatMap((entry) => [entry.kind, entry.result, entry.artifact ?? '']),
31
+ ...document.acceptance_matrix.flatMap((entry) => [entry.criterion, entry.evidence]),
32
+ ];
33
+ return evidenceTexts.some((text) => text && hasPlaceholderSignal(text));
34
+ }
35
+ function sortFeaturesByRecency(featureIds) {
36
+ return [...featureIds].sort((left, right) => {
37
+ const leftNum = featNumericId(left);
38
+ const rightNum = featNumericId(right);
39
+ if (leftNum !== null && rightNum !== null && leftNum !== rightNum) {
40
+ return rightNum - leftNum;
41
+ }
42
+ if (leftNum !== null && rightNum === null)
43
+ return -1;
44
+ if (leftNum === null && rightNum !== null)
45
+ return 1;
46
+ return right.localeCompare(left);
47
+ });
48
+ }
49
+ async function loadBacklogEvidence(backlogPath) {
50
+ const map = new Map();
51
+ if (!existsSync(backlogPath))
52
+ return map;
53
+ const raw = await fs.readFile(backlogPath, 'utf-8').catch(() => '');
54
+ if (!raw.trim())
55
+ return map;
56
+ const parsed = parseYaml(raw);
57
+ for (const item of parsed.items ?? []) {
58
+ const id = typeof item.id === 'string' ? item.id : '';
59
+ if (!id.startsWith('FEAT-'))
60
+ continue;
61
+ map.set(id, {
62
+ id,
63
+ status: typeof item.status === 'string' ? item.status : undefined,
64
+ frontend_impact_status: typeof item.frontend_impact_status === 'string' ? item.frontend_impact_status : undefined,
65
+ done_at: typeof item.done_at === 'string' ? item.done_at : undefined,
66
+ archived_at: typeof item.archived_at === 'string' ? item.archived_at : undefined,
67
+ });
68
+ }
69
+ return map;
70
+ }
71
+ export class HistoricalQualityRegressionService {
72
+ async execute(projectRoot, options = {}) {
73
+ const mode = options.mode ?? 'recent-window';
74
+ const recentWindowSize = options.recentWindowSize ?? DEFAULT_RECENT_WINDOW_SIZE;
75
+ const grandfatherMaxFeat = options.grandfatherMaxFeat ?? DEFAULT_GRANDFATHER_MAX_FEAT;
76
+ const archivedDir = path.join(projectRoot, '.sdd', 'archived');
77
+ const backlogPath = path.join(projectRoot, '.sdd', 'state', 'backlog.yaml');
78
+ const adrsDir = path.join(projectRoot, '.sdd', 'core', 'adrs');
79
+ const backlogByFeature = await loadBacklogEvidence(backlogPath);
80
+ if (!existsSync(archivedDir)) {
81
+ return {
82
+ generated_at: new Date().toISOString(),
83
+ mode,
84
+ recent_window_size: mode === 'recent-window' ? recentWindowSize : null,
85
+ scanned: 0,
86
+ considered: 0,
87
+ analyzed: 0,
88
+ grandfathered: 0,
89
+ issue_count: 0,
90
+ grandfathering: {
91
+ enabled: true,
92
+ max_feat_id: grandfatherMaxFeat,
93
+ policy: `Skip blocking regression checks for archived FEAT ids <= FEAT-${String(grandfatherMaxFeat).padStart(4, '0')}.`,
94
+ },
95
+ issues: [],
96
+ };
97
+ }
98
+ const entries = await fs.readdir(archivedDir, { withFileTypes: true });
99
+ const scannedFeatures = entries
100
+ .filter((entry) => entry.isDirectory() && entry.name.startsWith('FEAT-'))
101
+ .map((entry) => entry.name);
102
+ const orderedFeatures = sortFeaturesByRecency(scannedFeatures);
103
+ const consideredFeatures = mode === 'recent-window' ? orderedFeatures.slice(0, Math.max(1, recentWindowSize)) : orderedFeatures;
104
+ let analyzed = 0;
105
+ let grandfathered = 0;
106
+ const issues = [];
107
+ for (const featureId of consideredFeatures) {
108
+ const numericId = featNumericId(featureId);
109
+ if (numericId !== null && numericId <= grandfatherMaxFeat) {
110
+ grandfathered += 1;
111
+ continue;
112
+ }
113
+ const backlog = backlogByFeature.get(featureId);
114
+ const qualityPath = path.join(archivedDir, featureId, '5-quality.yaml');
115
+ const adrPath = path.join(adrsDir, `ADR-${featureId}.md`);
116
+ if (!backlog) {
117
+ issues.push({
118
+ feature_id: featureId,
119
+ code: 'STATE_CORE_DIVERGENCE',
120
+ message: `${featureId} is archived but missing from .sdd/state/backlog.yaml.`,
121
+ backlog_path: backlogPath,
122
+ });
123
+ }
124
+ if (backlog && backlog.status && !['DONE', 'ARCHIVED'].includes(backlog.status)) {
125
+ issues.push({
126
+ feature_id: featureId,
127
+ code: 'STATE_CORE_DIVERGENCE',
128
+ message: `${featureId} is archived on disk but backlog status is ${backlog.status}.`,
129
+ backlog_path: backlogPath,
130
+ });
131
+ }
132
+ if (backlog && (backlog.frontend_impact_status ?? 'unknown') === 'unknown') {
133
+ issues.push({
134
+ feature_id: featureId,
135
+ code: 'FRONTEND_IMPACT_UNKNOWN',
136
+ message: `${featureId} has frontend_impact_status=unknown in backlog state.`,
137
+ backlog_path: backlogPath,
138
+ });
139
+ }
140
+ if (backlog && !backlog.done_at) {
141
+ issues.push({
142
+ feature_id: featureId,
143
+ code: 'MISSING_DONE_AT',
144
+ message: `${featureId} is archived without done_at in backlog state.`,
145
+ backlog_path: backlogPath,
146
+ });
147
+ }
148
+ if (backlog && !backlog.archived_at) {
149
+ issues.push({
150
+ feature_id: featureId,
151
+ code: 'MISSING_ARCHIVED_AT',
152
+ message: `${featureId} is archived without archived_at in backlog state.`,
153
+ backlog_path: backlogPath,
154
+ });
155
+ }
156
+ if (!existsSync(adrPath)) {
157
+ issues.push({
158
+ feature_id: featureId,
159
+ code: 'MISSING_ADR',
160
+ message: `${featureId} is missing required ADR file at .sdd/core/adrs/ADR-${featureId}.md.`,
161
+ adr_path: adrPath,
162
+ });
163
+ issues.push({
164
+ feature_id: featureId,
165
+ code: 'STATE_CORE_DIVERGENCE',
166
+ message: `${featureId} has no ADR in .sdd/core/adrs while archived state exists.`,
167
+ adr_path: adrPath,
168
+ });
169
+ }
170
+ if (!existsSync(qualityPath)) {
171
+ continue;
172
+ }
173
+ const rawQuality = await fs.readFile(qualityPath, 'utf-8').catch(() => '');
174
+ if (!rawQuality.trim()) {
175
+ continue;
176
+ }
177
+ let quality;
178
+ try {
179
+ quality = parseWorkspaceYamlDocument('5-quality.yaml', rawQuality);
180
+ }
181
+ catch {
182
+ continue;
183
+ }
184
+ analyzed += 1;
185
+ if (quality.acceptance_matrix.some((entry) => entry.status === 'not_met')) {
186
+ issues.push({
187
+ feature_id: featureId,
188
+ code: 'ACCEPTANCE_NOT_MET',
189
+ message: `${featureId} contains acceptance_matrix.status=not_met in archived quality evidence.`,
190
+ quality_path: qualityPath,
191
+ });
192
+ }
193
+ if (quality.requirement_validation_evidence_risk_matrix.some((entry) => entry.risk_status === 'open')) {
194
+ issues.push({
195
+ feature_id: featureId,
196
+ code: 'OPEN_RISK',
197
+ message: `${featureId} contains requirement risk_status=open in archived quality evidence.`,
198
+ quality_path: qualityPath,
199
+ });
200
+ }
201
+ if (hasPlaceholderEvidence(quality)) {
202
+ issues.push({
203
+ feature_id: featureId,
204
+ code: 'PLACEHOLDER_EVIDENCE',
205
+ message: `${featureId} still includes placeholder or future-tense evidence markers.`,
206
+ quality_path: qualityPath,
207
+ });
208
+ }
209
+ }
210
+ return {
211
+ generated_at: new Date().toISOString(),
212
+ mode,
213
+ recent_window_size: mode === 'recent-window' ? recentWindowSize : null,
214
+ scanned: orderedFeatures.length,
215
+ considered: consideredFeatures.length,
216
+ analyzed,
217
+ grandfathered,
218
+ issue_count: issues.length,
219
+ grandfathering: {
220
+ enabled: true,
221
+ max_feat_id: grandfatherMaxFeat,
222
+ policy: `Skip blocking regression checks for archived FEAT ids <= FEAT-${String(grandfatherMaxFeat).padStart(4, '0')}.`,
223
+ },
224
+ issues,
225
+ };
226
+ }
227
+ }
228
+ //# sourceMappingURL=historical-quality-regression.service.js.map
@@ -224,7 +224,7 @@ export class IngestDepositoService {
224
224
  'frontend-extractor-sdd',
225
225
  'planning-normalizer-sdd',
226
226
  ],
227
- recommended_prompt: relProjectPath(paths, path.join(paths.promptsDir, '01-ingestao-deposito.md')),
227
+ recommended_prompt: relProjectPath(paths, path.join(paths.promptsDir, config.layout === 'en-US' ? '01-source-intake.md' : '01-ingestao-deposito.md')),
228
228
  };
229
229
  }
230
230
  }
@@ -0,0 +1,45 @@
1
+ import { type WorkspaceChangelogDocument, type WorkspacePlanDocument, type WorkspaceQualityDocument, type WorkspaceSpecDocument, type WorkspaceTasksDocument } from '../workspace-schemas.js';
2
+ export type PlanningExecutionCoherenceIssueCode = 'MISSING_FILE_EVIDENCE' | 'MISSING_COMMAND_EVIDENCE' | 'ACCEPTANCE_NOT_MET' | 'RISK_STATUS_OPEN' | 'ADR_MISSING';
3
+ export interface PlanningExecutionCoherenceIssue {
4
+ code: PlanningExecutionCoherenceIssueCode;
5
+ severity: 'error' | 'warning';
6
+ message: string;
7
+ evidence: Record<string, unknown>;
8
+ }
9
+ export interface PlanningExecutionCoherenceReport {
10
+ schema_version: 1;
11
+ feature_id: string;
12
+ generated_at: string;
13
+ workspace_path: string;
14
+ adr_path: string;
15
+ healthy: boolean;
16
+ planned: {
17
+ files: string[];
18
+ commands: string[];
19
+ };
20
+ execution: {
21
+ files: string[];
22
+ commands: string[];
23
+ };
24
+ issues: PlanningExecutionCoherenceIssue[];
25
+ }
26
+ export interface EvaluatePlanningExecutionCoherenceInput {
27
+ featureId: string;
28
+ workspacePath: string;
29
+ adrPath: string;
30
+ adrExists: boolean;
31
+ spec: WorkspaceSpecDocument;
32
+ plan: WorkspacePlanDocument;
33
+ tasks: WorkspaceTasksDocument;
34
+ changelog: WorkspaceChangelogDocument;
35
+ quality: WorkspaceQualityDocument;
36
+ changedFiles: string[];
37
+ }
38
+ export interface PlanningExecutionCoherenceOptions {
39
+ changedFiles?: string[];
40
+ }
41
+ export declare function evaluatePlanningExecutionCoherence(input: EvaluatePlanningExecutionCoherenceInput): PlanningExecutionCoherenceReport;
42
+ export declare class PlanningExecutionCoherenceService {
43
+ execute(projectRoot: string, featureId: string, options?: PlanningExecutionCoherenceOptions): Promise<PlanningExecutionCoherenceReport>;
44
+ }
45
+ //# sourceMappingURL=planning-execution-coherence.service.d.ts.map