@devtrack-solution/codesdd 1.2.2 → 1.2.4-rc3

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 (413) hide show
  1. package/.sdd/skills/curated/api-clean-flask-langgraph/SKILL.md +17 -17
  2. package/.sdd/skills/curated/devtrack-api/SKILL.md +170 -31
  3. package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +8 -0
  4. package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +8 -0
  5. package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +8 -0
  6. package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +8 -0
  7. package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +8 -0
  8. package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +4 -2
  9. package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +10 -0
  10. package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +2 -2
  11. package/.sdd/skills/curated/devtrack-api/references/architecture-governance.md +8 -7
  12. package/.sdd/skills/curated/devtrack-api/references/consumer-sync-policy.md +93 -0
  13. package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +372 -0
  14. package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +13 -13
  15. package/.sdd/skills/curated/devtrack-api/references/field-validation-protocol.md +95 -0
  16. package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +294 -0
  17. package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +5 -5
  18. package/.sdd/skills/curated/devtrack-api/references/imports-lint.md +4 -0
  19. package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +41 -0
  20. package/.sdd/skills/curated/devtrack-api/references/testing-validation.md +2 -2
  21. package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +7 -9
  22. package/LICENSE +1 -1
  23. package/README.md +399 -53
  24. package/bin/codesdd.js +3 -2
  25. package/dist/applications/sdd/index.d.ts +16 -0
  26. package/dist/applications/sdd/index.js +16 -0
  27. package/dist/cli/index.d.ts +2 -2
  28. package/dist/cli/index.js +11 -558
  29. package/dist/cli/program.d.ts +14 -0
  30. package/dist/cli/program.js +645 -0
  31. package/dist/commands/change.js +5 -5
  32. package/dist/commands/completion.d.ts +1 -1
  33. package/dist/commands/completion.js +9 -2
  34. package/dist/commands/config.js +320 -20
  35. package/dist/commands/feedback.js +1 -1
  36. package/dist/commands/schema.d.ts +63 -0
  37. package/dist/commands/schema.js +12 -12
  38. package/dist/commands/sdd/backlog.d.ts +3 -0
  39. package/dist/commands/sdd/backlog.js +54 -0
  40. package/dist/commands/sdd/execution.js +489 -28
  41. package/dist/commands/sdd/plugin.d.ts +3 -0
  42. package/dist/commands/sdd/plugin.js +158 -0
  43. package/dist/commands/sdd/shared.d.ts +1 -0
  44. package/dist/commands/sdd/shared.js +11 -22
  45. package/dist/commands/sdd/skills.js +7 -0
  46. package/dist/commands/sdd.js +107 -15
  47. package/dist/commands/spec.js +9 -9
  48. package/dist/commands/validate.js +6 -6
  49. package/dist/commands/workflow/instructions.js +6 -6
  50. package/dist/commands/workflow/new-change.js +3 -3
  51. package/dist/commands/workflow/shared.d.ts +1 -1
  52. package/dist/commands/workflow/shared.js +4 -4
  53. package/dist/core/archive.js +15 -5
  54. package/dist/core/artifact-graph/instruction-loader.d.ts +1 -1
  55. package/dist/core/artifact-graph/instruction-loader.js +3 -3
  56. package/dist/core/artifact-graph/resolver.d.ts +4 -4
  57. package/dist/core/artifact-graph/resolver.js +6 -6
  58. package/dist/core/branding.js +3 -3
  59. package/dist/core/cli/command-matrix.js +19 -1
  60. package/dist/core/cli-command-quality.d.ts +27 -0
  61. package/dist/core/cli-command-quality.js +180 -0
  62. package/dist/core/command-generation/adapters/costrict.d.ts +1 -1
  63. package/dist/core/command-generation/adapters/costrict.js +2 -2
  64. package/dist/core/command-generation/types.d.ts +1 -1
  65. package/dist/core/completions/command-registry.d.ts +1 -1
  66. package/dist/core/completions/command-registry.js +200 -12
  67. package/dist/core/completions/completion-provider.d.ts +14 -1
  68. package/dist/core/completions/completion-provider.js +29 -1
  69. package/dist/core/completions/generators/bash-generator.d.ts +1 -1
  70. package/dist/core/completions/generators/bash-generator.js +20 -12
  71. package/dist/core/completions/generators/fish-generator.d.ts +9 -1
  72. package/dist/core/completions/generators/fish-generator.js +39 -25
  73. package/dist/core/completions/generators/powershell-generator.d.ts +1 -1
  74. package/dist/core/completions/generators/powershell-generator.js +21 -11
  75. package/dist/core/completions/generators/zsh-generator.d.ts +3 -6
  76. package/dist/core/completions/generators/zsh-generator.js +21 -42
  77. package/dist/core/completions/installers/bash-installer.js +6 -6
  78. package/dist/core/completions/installers/fish-installer.js +1 -1
  79. package/dist/core/completions/installers/powershell-installer.js +14 -14
  80. package/dist/core/completions/installers/zsh-installer.d.ts +7 -1
  81. package/dist/core/completions/installers/zsh-installer.js +36 -8
  82. package/dist/core/completions/templates/bash-templates.d.ts +1 -1
  83. package/dist/core/completions/templates/bash-templates.js +12 -6
  84. package/dist/core/completions/templates/fish-templates.d.ts +2 -2
  85. package/dist/core/completions/templates/fish-templates.js +20 -9
  86. package/dist/core/completions/templates/powershell-templates.d.ts +1 -1
  87. package/dist/core/completions/templates/powershell-templates.js +13 -4
  88. package/dist/core/completions/templates/zsh-templates.d.ts +1 -1
  89. package/dist/core/completions/templates/zsh-templates.js +18 -9
  90. package/dist/core/config-schema.d.ts +20 -1
  91. package/dist/core/config-schema.js +70 -2
  92. package/dist/core/config.d.ts +3 -3
  93. package/dist/core/config.js +4 -4
  94. package/dist/core/global-config.d.ts +57 -12
  95. package/dist/core/global-config.js +344 -27
  96. package/dist/core/index.d.ts +1 -1
  97. package/dist/core/index.js +2 -2
  98. package/dist/core/init.d.ts +6 -1
  99. package/dist/core/init.js +99 -77
  100. package/dist/core/legacy-cleanup.d.ts +17 -17
  101. package/dist/core/legacy-cleanup.js +96 -79
  102. package/dist/core/list.js +18 -4
  103. package/dist/core/migration.d.ts +3 -1
  104. package/dist/core/migration.js +7 -8
  105. package/dist/core/parsers/change-parser.js +1 -1
  106. package/dist/core/parsers/markdown-parser.js +2 -2
  107. package/dist/core/profile-sync-drift.d.ts +1 -1
  108. package/dist/core/profile-sync-drift.js +13 -13
  109. package/dist/core/project-config.d.ts +4 -4
  110. package/dist/core/project-config.js +11 -11
  111. package/dist/core/schemas/change.schema.d.ts +1 -1
  112. package/dist/core/schemas/change.schema.js +1 -1
  113. package/dist/core/schemas/spec.schema.d.ts +1 -1
  114. package/dist/core/schemas/spec.schema.js +1 -1
  115. package/dist/core/sdd/adr.js +23 -1
  116. package/dist/core/sdd/agent-binding.d.ts +346 -0
  117. package/dist/core/sdd/agent-binding.js +343 -0
  118. package/dist/core/sdd/agent-runtime-contract.d.ts +204 -0
  119. package/dist/core/sdd/agent-runtime-contract.js +200 -0
  120. package/dist/core/sdd/backlog-cli.d.ts +16 -0
  121. package/dist/core/sdd/backlog-cli.js +146 -0
  122. package/dist/core/sdd/backlog-conflict-policy.d.ts +58 -0
  123. package/dist/core/sdd/backlog-conflict-policy.js +230 -0
  124. package/dist/core/sdd/backlog-projection.d.ts +8 -0
  125. package/dist/core/sdd/backlog-projection.js +89 -0
  126. package/dist/core/sdd/backlog-provider-contract.d.ts +252 -0
  127. package/dist/core/sdd/backlog-provider-contract.js +158 -0
  128. package/dist/core/sdd/bootstrap.js +2 -2
  129. package/dist/core/sdd/check.d.ts +44 -0
  130. package/dist/core/sdd/check.js +62 -24
  131. package/dist/core/sdd/contract.d.ts +13 -0
  132. package/dist/core/sdd/contract.js +36 -0
  133. package/dist/core/sdd/coordination/coordination-adapters.d.ts +53 -8
  134. package/dist/core/sdd/coordination/coordination-adapters.js +182 -16
  135. package/dist/core/sdd/coordination/index.d.ts +1 -0
  136. package/dist/core/sdd/coordination/index.js +1 -0
  137. package/dist/core/sdd/coordination/redis-runtime.d.ts +131 -0
  138. package/dist/core/sdd/coordination/redis-runtime.js +698 -0
  139. package/dist/core/sdd/deepagent-contracts.d.ts +370 -0
  140. package/dist/core/sdd/deepagent-contracts.js +235 -0
  141. package/dist/core/sdd/deepagents/adr-governor.d.ts +2 -0
  142. package/dist/core/sdd/deepagents/adr-governor.js +30 -0
  143. package/dist/core/sdd/deepagents/backend.d.ts +63 -0
  144. package/dist/core/sdd/deepagents/backend.js +174 -0
  145. package/dist/core/sdd/deepagents/codesdd-tools.d.ts +39 -0
  146. package/dist/core/sdd/deepagents/codesdd-tools.js +83 -0
  147. package/dist/core/sdd/deepagents/evidence-mapper.d.ts +86 -0
  148. package/dist/core/sdd/deepagents/evidence-mapper.js +178 -0
  149. package/dist/core/sdd/deepagents/model-provider.d.ts +53 -0
  150. package/dist/core/sdd/deepagents/model-provider.js +379 -0
  151. package/dist/core/sdd/deepagents/policy-enforcement.d.ts +30 -0
  152. package/dist/core/sdd/deepagents/policy-enforcement.js +90 -0
  153. package/dist/core/sdd/deepagents/policy.d.ts +75 -0
  154. package/dist/core/sdd/deepagents/policy.js +358 -0
  155. package/dist/core/sdd/deepagents/quality-witness.d.ts +3 -0
  156. package/dist/core/sdd/deepagents/quality-witness.js +77 -0
  157. package/dist/core/sdd/deepagents/reversa-subagents.d.ts +75 -0
  158. package/dist/core/sdd/deepagents/reversa-subagents.js +182 -0
  159. package/dist/core/sdd/deepagents/runtime-factory.d.ts +90 -0
  160. package/dist/core/sdd/deepagents/runtime-factory.js +231 -0
  161. package/dist/core/sdd/deepagents/runtime-loader.d.ts +16 -0
  162. package/dist/core/sdd/deepagents/runtime-loader.js +65 -0
  163. package/dist/core/sdd/default-bootstrap-files.d.ts +3 -3
  164. package/dist/core/sdd/default-bootstrap-files.js +50 -10
  165. package/dist/core/sdd/default-skills.d.ts +30 -0
  166. package/dist/core/sdd/default-skills.js +288 -8
  167. package/dist/core/sdd/devtrack-api-appliance.d.ts +91 -0
  168. package/dist/core/sdd/devtrack-api-appliance.js +280 -0
  169. package/dist/core/sdd/devtrack-api-architecture.d.ts +31 -0
  170. package/dist/core/sdd/devtrack-api-architecture.js +608 -0
  171. package/dist/core/sdd/devtrack-api-import-boundary.d.ts +19 -0
  172. package/dist/core/sdd/devtrack-api-import-boundary.js +32 -0
  173. package/dist/core/sdd/diagnose.d.ts +59 -0
  174. package/dist/core/sdd/diagnose.js +37 -37
  175. package/dist/core/sdd/docs-sync.js +54 -20
  176. package/dist/core/sdd/domain/capability-diff.d.ts +63 -0
  177. package/dist/core/sdd/domain/capability-diff.js +200 -0
  178. package/dist/core/sdd/domain/change-safety-guardrails.d.ts +74 -0
  179. package/dist/core/sdd/domain/change-safety-guardrails.js +333 -0
  180. package/dist/core/sdd/domain/post-active-validation.d.ts +7 -0
  181. package/dist/core/sdd/domain/post-active-validation.js +61 -0
  182. package/dist/core/sdd/domain/semantic-intent-classifier.d.ts +29 -0
  183. package/dist/core/sdd/domain/semantic-intent-classifier.js +117 -0
  184. package/dist/core/sdd/domain/transition-engine.js +1 -0
  185. package/dist/core/sdd/entity-reference.d.ts +5 -0
  186. package/dist/core/sdd/entity-reference.js +22 -0
  187. package/dist/core/sdd/foundation-artifact-map-validator.d.ts +16 -0
  188. package/dist/core/sdd/foundation-artifact-map-validator.js +71 -0
  189. package/dist/core/sdd/foundation-layer-manifest.d.ts +24 -0
  190. package/dist/core/sdd/foundation-layer-manifest.js +117 -0
  191. package/dist/core/sdd/governance-backfill.d.ts +31 -0
  192. package/dist/core/sdd/governance-backfill.js +359 -0
  193. package/dist/core/sdd/governance-parser.d.ts +21 -0
  194. package/dist/core/sdd/governance-parser.js +91 -0
  195. package/dist/core/sdd/governance-schemas.d.ts +245 -0
  196. package/dist/core/sdd/governance-schemas.js +143 -0
  197. package/dist/core/sdd/{import-openspec.d.ts → import-legacy-spec.d.ts} +7 -7
  198. package/dist/core/sdd/{import-openspec.js → import-legacy-spec.js} +21 -29
  199. package/dist/core/sdd/init.d.ts +3 -0
  200. package/dist/core/sdd/init.js +6 -3
  201. package/dist/core/sdd/intent-guard.d.ts +22 -0
  202. package/dist/core/sdd/intent-guard.js +67 -0
  203. package/dist/core/sdd/json-schema.js +108 -6
  204. package/dist/core/sdd/knowledge-graph.d.ts +45 -0
  205. package/dist/core/sdd/knowledge-graph.js +288 -0
  206. package/dist/core/sdd/legacy-operations.js +507 -44
  207. package/dist/core/sdd/lenses.d.ts +1 -0
  208. package/dist/core/sdd/lenses.js +29 -1
  209. package/dist/core/sdd/migrate-workspace.js +95 -2
  210. package/dist/core/sdd/migrate.d.ts +1 -1
  211. package/dist/core/sdd/migrate.js +36 -2
  212. package/dist/core/sdd/package-security-gates.d.ts +21 -0
  213. package/dist/core/sdd/package-security-gates.js +119 -0
  214. package/dist/core/sdd/package-structure-gate.d.ts +83 -0
  215. package/dist/core/sdd/package-structure-gate.js +357 -0
  216. package/dist/core/sdd/parallel-feat-automation.d.ts +330 -0
  217. package/dist/core/sdd/parallel-feat-automation.js +424 -0
  218. package/dist/core/sdd/plugin-broker.d.ts +777 -0
  219. package/dist/core/sdd/plugin-broker.js +492 -0
  220. package/dist/core/sdd/plugin-certification.d.ts +79 -0
  221. package/dist/core/sdd/plugin-certification.js +453 -0
  222. package/dist/core/sdd/plugin-cli.d.ts +139 -0
  223. package/dist/core/sdd/plugin-cli.js +265 -0
  224. package/dist/core/sdd/plugin-evidence.d.ts +348 -0
  225. package/dist/core/sdd/plugin-evidence.js +307 -0
  226. package/dist/core/sdd/plugin-manifest.d.ts +232 -0
  227. package/dist/core/sdd/plugin-manifest.js +225 -0
  228. package/dist/core/sdd/plugin-policy-pack.d.ts +88 -0
  229. package/dist/core/sdd/plugin-policy-pack.js +236 -0
  230. package/dist/core/sdd/plugin-policy.d.ts +68 -0
  231. package/dist/core/sdd/plugin-policy.js +212 -0
  232. package/dist/core/sdd/plugin-registry.d.ts +447 -0
  233. package/dist/core/sdd/plugin-registry.js +138 -0
  234. package/dist/core/sdd/plugin-sdk-contract.d.ts +363 -0
  235. package/dist/core/sdd/plugin-sdk-contract.js +268 -0
  236. package/dist/core/sdd/plugin-skill-binding.d.ts +151 -0
  237. package/dist/core/sdd/plugin-skill-binding.js +339 -0
  238. package/dist/core/sdd/quality-artifact-manifest-validator.d.ts +28 -0
  239. package/dist/core/sdd/quality-artifact-manifest-validator.js +167 -0
  240. package/dist/core/sdd/quality-evidence-renderer.d.ts +65 -0
  241. package/dist/core/sdd/quality-evidence-renderer.js +218 -0
  242. package/dist/core/sdd/quality-scenario-runner.d.ts +42 -0
  243. package/dist/core/sdd/quality-scenario-runner.js +613 -0
  244. package/dist/core/sdd/quality-validation.d.ts +620 -0
  245. package/dist/core/sdd/quality-validation.js +239 -0
  246. package/dist/core/sdd/release-readiness.d.ts +19 -0
  247. package/dist/core/sdd/release-readiness.js +472 -0
  248. package/dist/core/sdd/resolve-project-root.d.ts +2 -2
  249. package/dist/core/sdd/resolve-project-root.js +11 -5
  250. package/dist/core/sdd/runtime-boundary-contract.d.ts +45 -0
  251. package/dist/core/sdd/runtime-boundary-contract.js +90 -0
  252. package/dist/core/sdd/sanitize.d.ts +30 -1
  253. package/dist/core/sdd/sanitize.js +23 -23
  254. package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +150 -0
  255. package/dist/core/sdd/sdk-agent-plugin-quality-gates.js +258 -0
  256. package/dist/core/sdd/services/agent-run.service.d.ts +97 -0
  257. package/dist/core/sdd/services/agent-run.service.js +261 -0
  258. package/dist/core/sdd/services/breakdown.service.js +2 -1
  259. package/dist/core/sdd/services/capability-diff.service.d.ts +18 -0
  260. package/dist/core/sdd/services/capability-diff.service.js +26 -0
  261. package/dist/core/sdd/services/change-safety-preflight.service.d.ts +17 -0
  262. package/dist/core/sdd/services/change-safety-preflight.service.js +17 -0
  263. package/dist/core/sdd/services/context.service.d.ts +43 -340
  264. package/dist/core/sdd/services/context.service.js +341 -25
  265. package/dist/core/sdd/services/debate.service.js +15 -2
  266. package/dist/core/sdd/services/feature-lint.service.d.ts +22 -0
  267. package/dist/core/sdd/services/feature-lint.service.js +105 -5
  268. package/dist/core/sdd/services/finalize.service.d.ts +105 -0
  269. package/dist/core/sdd/services/finalize.service.js +499 -38
  270. package/dist/core/sdd/services/frontend-gap.service.js +22 -7
  271. package/dist/core/sdd/services/frontend-impact.service.d.ts +1 -1
  272. package/dist/core/sdd/services/governance-control-plane-runtime-adapters.d.ts +17 -0
  273. package/dist/core/sdd/services/governance-control-plane-runtime-adapters.js +38 -0
  274. package/dist/core/sdd/services/governance-control-plane.service.d.ts +66 -0
  275. package/dist/core/sdd/services/governance-control-plane.service.js +134 -0
  276. package/dist/core/sdd/services/ingest-deposito.service.js +1 -1
  277. package/dist/core/sdd/services/legacy-capability.service.d.ts +10 -7
  278. package/dist/core/sdd/services/legacy-capability.service.js +38 -21
  279. package/dist/core/sdd/services/mcp-runtime.service.d.ts +123 -8
  280. package/dist/core/sdd/services/mcp-runtime.service.js +1085 -33
  281. package/dist/core/sdd/services/onboard.service.js +2 -1
  282. package/dist/core/sdd/services/rebuild.service.js +6 -1
  283. package/dist/core/sdd/services/semantic-intent-classifier.service.d.ts +6 -0
  284. package/dist/core/sdd/services/semantic-intent-classifier.service.js +7 -0
  285. package/dist/core/sdd/services/skills-sync.service.d.ts +17 -5
  286. package/dist/core/sdd/services/skills-sync.service.js +55 -2
  287. package/dist/core/sdd/services/start.service.js +6 -4
  288. package/dist/core/sdd/skill-bundles-curation-schema.d.ts +66 -0
  289. package/dist/core/sdd/skill-bundles-curation-schema.js +52 -0
  290. package/dist/core/sdd/skill-evidence.d.ts +19 -0
  291. package/dist/core/sdd/skill-evidence.js +38 -0
  292. package/dist/core/sdd/skill-policy-pool.d.ts +46 -0
  293. package/dist/core/sdd/skill-policy-pool.js +185 -0
  294. package/dist/core/sdd/state.d.ts +23 -0
  295. package/dist/core/sdd/state.js +313 -66
  296. package/dist/core/sdd/store/sdd-stores.js +2 -2
  297. package/dist/core/sdd/structural-health.d.ts +55 -55
  298. package/dist/core/sdd/types.d.ts +60 -19
  299. package/dist/core/sdd/types.js +21 -0
  300. package/dist/core/sdd/upgrade-to-codesdd.d.ts +45 -0
  301. package/dist/core/sdd/upgrade-to-codesdd.js +179 -0
  302. package/dist/core/sdd/views.js +17 -0
  303. package/dist/core/sdd/workspace-schemas.d.ts +670 -19
  304. package/dist/core/sdd/workspace-schemas.js +285 -5
  305. package/dist/core/sdd/write-manifest.js +22 -4
  306. package/dist/core/shared/skill-generation.d.ts +1 -1
  307. package/dist/core/shared/skill-generation.js +15 -15
  308. package/dist/core/shared/tool-detection.d.ts +3 -3
  309. package/dist/core/shared/tool-detection.js +14 -14
  310. package/dist/core/specs-apply.js +6 -6
  311. package/dist/core/templates/index.d.ts +1 -1
  312. package/dist/core/templates/index.js +1 -1
  313. package/dist/core/templates/workflows/apply-change.js +14 -14
  314. package/dist/core/templates/workflows/archive-change.js +32 -32
  315. package/dist/core/templates/workflows/bulk-archive-change.js +25 -25
  316. package/dist/core/templates/workflows/continue-change.js +12 -12
  317. package/dist/core/templates/workflows/explore.js +29 -29
  318. package/dist/core/templates/workflows/feedback.js +6 -6
  319. package/dist/core/templates/workflows/ff-change.js +24 -24
  320. package/dist/core/templates/workflows/new-change.js +20 -20
  321. package/dist/core/templates/workflows/onboard.js +33 -33
  322. package/dist/core/templates/workflows/propose.js +23 -23
  323. package/dist/core/templates/workflows/sdd.js +8 -8
  324. package/dist/core/templates/workflows/sync-specs.js +19 -19
  325. package/dist/core/templates/workflows/verify-change.js +17 -17
  326. package/dist/core/update.d.ts +2 -2
  327. package/dist/core/update.js +16 -15
  328. package/dist/core/validation/constants.d.ts +1 -1
  329. package/dist/core/validation/constants.js +1 -1
  330. package/dist/core/view.js +11 -11
  331. package/dist/domains/sdd/index.d.ts +6 -0
  332. package/dist/domains/sdd/index.js +6 -0
  333. package/dist/infrastructures/sdd/index.d.ts +7 -0
  334. package/dist/infrastructures/sdd/index.js +6 -0
  335. package/dist/presentations/cli/sdd/index.d.ts +3 -0
  336. package/dist/presentations/cli/sdd/index.js +3 -0
  337. package/dist/shared/sdd/index.d.ts +3 -0
  338. package/dist/shared/sdd/index.js +2 -0
  339. package/dist/telemetry/config.d.ts +2 -1
  340. package/dist/telemetry/config.js +17 -8
  341. package/dist/telemetry/index.d.ts +10 -2
  342. package/dist/telemetry/index.js +40 -7
  343. package/dist/ui/ascii-patterns.d.ts +2 -2
  344. package/dist/ui/ascii-patterns.js +2 -2
  345. package/dist/ui/welcome-screen.js +2 -2
  346. package/dist/utils/change-metadata.d.ts +4 -4
  347. package/dist/utils/change-metadata.js +6 -6
  348. package/dist/utils/change-utils.d.ts +3 -3
  349. package/dist/utils/change-utils.js +5 -5
  350. package/dist/utils/file-system.js +1 -1
  351. package/dist/utils/interactive.js +1 -1
  352. package/dist/utils/item-discovery.js +4 -4
  353. package/dist/utils/legacy-spec-compat.d.ts +2 -0
  354. package/dist/utils/legacy-spec-compat.js +2 -0
  355. package/dist/utils/shell-detection.d.ts +1 -0
  356. package/dist/utils/shell-detection.js +16 -0
  357. package/package.json +34 -21
  358. package/schemas/sdd/1-spec.schema.json +1 -1
  359. package/schemas/sdd/2-plan.schema.json +280 -3
  360. package/schemas/sdd/3-tasks.schema.json +73 -1
  361. package/schemas/sdd/4-changelog.schema.json +1 -1
  362. package/schemas/sdd/5-quality.schema.json +701 -5
  363. package/schemas/sdd/adr.schema.json +148 -0
  364. package/schemas/sdd/agent-binding-adapter.schema.json +210 -0
  365. package/schemas/sdd/agent-binding-resolution.schema.json +338 -0
  366. package/schemas/sdd/agent-runtime-command-plan.schema.json +212 -0
  367. package/schemas/sdd/agent-runtime-opencode-run-evidence.schema.json +270 -0
  368. package/schemas/sdd/backlog-projection-plan.schema.json +180 -0
  369. package/schemas/sdd/backlog-provider-contract.schema.json +260 -0
  370. package/schemas/sdd/codesdd-plugin.schema.json +645 -0
  371. package/schemas/sdd/debate.schema.json +244 -0
  372. package/schemas/sdd/deepagent-decision-evidence.schema.json +58 -0
  373. package/schemas/sdd/deepagent-env-contract.schema.json +143 -0
  374. package/schemas/sdd/deepagent-quality-evidence.schema.json +108 -0
  375. package/schemas/sdd/deepagent-run-evidence.schema.json +192 -0
  376. package/schemas/sdd/deepagent-run-plan.schema.json +197 -0
  377. package/schemas/sdd/deepagent-run-request.schema.json +637 -0
  378. package/schemas/sdd/deepagent-subagent-evidence.schema.json +110 -0
  379. package/schemas/sdd/deepagent-tool-call-evidence.schema.json +78 -0
  380. package/schemas/sdd/discarded.schema.json +127 -0
  381. package/schemas/sdd/epic.schema.json +147 -0
  382. package/schemas/sdd/insight.schema.json +136 -0
  383. package/schemas/sdd/parallel-feat-automation-plan.schema.json +304 -0
  384. package/schemas/sdd/parallel-feat-automation-request.schema.json +109 -0
  385. package/schemas/sdd/parallel-feat-scheduler-request.schema.json +116 -0
  386. package/schemas/sdd/parallel-feat-scheduler-result.schema.json +404 -0
  387. package/schemas/sdd/plugin-artifact-manifest.schema.json +259 -0
  388. package/schemas/sdd/plugin-artifact-map.schema.json +223 -0
  389. package/schemas/sdd/plugin-compliance-index.schema.json +136 -0
  390. package/schemas/sdd/plugin-dry-run-plan.schema.json +260 -0
  391. package/schemas/sdd/plugin-evidence-manifest.schema.json +678 -0
  392. package/schemas/sdd/plugin-language-runtime.schema.json +103 -0
  393. package/schemas/sdd/plugin-package-governance.schema.json +74 -0
  394. package/schemas/sdd/plugin-policy-evaluation.schema.json +92 -0
  395. package/schemas/sdd/plugin-policy-pack-evaluation.schema.json +94 -0
  396. package/schemas/sdd/plugin-policy-pack.schema.json +196 -0
  397. package/schemas/sdd/plugin-registry.schema.json +729 -0
  398. package/schemas/sdd/plugin-rollback-manifest.schema.json +87 -0
  399. package/schemas/sdd/plugin-runtime-invocation-plan.schema.json +954 -0
  400. package/schemas/sdd/plugin-skill-binding-resolution.schema.json +305 -0
  401. package/schemas/sdd/plugin-skill-binding.schema.json +88 -0
  402. package/schemas/sdd/plugin-validation-manifest.schema.json +123 -0
  403. package/schemas/sdd/quality-architecture-schema.schema.json +216 -0
  404. package/schemas/sdd/quality-evidence-bundle.schema.json +1337 -0
  405. package/schemas/sdd/quality-run.schema.json +197 -0
  406. package/schemas/sdd/quality-scenario.schema.json +252 -0
  407. package/schemas/sdd/sdk-agent-plugin-quality-gate-input.schema.json +168 -0
  408. package/schemas/sdd/sdk-agent-plugin-quality-gate-report.schema.json +160 -0
  409. package/schemas/sdd/workspace-catalog.schema.json +13232 -35
  410. package/schemas/spec-driven/schema.yaml +4 -4
  411. package/schemas/spec-driven/templates/proposal.md +1 -1
  412. package/dist/utils/openspec-compat.d.ts +0 -2
  413. package/dist/utils/openspec-compat.js +0 -2
@@ -1,19 +1,80 @@
1
1
  import path from "node:path";
2
2
  import { existsSync, promises as fs } from "node:fs";
3
- import { LENSES, validateDocumentAgainstLens } from "../lenses.js";
4
3
  import { adrFileName } from "../adr.js";
4
+ import { evaluateAdrGovernorDocument } from "../deepagents/adr-governor.js";
5
+ import { evaluateQualityWitnessMatrix } from "../deepagents/quality-witness.js";
5
6
  import { evaluateFeatureFinalizeGuardrails } from "../domain/lifecycle-guardrails.js";
6
7
  import { runLifecycleHooks } from "../domain/lifecycle-hooks.js";
7
8
  import { evaluateWorkspaceTraceability } from "../domain/traceability.js";
8
- import { validatePostActiveFeaturePlacement, validatePreFinalizeArchiveCanonicalization, } from "../domain/post-active-validation.js";
9
+ import { normalizeArchivedFeatureActiveReferences, validatePostActiveFeaturePlacement, validatePreFinalizeArchiveCanonicalization, } from "../domain/post-active-validation.js";
9
10
  import { loadStateSnapshot, nowIso, saveStateTransaction } from "../state.js";
10
11
  import { syncSddGuideDocs } from "../docs-sync.js";
11
12
  import { mergeArchitectureNode, mergeFrontendDecisionRecord, mergeRepoMapRecord, mergeServiceRecord, mergeTechStackRecord, stableUniqueStrings, upsertByKey } from "../merge-catalog.js";
12
- 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";
13
14
  import { SddWriteTransaction } from "../write-manifest.js";
14
15
  import { withStateLock } from "../state-lock.js";
15
16
  import { activeWorkspaceDeclaresMandatoryAdrImpact } from "../adr-policy.js";
16
- import { parseWorkspaceYamlDocument, } from "../workspace-schemas.js";
17
+ import { normalizeFeatRef } from "../entity-reference.js";
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
+ function buildPostFinalizeReplan(items, finalized, unlocked, generatedAt) {
47
+ const rank = 'impact';
48
+ const computed = computeReadyFeatures(items, { rank });
49
+ const dependentsMap = buildDependentsMap(items);
50
+ const ready = computed.ready
51
+ .map((item) => {
52
+ const scored = scoreReadyItem(item, items, dependentsMap, rank);
53
+ return {
54
+ id: item.id,
55
+ title: item.title,
56
+ recommended_skills: item.recommended_skills.slice(0, 3),
57
+ score: scored.score,
58
+ reasons: scored.reasons,
59
+ };
60
+ })
61
+ .sort((left, right) => {
62
+ if (right.score !== left.score)
63
+ return right.score - left.score;
64
+ return extractFeatureNumber(left.id) - extractFeatureNumber(right.id);
65
+ })
66
+ .slice(0, 10);
67
+ return {
68
+ rank,
69
+ generated_at: generatedAt,
70
+ finalized,
71
+ unlocked,
72
+ ready,
73
+ waves: computed.waves,
74
+ blocked_count: computed.blocked.length,
75
+ conflicts_count: computed.conflicts.length,
76
+ };
77
+ }
17
78
  export class FinalizeService {
18
79
  stores;
19
80
  constructor(stores) {
@@ -23,6 +84,7 @@ export class FinalizeService {
23
84
  const { config, paths } = await getRuntime(projectRoot);
24
85
  return withStateLock(paths.stateDir, async () => {
25
86
  const snapshot = await loadStateSnapshot(paths, config);
87
+ moveCompletedFinalizeItemsToHistory(snapshot.finalizeQueue);
26
88
  snapshot.finalizeQueue.items = await buildFinalizeQueue(paths, snapshot.backlog.items, snapshot.finalizeQueue.items);
27
89
  const pending = snapshot.finalizeQueue.items.filter((item) => item.status === 'PENDING');
28
90
  const inferredRef = options?.allReady
@@ -45,6 +107,7 @@ export class FinalizeService {
45
107
  finalized: [],
46
108
  unblocked: [],
47
109
  pending: pending.length,
110
+ post_finalize_replan: buildPostFinalizeReplan(snapshot.backlog.items, [], [], nowIso()),
48
111
  updated_core_docs: [],
49
112
  updated_readme: false,
50
113
  updated_agent_guide: false,
@@ -197,6 +260,14 @@ export class FinalizeService {
197
260
  }
198
261
  docWarnings.push(`${feature.id} finalized with --force-transition despite privacy compliance guardrail warnings.`);
199
262
  }
263
+ const devtrackApiPolicyGuardrail = await evaluateDevTrackApiPolicyGates(paths, config, feature);
264
+ if (!devtrackApiPolicyGuardrail.ok) {
265
+ docWarnings.push(`${feature.id} devtrack-api policy gate blocked finalize: ${devtrackApiPolicyGuardrail.reasons.join(' | ')}`);
266
+ if (!options?.forceTransition) {
267
+ continue;
268
+ }
269
+ docWarnings.push(`${feature.id} finalized with --force-transition despite devtrack-api policy gate warnings.`);
270
+ }
200
271
  if (!feature.requires_adr && (await activeWorkspaceDeclaresMandatoryAdrImpact(paths, feature))) {
201
272
  feature.requires_adr = true;
202
273
  }
@@ -204,20 +275,14 @@ export class FinalizeService {
204
275
  const requiredAdrPath = path.join(paths.coreDir, 'adrs', adrFileName(feature.id));
205
276
  const adrContent = await fs.readFile(requiredAdrPath, 'utf-8').catch(() => '');
206
277
  if (!adrContent.trim()) {
207
- docWarnings.push(`${feature.id} exige ADR obrigatório ausente: ${relProjectPath(paths, requiredAdrPath)}`);
208
- if (!options?.forceTransition) {
209
- continue;
210
- }
211
- docWarnings.push(`${feature.id} finalizada com --force-transition sem ADR obrigatório preenchido.`);
278
+ docWarnings.push(`${feature.id} adr governor blocked finalize: ADR obrigatório ausente: ${relProjectPath(paths, requiredAdrPath)}`);
279
+ continue;
212
280
  }
213
281
  else {
214
- const adrViolations = validateDocumentAgainstLens(adrContent, LENSES.adr);
282
+ const adrViolations = evaluateAdrGovernorDocument(adrContent);
215
283
  if (adrViolations.length > 0) {
216
- docWarnings.push(`${feature.id} ADR obrigatório inválido: ${adrViolations.join(' | ')}`);
217
- if (!options?.forceTransition) {
218
- continue;
219
- }
220
- docWarnings.push(`${feature.id} finalizada com --force-transition apesar de violações no ADR obrigatório.`);
284
+ docWarnings.push(`${feature.id} adr governor blocked finalize: ADR obrigatório inválido: ${adrViolations.join(' | ')}`);
285
+ continue;
221
286
  }
222
287
  }
223
288
  }
@@ -261,6 +326,7 @@ export class FinalizeService {
261
326
  afterTransition: (currentFeature) => {
262
327
  currentFeature.current_stage = 'consolidacao';
263
328
  currentFeature.done_at = now;
329
+ currentFeature.archived_at = now;
264
330
  currentFeature.last_sync_at = now;
265
331
  },
266
332
  });
@@ -270,19 +336,14 @@ export class FinalizeService {
270
336
  continue;
271
337
  }
272
338
  const queue = snapshot.finalizeQueue.items.find((item) => item.feature_id === featureId);
273
- if (queue) {
274
- queue.status = 'DONE';
275
- queue.completed_at = now;
276
- }
277
- else {
278
- snapshot.finalizeQueue.items.push({
279
- feature_id: featureId,
280
- status: 'DONE',
281
- summary: `Finalizado manualmente: ${featureId}`,
282
- created_at: now,
283
- completed_at: now,
284
- });
285
- }
339
+ snapshot.finalizeQueue.items = snapshot.finalizeQueue.items.filter((item) => item.feature_id !== featureId);
340
+ recordFinalizeHistory(snapshot.finalizeQueue.history, {
341
+ feature_id: featureId,
342
+ status: 'DONE',
343
+ summary: queue?.summary || `Finalizado manualmente: ${featureId}`,
344
+ created_at: queue?.created_at || now,
345
+ completed_at: now,
346
+ });
286
347
  if ((feature.origin_type === 'radar' || feature.origin_type === 'epic') && feature.origin_ref) {
287
348
  const siblings = snapshot.backlog.items.filter((item) => (item.origin_type === 'radar' || item.origin_type === 'epic') && item.origin_ref === feature.origin_ref);
288
349
  if (siblings.every((item) => item.status === 'DONE' || item.status === 'ARCHIVED')) {
@@ -395,6 +456,7 @@ export class FinalizeService {
395
456
  }
396
457
  await fs.mkdir(paths.archivedDir, { recursive: true });
397
458
  await fs.rename(activeDirPath, archivedDirPath);
459
+ await normalizeArchivedFeatureActiveReferences(paths, feature.id);
398
460
  const postActiveValidation = await validatePostActiveFeaturePlacement(paths, feature.id);
399
461
  if (!postActiveValidation.ok) {
400
462
  if (!(await pathExists(activeDirPath)) && (await pathExists(archivedDirPath))) {
@@ -415,6 +477,7 @@ export class FinalizeService {
415
477
  });
416
478
  }
417
479
  updateDependencyMetadata(snapshot.backlog.items);
480
+ const postFinalizeReplan = buildPostFinalizeReplan(snapshot.backlog.items, finalized, Array.from(unblocked).sort(), now);
418
481
  const stateUpdates = {
419
482
  discoveryIndex: snapshot.discoveryIndex,
420
483
  backlog: snapshot.backlog,
@@ -448,6 +511,7 @@ export class FinalizeService {
448
511
  finalized,
449
512
  unblocked: Array.from(unblocked).sort(),
450
513
  pending: remaining,
514
+ post_finalize_replan: postFinalizeReplan,
451
515
  updated_core_docs: Array.from(updatedCoreDocs).sort(),
452
516
  updated_readme: syncResult.updatedReadme,
453
517
  updated_agent_guide: syncResult.updatedAgentGuide || syncResult.updatedRootAgents,
@@ -458,9 +522,9 @@ export class FinalizeService {
458
522
  });
459
523
  }
460
524
  }
461
- async function inferFinalizeTarget(paths, pending, explicitRef, cwd) {
525
+ export async function inferFinalizeTarget(paths, pending, explicitRef, cwd) {
462
526
  if (explicitRef)
463
- return explicitRef;
527
+ return normalizeFeatRef(explicitRef) ?? explicitRef;
464
528
  const activeEntries = await fs.readdir(paths.activeDir, { withFileTypes: true }).catch(() => []);
465
529
  const activeFeatures = activeEntries
466
530
  .filter((entry) => entry.isDirectory() && /^FEAT-\d{4}$/.test(entry.name))
@@ -483,13 +547,13 @@ async function inferFinalizeTarget(paths, pending, explicitRef, cwd) {
483
547
  }
484
548
  return undefined;
485
549
  }
486
- function isPrivacyComplianceFeature(feature) {
550
+ export function isPrivacyComplianceFeature(feature) {
487
551
  if (feature.origin_ref === 'EPIC-0020' || feature.origin_ref === 'EPIC-0021')
488
552
  return true;
489
553
  const refs = new Set(feature.acceptance_refs || []);
490
554
  return refs.has('EPIC-0020') || refs.has('EPIC-0021') || refs.has('DEB-0021') || refs.has('INS-0021');
491
555
  }
492
- async function evaluatePrivacyFinalizeGuardrail(paths, config, feature) {
556
+ export async function evaluatePrivacyFinalizeGuardrail(paths, config, feature) {
493
557
  if (!isPrivacyComplianceFeature(feature)) {
494
558
  return { ok: true, reasons: [] };
495
559
  }
@@ -576,7 +640,46 @@ async function evaluatePrivacyFinalizeGuardrail(paths, config, feature) {
576
640
  }
577
641
  return { ok: reasons.length === 0, reasons };
578
642
  }
579
- async function evaluateWorkspaceQualityFeedback(paths, config, feature) {
643
+ export async function evaluateDevTrackApiPolicyGates(paths, config, feature) {
644
+ const activePath = path.join(paths.activeDir, feature.id);
645
+ const names = activeDocNamesForLayout(config);
646
+ const qualityPath = path.join(activePath, names.quality);
647
+ const qualityContent = await fs.readFile(qualityPath, 'utf-8').catch(() => '');
648
+ if (!qualityContent.trim()) {
649
+ return { ok: true, reasons: [] };
650
+ }
651
+ let quality;
652
+ try {
653
+ quality = parseWorkspaceYamlDocument('5-quality.yaml', qualityContent);
654
+ }
655
+ catch {
656
+ return { ok: true, reasons: [] };
657
+ }
658
+ const reasons = evaluateDevTrackApiPolicyEvidence(quality);
659
+ return { ok: reasons.length === 0, reasons };
660
+ }
661
+ export function evaluateDevTrackApiPolicyEvidence(quality) {
662
+ const policyRequirements = [
663
+ ...(quality.skill_evidence?.policy_requirements ?? []),
664
+ ...(quality.policy_injection?.required_policies ?? []),
665
+ ];
666
+ if (policyRequirements.length === 0) {
667
+ return [];
668
+ }
669
+ const evidenceEntries = quality.skill_evidence?.evidence ?? [];
670
+ const hasDevTrackApiEvidence = evidenceEntries.some((entry) => entry.skill_id === 'devtrack-api');
671
+ const reasons = new Set();
672
+ for (const policy of policyRequirements) {
673
+ if (policy.skill_id !== 'devtrack-api' || policy.enforcement !== 'blocking') {
674
+ continue;
675
+ }
676
+ if (!hasDevTrackApiEvidence) {
677
+ reasons.add(`devtrack-api policy gate: blocking skill "devtrack-api" lacks evidence in skill_evidence (required rules: ${policy.required_rule_refs.join(', ')})`);
678
+ }
679
+ }
680
+ return Array.from(reasons);
681
+ }
682
+ export async function evaluateWorkspaceQualityFeedback(paths, config, feature) {
580
683
  const activePath = path.join(paths.activeDir, feature.id);
581
684
  const names = activeDocNamesForLayout(config);
582
685
  const artifactName = [names.quality, ...activeDocCandidateNames(config)].find((name) => name === '5-quality.yaml' && existsSync(path.join(activePath, name))) || '';
@@ -598,9 +701,13 @@ async function evaluateWorkspaceQualityFeedback(paths, config, feature) {
598
701
  }
599
702
  const missingTargets = missingCoverageTargets(document);
600
703
  const missingSkills = missingSkillEvidence(document);
704
+ const matrixReasons = evaluateQualityWitnessMatrix(document);
601
705
  const reasons = [];
602
706
  const maxRounds = document.remediation_policy.max_rounds;
603
707
  const rounds = countQualityEvidenceRounds(document);
708
+ const q95Ledger = await computeQ95Ledger(paths, config, feature, document);
709
+ document.q95_ledger = q95Ledger;
710
+ await fs.writeFile(artifactPath, stringifyWorkspaceYamlDocument('5-quality.yaml', document), 'utf-8');
604
711
  if (rounds > maxRounds && document.exceptions.length === 0) {
605
712
  reasons.push(`quality remediation max_rounds exceeded (${rounds}/${maxRounds}); formal exception required in ${artifact}`);
606
713
  }
@@ -621,9 +728,15 @@ async function evaluateWorkspaceQualityFeedback(paths, config, feature) {
621
728
  if (missingSkills.length > 0) {
622
729
  reasons.push(`required skill evidence missing for ${missingSkills.join(', ')}`);
623
730
  }
731
+ if (matrixReasons.length > 0) {
732
+ reasons.push(`quality-witness matrix blocked finalize: ${matrixReasons.join(' | ')}`);
733
+ }
734
+ if (q95Ledger.score < q95Ledger.threshold && document.exceptions.length === 0) {
735
+ reasons.push(`Q95 composite score below threshold (${q95Ledger.score.toFixed(2)} < ${q95Ledger.threshold}); next best action: ${q95Ledger.next_best_action}`);
736
+ }
624
737
  return { ok: reasons.length === 0, reasons, artifact };
625
738
  }
626
- async function evaluateWorkspaceTraceabilityFeedback(paths, config, feature) {
739
+ export async function evaluateWorkspaceTraceabilityFeedback(paths, config, feature) {
627
740
  const activePath = path.join(paths.activeDir, feature.id);
628
741
  const names = activeDocNamesForLayout(config);
629
742
  const specPath = path.join(activePath, names.spec);
@@ -666,14 +779,362 @@ async function evaluateWorkspaceTraceabilityFeedback(paths, config, feature) {
666
779
  artifact,
667
780
  };
668
781
  }
669
- function missingCoverageTargets(document) {
782
+ export async function computeQ95Ledger(paths, config, feature, document) {
783
+ const threshold = document.q95_ledger?.threshold ?? 95;
784
+ const weights = {
785
+ coverage: document.q95_ledger?.weights?.coverage ?? 30,
786
+ traceability: document.q95_ledger?.weights?.traceability ?? 20,
787
+ integrity: document.q95_ledger?.weights?.integrity ?? 20,
788
+ naming: document.q95_ledger?.weights?.naming ?? 10,
789
+ token: document.q95_ledger?.weights?.token ?? 20,
790
+ };
791
+ const coverage = computeCoverageAxis(document);
792
+ const traceability = await computeTraceabilityAxis(paths, config, feature, document);
793
+ const integrity = computeIntegrityAxis(document);
794
+ const naming = computeNamingAxis(feature, document);
795
+ const token = computeTokenAxis(document);
796
+ const axes = {
797
+ coverage: weightedAxis(coverage, weights.coverage),
798
+ traceability: weightedAxis(traceability, weights.traceability),
799
+ integrity: weightedAxis(integrity, weights.integrity),
800
+ naming: weightedAxis(naming, weights.naming),
801
+ token: weightedAxis(token, weights.token),
802
+ };
803
+ const score = round2(axes.coverage.weighted_score +
804
+ axes.traceability.weighted_score +
805
+ axes.integrity.weighted_score +
806
+ axes.naming.weighted_score +
807
+ axes.token.weighted_score);
808
+ const status = score >= threshold ? 'pass' : 'fail';
809
+ return {
810
+ threshold,
811
+ score,
812
+ status,
813
+ computed_at: nowIso(),
814
+ weights,
815
+ axes,
816
+ next_best_action: inferQ95NextAction(axes),
817
+ };
818
+ }
819
+ export function weightedAxis(input, weight) {
820
+ return {
821
+ raw_score: clampPercent(input.raw_score),
822
+ weighted_score: round2((clampPercent(input.raw_score) * weight) / 100),
823
+ rationale: input.rationale,
824
+ };
825
+ }
826
+ export function computeCoverageAxis(document) {
827
+ const unit = extractCoveragePerformance(document, 'unit');
828
+ const integration = extractCoveragePerformance(document, 'integration');
829
+ const raw = round2((unit + integration) / 2);
830
+ return {
831
+ raw_score: raw,
832
+ rationale: `unit=${unit.toFixed(2)} integration=${integration.toFixed(2)} derived from evidence_log`,
833
+ };
834
+ }
835
+ export async function computeTraceabilityAxis(paths, config, feature, document) {
836
+ if ((document.traceability?.requirements?.length ?? 0) === 0) {
837
+ return {
838
+ raw_score: 100,
839
+ rationale: 'no requirement matrix declared yet; dedicated traceability guardrail remains authoritative',
840
+ };
841
+ }
842
+ const activePath = path.join(paths.activeDir, feature.id);
843
+ const names = activeDocNamesForLayout(config);
844
+ const specPath = path.join(activePath, names.spec);
845
+ const changelogPath = path.join(activePath, names.changelog);
846
+ const [specContent, changelogContent] = await Promise.all([
847
+ fs.readFile(specPath, 'utf-8').catch(() => ''),
848
+ fs.readFile(changelogPath, 'utf-8').catch(() => ''),
849
+ ]);
850
+ if (!specContent.trim() || !changelogContent.trim()) {
851
+ return {
852
+ raw_score: 70,
853
+ rationale: 'traceability matrix exists but spec/changelog evidence is unavailable for Q95 composite scoring',
854
+ };
855
+ }
856
+ try {
857
+ const spec = parseWorkspaceYamlDocument('1-spec.yaml', specContent);
858
+ const changelog = parseWorkspaceYamlDocument('4-changelog.yaml', changelogContent);
859
+ const result = evaluateWorkspaceTraceability(paths.projectRoot, spec, changelog, document);
860
+ return result.ok
861
+ ? { raw_score: 100, rationale: 'traceability closure validated successfully' }
862
+ : { raw_score: 70, rationale: result.reasons.join(' | ') };
863
+ }
864
+ catch (error) {
865
+ return {
866
+ raw_score: 70,
867
+ rationale: `traceability parse error: ${error.message}`,
868
+ };
869
+ }
870
+ }
871
+ export function computeIntegrityAxis(document) {
872
+ const requiredSkillIds = Array.from(new Set((document.skill_evidence?.required_skill_ids ?? []).map((value) => value.trim()).filter(Boolean)));
873
+ const providedSkills = new Set((document.skill_evidence?.evidence ?? [])
874
+ .map((entry) => entry.skill_id.trim().toLowerCase())
875
+ .filter(Boolean));
876
+ const coveredSkills = requiredSkillIds.filter((id) => providedSkills.has(id.toLowerCase())).length;
877
+ const skillScore = requiredSkillIds.length === 0 ? 100 : round2((coveredSkills / requiredSkillIds.length) * 100);
878
+ const security = document.security_integrity;
879
+ const securityScore = !security
880
+ ? 100
881
+ : round2([
882
+ integritySignalScore(security.endpoint_auth_review),
883
+ integritySignalScore(security.sensitive_data_exposure_review),
884
+ integritySignalScore(security.incident_response_review),
885
+ ].reduce((acc, value) => acc + value, 0) / 3);
886
+ const runtimeQuality = computeRuntimeQualityAxis(document);
887
+ const raw = round2(skillScore * 0.55 + securityScore * 0.25 + runtimeQuality.raw_score * 0.2);
888
+ return {
889
+ raw_score: raw,
890
+ rationale: `skill_evidence=${skillScore.toFixed(2)} security_integrity=${securityScore.toFixed(2)} runtime_quality=${runtimeQuality.raw_score.toFixed(2)} (${runtimeQuality.rationale})`,
891
+ };
892
+ }
893
+ export function computeRuntimeQualityAxis(document) {
894
+ const gates = document.runtime_quality_gates;
895
+ const performance = gates?.performance ?? [];
896
+ const flakiness = gates?.flakiness ?? [];
897
+ const entries = [
898
+ ...performance.map((entry) => ({ kind: 'performance', gate: entry.gate, evidence: entry.evidence_ref, score: runtimePerformanceScore(entry) })),
899
+ ...flakiness.map((entry) => ({ kind: 'flakiness', gate: entry.gate, evidence: entry.evidence_ref, score: runtimeFlakinessScore(entry) })),
900
+ ];
901
+ if (entries.length === 0) {
902
+ return {
903
+ raw_score: 100,
904
+ rationale: 'runtime quality telemetry not provided; neutral score applied',
905
+ };
906
+ }
907
+ const scores = entries.map((entry) => {
908
+ if (entry.gate === 'fail')
909
+ return Math.min(entry.score, 70);
910
+ if (entry.gate === 'warn')
911
+ return Math.min(entry.score, 85);
912
+ return entry.score;
913
+ });
914
+ const worst = Math.min(...scores);
915
+ const failed = entries.filter((entry) => entry.gate === 'fail').map((entry) => `${entry.kind}:${entry.evidence ?? 'runtime evidence'}`);
916
+ const warned = entries.filter((entry) => entry.gate === 'warn').map((entry) => `${entry.kind}:${entry.evidence ?? 'runtime evidence'}`);
917
+ const notes = [...failed.map((value) => `${value} failed`), ...warned.map((value) => `${value} warned`)];
918
+ return {
919
+ raw_score: worst,
920
+ rationale: `runtime quality gate scored ${worst.toFixed(2)}${notes.length > 0 ? `; ${notes.join('; ')}` : ''}`,
921
+ };
922
+ }
923
+ function runtimePerformanceScore(entry) {
924
+ if (entry.actual !== undefined && entry.threshold !== undefined && entry.threshold > 0) {
925
+ return clampPercent((entry.threshold / Math.max(entry.actual, 1)) * 100);
926
+ }
927
+ return entry.gate === 'pass' ? 100 : entry.gate === 'warn' ? 85 : 70;
928
+ }
929
+ function runtimeFlakinessScore(entry) {
930
+ let failureRate = entry.failure_rate_percent;
931
+ if (failureRate === undefined && entry.attempts !== undefined && entry.failures !== undefined && entry.attempts > 0) {
932
+ failureRate = clampPercent((entry.failures / entry.attempts) * 100);
933
+ }
934
+ if (failureRate === undefined) {
935
+ return entry.gate === 'pass' ? 100 : entry.gate === 'warn' ? 85 : 70;
936
+ }
937
+ return clampPercent(100 - failureRate);
938
+ }
939
+ const LEGACY_NAMING_PATTERNS = [
940
+ /\bcoachsdd\b/u,
941
+ /\bcoach\s+sdd\b/u,
942
+ /\bcoach-sdd\b/u,
943
+ /\bcoach_sdd\b/u,
944
+ /\bsdd\s+coach\b/u,
945
+ /\.codesdd\b/u,
946
+ ];
947
+ export function computeNamingAxis(feature, document) {
948
+ let score = 100;
949
+ const rationale = [];
950
+ if (!/^FEAT-\d{4,}$/.test(feature.id)) {
951
+ score -= 40;
952
+ rationale.push('feature id not canonical FEAT-####');
953
+ }
954
+ if (!feature.title || feature.title.trim().length < 10) {
955
+ score -= 30;
956
+ rationale.push('feature title too short');
957
+ }
958
+ const combined = JSON.stringify({ title: feature.title || '', quality: document }).toLowerCase();
959
+ if (LEGACY_NAMING_PATTERNS.some((pattern) => pattern.test(combined))) {
960
+ score -= 30;
961
+ rationale.push('legacy naming detected in active quality context by naming-contract forbidden terms');
962
+ }
963
+ return {
964
+ raw_score: clampPercent(score),
965
+ rationale: rationale.length > 0 ? rationale.join('; ') : 'canonical naming and state metadata checks passed',
966
+ };
967
+ }
968
+ export function computeTokenAxis(document) {
969
+ const structuredTelemetry = document.token_budget_gates?.telemetry ?? [];
970
+ if (structuredTelemetry.length > 0) {
971
+ return computeStructuredTokenAxis(document);
972
+ }
973
+ const tokenEntries = document.evidence_log.filter((entry) => {
974
+ const label = `${entry.kind} ${entry.result}`.toLowerCase();
975
+ return label.includes('token');
976
+ });
977
+ if (tokenEntries.length === 0) {
978
+ return {
979
+ raw_score: 100,
980
+ rationale: 'token telemetry not provided; neutral score applied until FEAT token harness evidence is recorded',
981
+ };
982
+ }
983
+ const percents = [];
984
+ for (const entry of tokenEntries) {
985
+ const matches = entry.result.match(/(\d+(?:\.\d+)?)\s*%/g) ?? [];
986
+ for (const match of matches) {
987
+ const value = Number(match.replace('%', '').trim());
988
+ if (Number.isFinite(value)) {
989
+ percents.push(clampPercent(value));
990
+ }
991
+ }
992
+ }
993
+ if (percents.length > 0) {
994
+ const best = Math.max(...percents);
995
+ return {
996
+ raw_score: best,
997
+ rationale: `token efficiency evidence detected (${best.toFixed(2)}%)`,
998
+ };
999
+ }
1000
+ return {
1001
+ raw_score: 70,
1002
+ rationale: 'token evidence found but no numeric percentage; conservative score applied',
1003
+ };
1004
+ }
1005
+ export function computeStructuredTokenAxis(document) {
1006
+ const gates = document.token_budget_gates;
1007
+ const telemetry = gates?.telemetry ?? [];
1008
+ const requireNumeric = gates?.require_numeric_efficiency ?? true;
1009
+ const failBelow = gates?.fail_below_percent ?? 95;
1010
+ const scores = [];
1011
+ const reasons = [];
1012
+ let hardFailure = false;
1013
+ for (const entry of telemetry) {
1014
+ let score = entry.efficiency_percent;
1015
+ if (score === undefined && entry.budget_chars !== undefined && entry.actual_chars !== undefined) {
1016
+ score = entry.actual_chars === 0 ? 100 : clampPercent((entry.budget_chars / entry.actual_chars) * 100);
1017
+ }
1018
+ if (score === undefined && entry.actual_chars !== undefined && gates?.max_context_chars !== undefined) {
1019
+ score = entry.actual_chars === 0 ? 100 : clampPercent((gates.max_context_chars / entry.actual_chars) * 100);
1020
+ }
1021
+ if (score === undefined) {
1022
+ if (requireNumeric) {
1023
+ scores.push(70);
1024
+ reasons.push(`${entry.evidence_ref ?? 'token telemetry'} lacks numeric efficiency`);
1025
+ }
1026
+ continue;
1027
+ }
1028
+ const normalized = clampPercent(score);
1029
+ scores.push(normalized);
1030
+ if (entry.gate === 'fail' || normalized < failBelow) {
1031
+ hardFailure = true;
1032
+ reasons.push(`${entry.evidence_ref ?? 'token telemetry'} below ${failBelow}%`);
1033
+ }
1034
+ else if (entry.gate === 'warn') {
1035
+ reasons.push(`${entry.evidence_ref ?? 'token telemetry'} warned at ${normalized.toFixed(2)}%`);
1036
+ }
1037
+ }
1038
+ if (scores.length === 0) {
1039
+ return {
1040
+ raw_score: requireNumeric ? 70 : 100,
1041
+ rationale: requireNumeric
1042
+ ? 'token budget gate requires numeric efficiency but no numeric telemetry was provided'
1043
+ : 'token budget telemetry provided without numeric scoring requirement',
1044
+ };
1045
+ }
1046
+ const worst = Math.min(...scores);
1047
+ if (hardFailure) {
1048
+ return {
1049
+ raw_score: Math.min(worst, 70),
1050
+ rationale: `token budget gate failed: ${reasons.join('; ')}`,
1051
+ };
1052
+ }
1053
+ return {
1054
+ raw_score: worst,
1055
+ rationale: `token budget gate satisfied (${worst.toFixed(2)}% worst-case efficiency)${reasons.length > 0 ? `; ${reasons.join('; ')}` : ''}`,
1056
+ };
1057
+ }
1058
+ export function extractCoveragePerformance(document, kind) {
1059
+ const target = kind === 'unit' ? document.coverage_targets.unit : document.coverage_targets.integration;
1060
+ const relevant = document.evidence_log.filter((entry) => {
1061
+ const evidenceKind = entry.kind.toLowerCase();
1062
+ return (evidenceKind.includes(kind) ||
1063
+ evidenceKind.includes('coverage') ||
1064
+ (kind === 'integration' && evidenceKind.includes('e2e')));
1065
+ });
1066
+ if (relevant.length === 0)
1067
+ return 0;
1068
+ const values = relevant.flatMap((entry) => {
1069
+ const matches = entry.result.match(/\d+(?:\.\d+)?/g) ?? [];
1070
+ return matches.map(Number).filter((value) => Number.isFinite(value) && value >= 0 && value <= 100);
1071
+ });
1072
+ if (values.length === 0)
1073
+ return 0;
1074
+ const best = Math.max(...values);
1075
+ if (target <= 0)
1076
+ return 100;
1077
+ return clampPercent((best / target) * 100);
1078
+ }
1079
+ export function integritySignalScore(value) {
1080
+ if (value === 'passed' || value === 'not_applicable')
1081
+ return 100;
1082
+ if (value === 'pending')
1083
+ return 50;
1084
+ return 0;
1085
+ }
1086
+ export function inferQ95NextAction(axes) {
1087
+ const ranking = [
1088
+ { axis: 'coverage', weightedGap: 30 - axes.coverage.weighted_score, rawGap: 100 - axes.coverage.raw_score },
1089
+ {
1090
+ axis: 'traceability',
1091
+ weightedGap: 20 - axes.traceability.weighted_score,
1092
+ rawGap: 100 - axes.traceability.raw_score,
1093
+ },
1094
+ { axis: 'integrity', weightedGap: 20 - axes.integrity.weighted_score, rawGap: 100 - axes.integrity.raw_score },
1095
+ { axis: 'naming', weightedGap: 10 - axes.naming.weighted_score, rawGap: 100 - axes.naming.raw_score },
1096
+ { axis: 'token', weightedGap: 20 - axes.token.weighted_score, rawGap: 100 - axes.token.raw_score },
1097
+ ];
1098
+ ranking.sort((a, b) => b.weightedGap - a.weightedGap || b.rawGap - a.rawGap);
1099
+ const primary = ranking[0];
1100
+ if (!primary || primary.weightedGap <= 0) {
1101
+ return 'Q95 satisfied. Keep evidence_log and traceability synchronized for future rounds.';
1102
+ }
1103
+ switch (primary.axis) {
1104
+ case 'coverage':
1105
+ return 'Add or update unit/integration evidence entries with numeric percentages that meet coverage_targets.';
1106
+ case 'traceability':
1107
+ return 'Complete traceability.spec_anchor and traceability.requirements links across spec, changelog, code, and tests.';
1108
+ case 'integrity':
1109
+ return 'Record required skill evidence and close pending security_integrity reviews when applicable.';
1110
+ case 'naming':
1111
+ return 'Fix canonical naming drift in FEAT metadata and avoid legacy governance aliases in quality artifacts.';
1112
+ case 'token':
1113
+ return 'Record token efficiency telemetry (percentage) in evidence_log to score the token axis explicitly.';
1114
+ default:
1115
+ return 'Record missing evidence to raise the lowest weighted axis.';
1116
+ }
1117
+ }
1118
+ export function clampPercent(value) {
1119
+ if (!Number.isFinite(value))
1120
+ return 0;
1121
+ if (value < 0)
1122
+ return 0;
1123
+ if (value > 100)
1124
+ return 100;
1125
+ return value;
1126
+ }
1127
+ export function round2(value) {
1128
+ return Math.round(value * 100) / 100;
1129
+ }
1130
+ export function missingCoverageTargets(document) {
670
1131
  const targets = [
671
1132
  { kind: 'unit', target: document.coverage_targets.unit },
672
1133
  { kind: 'integration', target: document.coverage_targets.integration },
673
1134
  ];
674
1135
  return targets.filter((target) => !coverageTargetMet(document, target.kind, target.target));
675
1136
  }
676
- function coverageTargetMet(document, kind, target) {
1137
+ export function coverageTargetMet(document, kind, target) {
677
1138
  return document.evidence_log.some((entry) => {
678
1139
  const evidenceKind = entry.kind.toLowerCase();
679
1140
  const result = entry.result.toLowerCase();
@@ -687,14 +1148,14 @@ function coverageTargetMet(document, kind, target) {
687
1148
  return percentages.some((value) => value >= target);
688
1149
  });
689
1150
  }
690
- function countQualityEvidenceRounds(document) {
1151
+ export function countQualityEvidenceRounds(document) {
691
1152
  const roundKinds = ['round', 'unit', 'integration', 'e2e', 'coverage', 'validation', 'test', 'build'];
692
1153
  return document.evidence_log.filter((entry) => {
693
1154
  const kind = entry.kind.toLowerCase();
694
1155
  return roundKinds.some((token) => kind.includes(token));
695
1156
  }).length;
696
1157
  }
697
- function missingSkillEvidence(document) {
1158
+ export function missingSkillEvidence(document) {
698
1159
  const required = Array.from(new Set((document.skill_evidence?.required_skill_ids ?? []).map((value) => value.trim()).filter(Boolean)));
699
1160
  if (required.length === 0) {
700
1161
  return [];