specky-sdd 3.10.2 → 3.11.1

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 (322) hide show
  1. package/.apm/agents/specky-design-architect.agent.md +8 -28
  2. package/.apm/agents/specky-implementer.agent.md +15 -27
  3. package/.apm/agents/specky-onboarding.agent.md +8 -49
  4. package/.apm/agents/specky-orchestrator.agent.md +12 -37
  5. package/.apm/agents/specky-quality-reviewer.agent.md +9 -30
  6. package/.apm/agents/specky-release-engineer.agent.md +8 -30
  7. package/.apm/agents/specky-requirements-engineer.agent.md +1 -1
  8. package/.apm/agents/specky-research-analyst.agent.md +1 -1
  9. package/.apm/agents/specky-sdd-clarify.agent.md +1 -1
  10. package/.apm/agents/specky-sdd-init.agent.md +8 -19
  11. package/.apm/agents/specky-spec-engineer.agent.md +8 -30
  12. package/.apm/agents/specky-task-planner.agent.md +7 -26
  13. package/.apm/agents/specky-test-verifier.agent.md +7 -17
  14. package/.apm/hooks/scripts/specky-artifact-validator.sh +14 -10
  15. package/.apm/hooks/scripts/specky-auto-checkpoint.sh +9 -4
  16. package/.apm/hooks/scripts/specky-branch-validator.sh +29 -116
  17. package/.apm/hooks/scripts/specky-cognitive-debt-alert.sh +6 -3
  18. package/.apm/hooks/scripts/specky-contract-context.bash +24 -0
  19. package/.apm/hooks/scripts/specky-contract-context.mjs +219 -0
  20. package/.apm/hooks/scripts/specky-drift-monitor.sh +6 -3
  21. package/.apm/hooks/scripts/specky-ears-validator.sh +5 -2
  22. package/.apm/hooks/scripts/specky-lgtm-gate.sh +12 -10
  23. package/.apm/hooks/scripts/specky-metrics-dashboard.sh +5 -2
  24. package/.apm/hooks/scripts/specky-phase-gate.sh +18 -9
  25. package/.apm/hooks/scripts/specky-pipeline-guard.sh +19 -26
  26. package/.apm/hooks/scripts/specky-release-gate.sh +38 -46
  27. package/.apm/hooks/scripts/specky-security-scan.sh +53 -36
  28. package/.apm/hooks/scripts/specky-session-banner.sh +22 -74
  29. package/.apm/hooks/scripts/specky-spec-quality.sh +7 -4
  30. package/.apm/hooks/scripts/specky-spec-sync.sh +12 -11
  31. package/.apm/hooks/scripts/specky-task-tracer.sh +5 -2
  32. package/.apm/hooks/specky-run.sh +3 -0
  33. package/.apm/instructions/claude-instructions.instructions.md +3 -3
  34. package/.apm/instructions/copilot-instructions.instructions.md +3 -3
  35. package/.apm/instructions/cursor-instructions.instructions.md +3 -3
  36. package/.apm/instructions/opencode-instructions.instructions.md +2 -2
  37. package/.apm/prompts/specky-brownfield.prompt.md +8 -5
  38. package/.apm/prompts/specky-greenfield.prompt.md +7 -5
  39. package/.apm/prompts/specky-implement.prompt.md +1 -1
  40. package/.apm/prompts/specky-orchestrate.prompt.md +1 -1
  41. package/.apm/skills/specky-design-architect/SKILL.md +39 -16
  42. package/.apm/skills/specky-implementer/SKILL.md +46 -158
  43. package/.apm/skills/specky-onboarding/SKILL.md +50 -156
  44. package/.apm/skills/specky-orchestrator/SKILL.md +28 -26
  45. package/.apm/skills/specky-quality-reviewer/SKILL.md +38 -23
  46. package/.apm/skills/specky-release-engineer/SKILL.md +38 -270
  47. package/.apm/skills/specky-research-analyst/SKILL.md +1 -1
  48. package/.apm/skills/specky-sdd-init/SKILL.md +61 -23
  49. package/.apm/skills/specky-sdd-pipeline/SKILL.md +36 -216
  50. package/.apm/skills/specky-spec-engineer/SKILL.md +40 -17
  51. package/.apm/skills/specky-task-planner/SKILL.md +31 -12
  52. package/.apm/skills/specky-test-verifier/SKILL.md +23 -202
  53. package/CHANGELOG.md +39 -0
  54. package/README.md +49 -47
  55. package/SECURITY.md +5 -1
  56. package/apm-policy.yml +2 -0
  57. package/apm.lock.yaml +55 -53
  58. package/apm.yml +3 -3
  59. package/config.yml +32 -53
  60. package/dist/cli/commands/doctor.d.ts.map +1 -1
  61. package/dist/cli/commands/doctor.js +106 -20
  62. package/dist/cli/commands/doctor.js.map +1 -1
  63. package/dist/cli/commands/init.d.ts +2 -0
  64. package/dist/cli/commands/init.d.ts.map +1 -1
  65. package/dist/cli/commands/init.js +105 -7
  66. package/dist/cli/commands/init.js.map +1 -1
  67. package/dist/cli/commands/migrate-contracts.d.ts +15 -0
  68. package/dist/cli/commands/migrate-contracts.d.ts.map +1 -0
  69. package/dist/cli/commands/migrate-contracts.js +311 -0
  70. package/dist/cli/commands/migrate-contracts.js.map +1 -0
  71. package/dist/cli/commands/status.d.ts.map +1 -1
  72. package/dist/cli/commands/status.js +63 -48
  73. package/dist/cli/commands/status.js.map +1 -1
  74. package/dist/cli/index.js +82 -27
  75. package/dist/cli/index.js.map +1 -1
  76. package/dist/cli/lib/apm/policy.d.ts +1 -0
  77. package/dist/cli/lib/apm/policy.d.ts.map +1 -1
  78. package/dist/cli/lib/apm/policy.js +15 -0
  79. package/dist/cli/lib/apm/policy.js.map +1 -1
  80. package/dist/cli/lib/asset-copier.d.ts +1 -0
  81. package/dist/cli/lib/asset-copier.d.ts.map +1 -1
  82. package/dist/cli/lib/asset-copier.js +4 -4
  83. package/dist/cli/lib/asset-copier.js.map +1 -1
  84. package/dist/cli/lib/cursor-plugin-writer.d.ts.map +1 -1
  85. package/dist/cli/lib/cursor-plugin-writer.js +34 -9
  86. package/dist/cli/lib/cursor-plugin-writer.js.map +1 -1
  87. package/dist/cli/lib/harness/compilers/claude.js +3 -3
  88. package/dist/cli/lib/harness/compilers/claude.js.map +1 -1
  89. package/dist/cli/lib/harness/compilers/common.d.ts +10 -1
  90. package/dist/cli/lib/harness/compilers/common.d.ts.map +1 -1
  91. package/dist/cli/lib/harness/compilers/common.js +71 -8
  92. package/dist/cli/lib/harness/compilers/common.js.map +1 -1
  93. package/dist/cli/lib/harness/compilers/copilot.js +3 -3
  94. package/dist/cli/lib/harness/compilers/copilot.js.map +1 -1
  95. package/dist/cli/lib/harness/compilers/cursor.js +3 -3
  96. package/dist/cli/lib/harness/compilers/cursor.js.map +1 -1
  97. package/dist/cli/lib/harness/compilers/opencode.js +3 -3
  98. package/dist/cli/lib/harness/compilers/opencode.js.map +1 -1
  99. package/dist/cli/lib/harness/tool-map.d.ts +8 -1
  100. package/dist/cli/lib/harness/tool-map.d.ts.map +1 -1
  101. package/dist/cli/lib/harness/tool-map.js +74 -0
  102. package/dist/cli/lib/harness/tool-map.js.map +1 -1
  103. package/dist/cli/lib/harness/types.d.ts +11 -1
  104. package/dist/cli/lib/harness/types.d.ts.map +1 -1
  105. package/dist/cli/lib/mcp-writer.d.ts +2 -1
  106. package/dist/cli/lib/mcp-writer.d.ts.map +1 -1
  107. package/dist/cli/lib/mcp-writer.js +13 -5
  108. package/dist/cli/lib/mcp-writer.js.map +1 -1
  109. package/dist/cli/lib/settings-merger.d.ts +15 -0
  110. package/dist/cli/lib/settings-merger.d.ts.map +1 -1
  111. package/dist/cli/lib/settings-merger.js +66 -1
  112. package/dist/cli/lib/settings-merger.js.map +1 -1
  113. package/dist/config.d.ts +110 -42
  114. package/dist/config.d.ts.map +1 -1
  115. package/dist/config.js +129 -140
  116. package/dist/config.js.map +1 -1
  117. package/dist/constants.d.ts +1 -1
  118. package/dist/constants.d.ts.map +1 -1
  119. package/dist/contracts/pipeline-profiles.d.ts +61 -0
  120. package/dist/contracts/pipeline-profiles.d.ts.map +1 -0
  121. package/dist/contracts/pipeline-profiles.js +303 -0
  122. package/dist/contracts/pipeline-profiles.js.map +1 -0
  123. package/dist/contracts/tool-contracts.d.ts +449 -0
  124. package/dist/contracts/tool-contracts.d.ts.map +1 -0
  125. package/dist/contracts/tool-contracts.js +83 -0
  126. package/dist/contracts/tool-contracts.js.map +1 -0
  127. package/dist/contracts/use-case.d.ts +736 -0
  128. package/dist/contracts/use-case.d.ts.map +1 -0
  129. package/dist/contracts/use-case.js +352 -0
  130. package/dist/contracts/use-case.js.map +1 -0
  131. package/dist/index.js +7 -4
  132. package/dist/index.js.map +1 -1
  133. package/dist/schemas/common.d.ts +3 -3
  134. package/dist/schemas/common.d.ts.map +1 -1
  135. package/dist/schemas/common.js +1 -4
  136. package/dist/schemas/common.js.map +1 -1
  137. package/dist/schemas/context.d.ts +2 -2
  138. package/dist/schemas/environment.d.ts +6 -17
  139. package/dist/schemas/environment.d.ts.map +1 -1
  140. package/dist/schemas/environment.js +1 -28
  141. package/dist/schemas/environment.js.map +1 -1
  142. package/dist/schemas/feature-content.d.ts +116 -0
  143. package/dist/schemas/feature-content.d.ts.map +1 -0
  144. package/dist/schemas/feature-content.js +65 -0
  145. package/dist/schemas/feature-content.js.map +1 -0
  146. package/dist/schemas/infrastructure.d.ts +6 -28
  147. package/dist/schemas/infrastructure.d.ts.map +1 -1
  148. package/dist/schemas/infrastructure.js +1 -30
  149. package/dist/schemas/infrastructure.js.map +1 -1
  150. package/dist/schemas/input.d.ts +412 -8
  151. package/dist/schemas/input.d.ts.map +1 -1
  152. package/dist/schemas/input.js +6 -7
  153. package/dist/schemas/input.js.map +1 -1
  154. package/dist/schemas/integration.d.ts +22 -28
  155. package/dist/schemas/integration.d.ts.map +1 -1
  156. package/dist/schemas/integration.js +11 -47
  157. package/dist/schemas/integration.js.map +1 -1
  158. package/dist/schemas/metrics.d.ts +3 -2
  159. package/dist/schemas/metrics.d.ts.map +1 -1
  160. package/dist/schemas/metrics.js +2 -1
  161. package/dist/schemas/metrics.js.map +1 -1
  162. package/dist/schemas/pbt.d.ts +2 -7
  163. package/dist/schemas/pbt.d.ts.map +1 -1
  164. package/dist/schemas/pbt.js +1 -9
  165. package/dist/schemas/pbt.js.map +1 -1
  166. package/dist/schemas/pipeline.d.ts +282 -35
  167. package/dist/schemas/pipeline.d.ts.map +1 -1
  168. package/dist/schemas/pipeline.js +29 -15
  169. package/dist/schemas/pipeline.js.map +1 -1
  170. package/dist/schemas/quality.d.ts +15 -19
  171. package/dist/schemas/quality.d.ts.map +1 -1
  172. package/dist/schemas/quality.js +6 -3
  173. package/dist/schemas/quality.js.map +1 -1
  174. package/dist/schemas/routing.d.ts +2 -2
  175. package/dist/schemas/routing.d.ts.map +1 -1
  176. package/dist/schemas/routing.js +2 -4
  177. package/dist/schemas/routing.js.map +1 -1
  178. package/dist/schemas/testing.d.ts +4 -13
  179. package/dist/schemas/testing.d.ts.map +1 -1
  180. package/dist/schemas/testing.js +2 -10
  181. package/dist/schemas/testing.js.map +1 -1
  182. package/dist/schemas/transcript.d.ts +648 -10
  183. package/dist/schemas/transcript.d.ts.map +1 -1
  184. package/dist/schemas/transcript.js +25 -12
  185. package/dist/schemas/transcript.js.map +1 -1
  186. package/dist/schemas/utility.d.ts +28 -15
  187. package/dist/schemas/utility.d.ts.map +1 -1
  188. package/dist/schemas/utility.js +23 -14
  189. package/dist/schemas/utility.js.map +1 -1
  190. package/dist/schemas/visualization.d.ts +66 -15
  191. package/dist/schemas/visualization.d.ts.map +1 -1
  192. package/dist/schemas/visualization.js +36 -12
  193. package/dist/schemas/visualization.js.map +1 -1
  194. package/dist/services/codebase-scanner.d.ts +1 -1
  195. package/dist/services/codebase-scanner.d.ts.map +1 -1
  196. package/dist/services/codebase-scanner.js +2 -2
  197. package/dist/services/codebase-scanner.js.map +1 -1
  198. package/dist/services/compliance-engine.d.ts +3 -2
  199. package/dist/services/compliance-engine.d.ts.map +1 -1
  200. package/dist/services/compliance-engine.js +34 -21
  201. package/dist/services/compliance-engine.js.map +1 -1
  202. package/dist/services/diagram-generator.d.ts +4 -96
  203. package/dist/services/diagram-generator.d.ts.map +1 -1
  204. package/dist/services/diagram-generator.js +18 -1051
  205. package/dist/services/diagram-generator.js.map +1 -1
  206. package/dist/services/doc-generator.d.ts +19 -52
  207. package/dist/services/doc-generator.d.ts.map +1 -1
  208. package/dist/services/doc-generator.js +389 -524
  209. package/dist/services/doc-generator.js.map +1 -1
  210. package/dist/services/execution-context.d.ts +32 -0
  211. package/dist/services/execution-context.d.ts.map +1 -0
  212. package/dist/services/execution-context.js +120 -0
  213. package/dist/services/execution-context.js.map +1 -0
  214. package/dist/services/file-manager.d.ts +16 -4
  215. package/dist/services/file-manager.d.ts.map +1 -1
  216. package/dist/services/file-manager.js +81 -5
  217. package/dist/services/file-manager.js.map +1 -1
  218. package/dist/services/iac-generator.d.ts +9 -10
  219. package/dist/services/iac-generator.d.ts.map +1 -1
  220. package/dist/services/iac-generator.js +36 -99
  221. package/dist/services/iac-generator.js.map +1 -1
  222. package/dist/services/methodology.js +1 -1
  223. package/dist/services/methodology.js.map +1 -1
  224. package/dist/services/metrics-generator.d.ts +1 -1
  225. package/dist/services/metrics-generator.d.ts.map +1 -1
  226. package/dist/services/metrics-generator.js +2 -2
  227. package/dist/services/metrics-generator.js.map +1 -1
  228. package/dist/services/pbt-generator.d.ts +10 -31
  229. package/dist/services/pbt-generator.d.ts.map +1 -1
  230. package/dist/services/pbt-generator.js +43 -515
  231. package/dist/services/pbt-generator.js.map +1 -1
  232. package/dist/services/state-machine.d.ts +22 -16
  233. package/dist/services/state-machine.d.ts.map +1 -1
  234. package/dist/services/state-machine.js +176 -179
  235. package/dist/services/state-machine.js.map +1 -1
  236. package/dist/services/template-engine.d.ts +11 -5
  237. package/dist/services/template-engine.d.ts.map +1 -1
  238. package/dist/services/template-engine.js +48 -21
  239. package/dist/services/template-engine.js.map +1 -1
  240. package/dist/services/test-generator.d.ts +11 -7
  241. package/dist/services/test-generator.d.ts.map +1 -1
  242. package/dist/services/test-generator.js +45 -54
  243. package/dist/services/test-generator.js.map +1 -1
  244. package/dist/templates/design.md +6 -0
  245. package/dist/tools/analysis.d.ts.map +1 -1
  246. package/dist/tools/analysis.js +8 -9
  247. package/dist/tools/analysis.js.map +1 -1
  248. package/dist/tools/checkpoint.d.ts.map +1 -1
  249. package/dist/tools/checkpoint.js +43 -46
  250. package/dist/tools/checkpoint.js.map +1 -1
  251. package/dist/tools/context.d.ts.map +1 -1
  252. package/dist/tools/context.js +5 -7
  253. package/dist/tools/context.js.map +1 -1
  254. package/dist/tools/documentation.d.ts +1 -4
  255. package/dist/tools/documentation.d.ts.map +1 -1
  256. package/dist/tools/documentation.js +112 -193
  257. package/dist/tools/documentation.js.map +1 -1
  258. package/dist/tools/environment.d.ts +1 -1
  259. package/dist/tools/environment.d.ts.map +1 -1
  260. package/dist/tools/environment.js +58 -99
  261. package/dist/tools/environment.js.map +1 -1
  262. package/dist/tools/infrastructure.d.ts.map +1 -1
  263. package/dist/tools/infrastructure.js +36 -38
  264. package/dist/tools/infrastructure.js.map +1 -1
  265. package/dist/tools/input.d.ts.map +1 -1
  266. package/dist/tools/input.js +18 -11
  267. package/dist/tools/input.js.map +1 -1
  268. package/dist/tools/integration.d.ts.map +1 -1
  269. package/dist/tools/integration.js +64 -65
  270. package/dist/tools/integration.js.map +1 -1
  271. package/dist/tools/metrics.d.ts.map +1 -1
  272. package/dist/tools/metrics.js +18 -30
  273. package/dist/tools/metrics.js.map +1 -1
  274. package/dist/tools/pbt.d.ts.map +1 -1
  275. package/dist/tools/pbt.js +10 -12
  276. package/dist/tools/pbt.js.map +1 -1
  277. package/dist/tools/pipeline.d.ts.map +1 -1
  278. package/dist/tools/pipeline.js +156 -274
  279. package/dist/tools/pipeline.js.map +1 -1
  280. package/dist/tools/quality.d.ts.map +1 -1
  281. package/dist/tools/quality.js +58 -45
  282. package/dist/tools/quality.js.map +1 -1
  283. package/dist/tools/response-builder.d.ts.map +1 -1
  284. package/dist/tools/response-builder.js +12 -10
  285. package/dist/tools/response-builder.js.map +1 -1
  286. package/dist/tools/testing.d.ts.map +1 -1
  287. package/dist/tools/testing.js +28 -29
  288. package/dist/tools/testing.js.map +1 -1
  289. package/dist/tools/tool-enforcement.d.ts +2 -0
  290. package/dist/tools/tool-enforcement.d.ts.map +1 -1
  291. package/dist/tools/tool-enforcement.js +84 -59
  292. package/dist/tools/tool-enforcement.js.map +1 -1
  293. package/dist/tools/transcript.d.ts.map +1 -1
  294. package/dist/tools/transcript.js +304 -374
  295. package/dist/tools/transcript.js.map +1 -1
  296. package/dist/tools/turnkey.d.ts +1 -31
  297. package/dist/tools/turnkey.d.ts.map +1 -1
  298. package/dist/tools/turnkey.js +104 -488
  299. package/dist/tools/turnkey.js.map +1 -1
  300. package/dist/tools/utility.d.ts.map +1 -1
  301. package/dist/tools/utility.js +115 -134
  302. package/dist/tools/utility.js.map +1 -1
  303. package/dist/tools/visualization.d.ts +1 -25
  304. package/dist/tools/visualization.d.ts.map +1 -1
  305. package/dist/tools/visualization.js +187 -562
  306. package/dist/tools/visualization.js.map +1 -1
  307. package/dist/types.d.ts +21 -11
  308. package/dist/types.d.ts.map +1 -1
  309. package/dist/utils/artifact-metadata.d.ts +8 -0
  310. package/dist/utils/artifact-metadata.d.ts.map +1 -0
  311. package/dist/utils/artifact-metadata.js +10 -0
  312. package/dist/utils/artifact-metadata.js.map +1 -0
  313. package/dist/utils/requirement-partition.d.ts +8 -0
  314. package/dist/utils/requirement-partition.d.ts.map +1 -0
  315. package/dist/utils/requirement-partition.js +15 -0
  316. package/dist/utils/requirement-partition.js.map +1 -0
  317. package/package.json +11 -2
  318. package/templates/design.md +6 -0
  319. package/dist/utils/design-stubs.d.ts +0 -32
  320. package/dist/utils/design-stubs.d.ts.map +0 -1
  321. package/dist/utils/design-stubs.js +0 -103
  322. package/dist/utils/design-stubs.js.map +0 -1
@@ -4,20 +4,20 @@
4
4
  # Ensures required artifacts exist before a phase tool runs
5
5
 
6
6
  set -euo pipefail
7
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
8
+ source "$SCRIPT_DIR/specky-contract-context.bash"
7
9
 
8
10
  TOOL="${SDD_TOOL_NAME:-unknown}"
9
- LATEST=$(ls -td .specs/*/ 2>/dev/null | head -1 || true)
10
11
  FAILS=0
11
12
 
12
- if [ -z "$LATEST" ]; then
13
- if [ "$TOOL" != "sdd_init" ]; then
14
- echo "❌ No .specs/ directory found. Run @specky-sdd-init first."
15
- exit 2
16
- fi
13
+ if [ "$TOOL" = "sdd_init" ]; then
14
+ echo " Artifact Validator — sdd_init has no existing feature prerequisites"
17
15
  exit 0
18
16
  fi
17
+ specky_require_feature_context || exit $?
18
+ LATEST="$SPECKY_FEATURE_DIR"
19
19
 
20
- FEATURE=$(basename "$LATEST")
20
+ FEATURE="${SPECKY_FEATURE_NUMBER}-${SPECKY_FEATURE_NAME}"
21
21
  echo "📄 Artifact Validator — $FEATURE — before $TOOL"
22
22
 
23
23
  check_exists() {
@@ -44,7 +44,7 @@ case "$TOOL" in
44
44
  sdd_init)
45
45
  echo " ✅ No prerequisites for sdd_init"
46
46
  ;;
47
- sdd_discover|sdd_research|sdd_import_document|sdd_import_transcript|sdd_batch_import)
47
+ sdd_discover|sdd_research|sdd_import_transcript)
48
48
  check_exists "CONSTITUTION.md" "CONSTITUTION.md" "Run @specky-sdd-init or /specky-greenfield"
49
49
  ;;
50
50
  sdd_clarify|sdd_validate_ears)
@@ -53,7 +53,7 @@ case "$TOOL" in
53
53
  sdd_write_spec|sdd_turnkey_spec|sdd_figma_to_spec)
54
54
  check_exists "CONSTITUTION.md" "CONSTITUTION.md" "Run @specky-sdd-init"
55
55
  ;;
56
- sdd_write_design|sdd_generate_all_diagrams)
56
+ sdd_write_design|sdd_generate_all_diagrams|sdd_generate_diagram|sdd_figma_diagram)
57
57
  check_exists "SPECIFICATION.md" "SPECIFICATION.md" "Run @specky-spec-engineer or /specky-specify"
58
58
  check_content "SPECIFICATION.md" "REQ-[A-Z]+-[0-9]+" "EARS requirements with REQ-IDs"
59
59
  ;;
@@ -70,13 +70,17 @@ case "$TOOL" in
70
70
  check_exists "TASKS.md" "TASKS.md" "Run /specky-tasks"
71
71
  ;;
72
72
  sdd_run_analysis|sdd_cross_analyze)
73
- check_exists "VERIFICATION.md" "VERIFICATION.md" "Run @specky-test-verifier or /specky-verify"
74
73
  check_exists "SPECIFICATION.md" "SPECIFICATION.md" "Run /specky-specify"
75
74
  check_exists "DESIGN.md" "DESIGN.md" "Run /specky-design"
76
75
  check_exists "TASKS.md" "TASKS.md" "Run /specky-tasks"
77
76
  ;;
78
77
  sdd_compliance_check)
78
+ if ! specky_has_capability "compliance"; then
79
+ echo "🚫 Compliance capability is not enabled by $SPECKY_CONTRACT_ID"
80
+ FAILS=$((FAILS+1))
81
+ fi
79
82
  check_exists "SPECIFICATION.md" "SPECIFICATION.md" "Run /specky-specify"
83
+ check_exists "DESIGN.md" "DESIGN.md" "Run /specky-design"
80
84
  ;;
81
85
  sdd_create_pr|sdd_export_work_items)
82
86
  check_exists "ANALYSIS.md" "ANALYSIS.md" "Run @specky-quality-reviewer"
@@ -5,16 +5,21 @@
5
5
  # Paper: arXiv:2602.20478 — artifact preservation
6
6
 
7
7
  set -euo pipefail
8
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
9
+ . "$SCRIPT_DIR/specky-contract-context.bash"
10
+ specky_load_contract_context || exit $?
11
+ [ "${SPECKY_CONTEXT_ACTIVE:-0}" = "1" ] || exit 0
12
+ [ "${SPECKY_CHECKPOINTS_REQUIRED:-0}" = "1" ] || exit 0
8
13
 
9
- # Check if a spec artifact was recently modified (last 60 seconds)
10
- RECENT=$(find .specs -name "*.md" -newer /tmp/.sdd-last-checkpoint 2>/dev/null | head -5 || true)
11
- [ -d .specs ] || exit 0
14
+ MARKER="/tmp/.sdd-last-checkpoint-${SPECKY_CONTRACT_FINGERPRINT}"
15
+ [ -f "$MARKER" ] || touch -t 197001010000 "$MARKER"
16
+ RECENT=$(find "$SPECKY_FEATURE_DIR" -name "*.md" -newer "$MARKER" 2>/dev/null | head -5 || true)
12
17
 
13
18
  if [ -n "$RECENT" ]; then
14
19
  echo "💾 Spec artifacts modified:"
15
20
  echo "$RECENT"
16
21
  echo " Consider running sdd_checkpoint to save a snapshot."
17
- touch /tmp/.sdd-last-checkpoint
22
+ touch "$MARKER"
18
23
  fi
19
24
 
20
25
  exit 0
@@ -1,131 +1,44 @@
1
- #!/bin/bash
2
- # specky-branch-validator.sh — Validate git branch matches expected pattern for current tool.
3
- #
4
- # Type: Mixed (see below) | Trigger: PreToolUse | All phases
5
- # • Advisory (exit 0, warn) for sdd_* pipeline tools (always).
6
- # • For native edit tools (Write|Edit|MultiEdit) on a wrong branch during
7
- # an active pipeline:
8
- # - default (SPECKY_GUARD unset OR "off"/"advisory") → warn, exit 0
9
- # - SPECKY_GUARD=strict → exit 2 (BLOCK)
10
- #
11
- # Rationale (rc.13): rc.10-rc.12 defaulted Write|Edit|MultiEdit to BLOCKING,
12
- # which burned pilots who run `specky init` and then edit anything from
13
- # develop/main. Enforcement is now explicit opt-in.
1
+ #!/usr/bin/env bash
2
+ # specky-branch-validator.sh — Validate persisted release branch policy.
3
+ # Type: advisory by default; strict for native edits when SPECKY_GUARD=strict.
14
4
 
15
5
  set -euo pipefail
6
+ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
7
+ source "$SCRIPT_DIR/specky-contract-context.bash"
16
8
 
17
9
  TOOL="${SDD_TOOL_NAME:-unknown}"
18
10
  CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | tr -d '\n' || true)
19
11
  [ -z "$CURRENT_BRANCH" ] && CURRENT_BRANCH="unknown"
20
12
 
21
- # Mode selection (rc.13): strict = block, anything else = advisory.
22
- SPECKY_GUARD_MODE="${SPECKY_GUARD:-advisory}"
23
- if [ "$SPECKY_GUARD_MODE" = "off" ]; then
24
- SPECKY_GUARD_MODE="advisory"
13
+ specky_load_contract_context || exit $?
14
+ if [ "${SPECKY_CONTEXT_ACTIVE:-0}" != "1" ]; then
15
+ echo "ℹ️ Branch Validator no explicit feature context; no branch inferred."
16
+ exit 0
25
17
  fi
26
-
27
- # ── Branch enforcement for native edit tools when pipeline is active ──
28
- if [[ "$TOOL" == "Write" || "$TOOL" == "Edit" || "$TOOL" == "MultiEdit" ]]; then
29
- LATEST=$(ls -td .specs/*/ 2>/dev/null | head -1 || true)
30
- if [ -z "$LATEST" ]; then exit 0; fi
31
- STATE="$LATEST/.sdd-state.json"
32
- if [ ! -f "$STATE" ]; then exit 0; fi
33
-
34
- PHASE="?"
35
- if command -v jq >/dev/null 2>&1; then
36
- PHASE=$(jq -r '.current_phase // "?"' "$STATE" 2>/dev/null || echo "?")
37
- fi
38
-
39
- FEATURE=$(basename "$LATEST")
40
-
41
- emit_violation() {
42
- local expected="$1"
43
- if [ "$SPECKY_GUARD_MODE" = "strict" ]; then
44
- echo "" >&2
45
- echo "🚫 [specky-branch-validator] BLOCKED — $TOOL on '$CURRENT_BRANCH' (phase $PHASE expects $expected) [SPECKY_GUARD=strict]" >&2
46
- echo " Feature: $FEATURE" >&2
47
- echo " Fix: git checkout $expected (or: git checkout -b spec/$FEATURE)" >&2
48
- echo " Disable: unset SPECKY_GUARD" >&2
49
- exit 2
50
- fi
51
- echo "⚠️ [specky-branch-validator] $TOOL on '$CURRENT_BRANCH' during phase $PHASE (expected $expected). Enforce with: export SPECKY_GUARD=strict" >&2
52
- }
53
-
54
- case "$PHASE" in
55
- init|discover|specify|clarify|design|tasks|analyze|implement)
56
- if [[ "$CURRENT_BRANCH" != spec/* ]]; then
57
- emit_violation "spec/$FEATURE"
58
- fi
59
- ;;
60
- verify)
61
- if [[ "$CURRENT_BRANCH" != "develop" ]]; then
62
- emit_violation "develop"
63
- fi
64
- ;;
65
- release)
66
- if [[ "$CURRENT_BRANCH" != "stage" ]]; then
67
- emit_violation "stage"
68
- fi
69
- ;;
70
- esac
18
+ if [ "${SPECKY_RELEASE_ENABLED:-0}" != "1" ]; then
19
+ echo "ℹ️ Branch Validator release capability disabled by $SPECKY_CONTRACT_ID."
71
20
  exit 0
72
21
  fi
73
22
 
74
- echo "🔀 Branch Validator — $CURRENT_BRANCH — before $TOOL"
23
+ EXPECTED_FEATURE_BRANCH="${SPECKY_BRANCH_PREFIX}${SPECKY_FEATURE_NUMBER}-${SPECKY_FEATURE_NAME}"
24
+ EXPECTED="$EXPECTED_FEATURE_BRANCH"
25
+ if [ "$TOOL" = "sdd_create_branch" ]; then
26
+ EXPECTED="$SPECKY_BASE_BRANCH"
27
+ fi
75
28
 
76
- warn() {
77
- echo "⚠️ $1"
78
- echo " Expected: $2"
79
- }
29
+ if [ "$CURRENT_BRANCH" = "$EXPECTED" ]; then
30
+ echo "✅ Branch Validator — $CURRENT_BRANCH matches persisted release policy."
31
+ exit 0
32
+ fi
80
33
 
81
- case "$TOOL" in
82
- sdd_init|sdd_create_branch)
83
- # Init should happen on develop (about to create spec branch)
84
- if [[ "$CURRENT_BRANCH" != "develop" ]] && [[ "$CURRENT_BRANCH" != spec/* ]]; then
85
- warn "sdd_init typically runs on 'develop' before creating a spec branch" "develop"
86
- fi
87
- ;;
88
- sdd_write_spec|sdd_turnkey_spec|sdd_figma_to_spec|sdd_write_design|sdd_write_tasks|sdd_implement|sdd_generate_tests|sdd_generate_pbt|sdd_generate_iac|sdd_generate_dockerfile)
89
- # Spec work must be on spec/* branch
90
- if [[ "$CURRENT_BRANCH" != spec/* ]]; then
91
- warn "Spec work should be on a spec/NNN-* branch, not '$CURRENT_BRANCH'" "spec/NNN-feature-name"
92
- echo " Flow: spec/NNN-* → develop → stage → main"
93
- fi
94
- ;;
95
- sdd_discover|sdd_research|sdd_import_document|sdd_import_transcript|sdd_clarify|sdd_validate_ears)
96
- # Research/clarify on spec branch
97
- if [[ "$CURRENT_BRANCH" != spec/* ]]; then
98
- warn "Research and clarification should be on a spec/NNN-* branch" "spec/NNN-feature-name"
99
- fi
100
- ;;
101
- sdd_verify_tests|sdd_verify_tasks|sdd_check_sync)
102
- # Verification on spec branch
103
- if [[ "$CURRENT_BRANCH" != spec/* ]]; then
104
- warn "Verification should be on a spec/NNN-* branch" "spec/NNN-feature-name"
105
- fi
106
- ;;
107
- sdd_run_analysis|sdd_cross_analyze|sdd_compliance_check)
108
- # Review on develop (after merge from spec)
109
- if [[ "$CURRENT_BRANCH" != "develop" ]] && [[ "$CURRENT_BRANCH" != spec/* ]]; then
110
- warn "Review tools typically run on 'develop' after merge from spec" "develop"
111
- fi
112
- ;;
113
- sdd_create_pr)
114
- # PR: branch determines target
115
- if [[ "$CURRENT_BRANCH" == spec/* ]]; then
116
- echo " ℹ️ spec branch → PR will target develop"
117
- elif [[ "$CURRENT_BRANCH" == "develop" ]]; then
118
- echo " ℹ️ develop → PR will target stage"
119
- elif [[ "$CURRENT_BRANCH" == "stage" ]]; then
120
- echo " ℹ️ stage → PR will target main"
121
- elif [[ "$CURRENT_BRANCH" == "main" ]]; then
122
- warn "Cannot create PR from main — nothing to merge" "spec/*, develop, or stage"
123
- fi
124
- ;;
125
- *)
126
- echo " ✅ No branch requirement for $TOOL"
127
- ;;
128
- esac
34
+ MESSAGE="branch '$CURRENT_BRANCH' does not match persisted release policy '$EXPECTED' for $TOOL"
35
+ if [[ "$TOOL" == "Write" || "$TOOL" == "Edit" || "$TOOL" == "MultiEdit" ]] && [ "${SPECKY_GUARD:-advisory}" = "strict" ]; then
36
+ echo "🚫 [specky-branch-validator] BLOCKED $MESSAGE" >&2
37
+ exit 2
38
+ fi
129
39
 
130
- # Always exit 0 — advisory only
40
+ echo "⚠️ [specky-branch-validator] $MESSAGE" >&2
41
+ echo " Contract: $SPECKY_CONTRACT_ID" >&2
42
+ echo " Base: $SPECKY_BASE_BRANCH | Prefix: $SPECKY_BRANCH_PREFIX" >&2
43
+ echo " Enforce native edits with: export SPECKY_GUARD=strict" >&2
131
44
  exit 0
@@ -5,14 +5,17 @@
5
5
  # Paper: arXiv:2603.22106 — cognitive surrender measurement
6
6
 
7
7
  set -euo pipefail
8
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
9
+ . "$SCRIPT_DIR/specky-contract-context.bash"
10
+ specky_load_contract_context || exit $?
11
+ [ "${SPECKY_CONTEXT_ACTIVE:-0}" = "1" ] || exit 0
8
12
 
9
- STATE=$(find . -name ".sdd-state.json" -maxdepth 2 2>/dev/null | head -1)
10
- [ -z "$STATE" ] || [ ! -f "$STATE" ] && exit 0
13
+ STATE="$SPECKY_STATE_FILE"
11
14
 
12
15
  # Check if gate history exists in state
13
16
  if command -v jq &>/dev/null && [ -f "$STATE" ]; then
14
17
  GATES=$(jq -r '.gate_history // [] | length' "$STATE" 2>/dev/null || echo "0")
15
- LGTM_NO_MOD=$(jq -r '[.gate_history // [] | .[] | select(.modified == false)] | length' "$STATE" 2>/dev/null || echo "0")
18
+ LGTM_NO_MOD=$(jq -r '[.gate_history // [] | .[] | select(.was_modified == false)] | length' "$STATE" 2>/dev/null || echo "0")
16
19
 
17
20
  if [ "$GATES" -gt 0 ]; then
18
21
  RATE=$((LGTM_NO_MOD * 100 / GATES))
@@ -0,0 +1,24 @@
1
+ # Shared explicit feature-contract context for Specky hooks.
2
+
3
+ specky_load_contract_context() {
4
+ local context_dir context_exports
5
+ context_dir=$(cd "$(dirname "$0")" && pwd)
6
+ context_exports=$(node "$context_dir/specky-contract-context.mjs" shell) || return $?
7
+ eval "$context_exports"
8
+ }
9
+
10
+ specky_has_capability() {
11
+ local capability=",${SPECKY_CAPABILITIES:-},"
12
+ case "$capability" in
13
+ *",$1,"*) return 0 ;;
14
+ *) return 1 ;;
15
+ esac
16
+ }
17
+
18
+ specky_require_feature_context() {
19
+ specky_load_contract_context || return $?
20
+ if [ "${SPECKY_CONTEXT_ACTIVE:-0}" != "1" ]; then
21
+ echo "[specky] Explicit feature context required: ${SPECKY_CONTEXT_REASON:-missing context}." >&2
22
+ return 2
23
+ fi
24
+ }
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
3
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
4
+ import { relative, resolve, sep } from "node:path";
5
+
6
+ function fail(message) {
7
+ console.error(`[specky-contract-context] ${message}`);
8
+ process.exit(2);
9
+ }
10
+
11
+ function readHookInput() {
12
+ const fromEnvironment = process.env.SDD_HOOK_INPUT;
13
+ if (fromEnvironment?.trim()) return fromEnvironment;
14
+ if (process.stdin.isTTY) return "";
15
+ try {
16
+ return readFileSync(0, "utf8");
17
+ } catch {
18
+ return "";
19
+ }
20
+ }
21
+
22
+ function parseInput(raw) {
23
+ if (!raw.trim()) return {};
24
+ try {
25
+ return JSON.parse(raw);
26
+ } catch {
27
+ return {};
28
+ }
29
+ }
30
+
31
+ function objects(value) {
32
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return [];
33
+ const record = value;
34
+ return [
35
+ record,
36
+ record.tool_input,
37
+ record.toolInput,
38
+ record.arguments,
39
+ record.input,
40
+ record.params,
41
+ record.params?.arguments,
42
+ record.request?.params?.arguments,
43
+ ].filter((candidate) => typeof candidate === "object" && candidate !== null && !Array.isArray(candidate));
44
+ }
45
+
46
+ function findString(input, keys) {
47
+ for (const candidate of objects(input)) {
48
+ for (const key of keys) {
49
+ const value = candidate[key];
50
+ if (typeof value === "string" && value.trim()) return value.trim();
51
+ }
52
+ }
53
+ return undefined;
54
+ }
55
+
56
+ function safeRelativePath(value, label) {
57
+ if (!value || value.startsWith("/") || value.startsWith("\\") || /^[A-Za-z]:/.test(value)) {
58
+ fail(`${label} must be a workspace-relative path.`);
59
+ }
60
+ const segments = value.split(/[\\/]/);
61
+ if (segments.includes("..") || value.includes("\0")) fail(`${label} contains unsafe traversal.`);
62
+ return segments.filter((segment) => segment && segment !== ".").join("/");
63
+ }
64
+
65
+ function canonicalize(value) {
66
+ if (Array.isArray(value)) return value.map(canonicalize);
67
+ if (typeof value !== "object" || value === null) return value;
68
+ return Object.keys(value)
69
+ .sort((left, right) => left.localeCompare(right))
70
+ .reduce((result, key) => {
71
+ result[key] = canonicalize(value[key]);
72
+ return result;
73
+ }, {});
74
+ }
75
+
76
+ function fingerprintContract(contract) {
77
+ const { fingerprint: _fingerprint, ...snapshot } = contract;
78
+ return createHash("sha256").update(JSON.stringify(canonicalize(snapshot))).digest("hex");
79
+ }
80
+
81
+ function safeEqualHex(left, right) {
82
+ if (!/^[a-f0-9]{64}$/.test(left) || !/^[a-f0-9]{64}$/.test(right)) return false;
83
+ return timingSafeEqual(Buffer.from(left, "hex"), Buffer.from(right, "hex"));
84
+ }
85
+
86
+ function shellQuote(value) {
87
+ return `'${String(value).replaceAll("'", `'"'"'`)}'`;
88
+ }
89
+
90
+ function resolveContext() {
91
+ const workspace = resolve(process.env.SPECKY_HOOK_WORKSPACE ?? process.cwd());
92
+ const input = parseInput(readHookInput());
93
+ const requestedSpecDir = process.env.SDD_SPEC_DIR ?? findString(input, ["spec_dir", "specDir"]);
94
+ const requestedFeatureNumber = process.env.SDD_FEATURE_NUMBER
95
+ ?? findString(input, ["feature_number", "featureNumber"]);
96
+
97
+ if (!requestedSpecDir || !requestedFeatureNumber) {
98
+ return { active: false, reason: "missing explicit SDD_SPEC_DIR/SDD_FEATURE_NUMBER context" };
99
+ }
100
+ const specDir = safeRelativePath(requestedSpecDir, "spec_dir");
101
+ if (!/^\d{3}$/.test(requestedFeatureNumber)) fail("feature_number must be exactly three digits.");
102
+
103
+ const specRoot = resolve(workspace, specDir);
104
+ if (!existsSync(specRoot)) fail(`spec root does not exist: ${specDir}`);
105
+ const matches = readdirSync(specRoot, { withFileTypes: true })
106
+ .filter((entry) => entry.isDirectory() && entry.name.startsWith(`${requestedFeatureNumber}-`));
107
+ if (matches.length !== 1) {
108
+ fail(`feature ${requestedFeatureNumber} must resolve to exactly one directory in ${specDir}; found ${matches.length}.`);
109
+ }
110
+
111
+ const featureName = matches[0].name.slice(4);
112
+ const featureDirectory = `${specDir}/${matches[0].name}`;
113
+ const statePath = resolve(workspace, featureDirectory, ".sdd-state.json");
114
+ const signaturePath = `${statePath}.sig`;
115
+ if (!existsSync(statePath) || !existsSync(signaturePath)) {
116
+ fail(`feature ${requestedFeatureNumber} requires signed v5 state at ${featureDirectory}/.sdd-state.json.`);
117
+ }
118
+
119
+ const raw = readFileSync(statePath, "utf8");
120
+ let state;
121
+ try {
122
+ state = JSON.parse(raw);
123
+ } catch {
124
+ fail(`state is not valid JSON: ${relative(workspace, statePath)}`);
125
+ }
126
+ if (state.version !== "5.0.0") fail(`state version ${String(state.version)} requires migration.`);
127
+
128
+ const key = process.env.SDD_STATE_KEY
129
+ ?? createHash("sha256").update(`specky-state-v1:${workspace}`).digest("hex");
130
+ const expectedSignature = createHmac("sha256", key).update(raw).digest("hex");
131
+ const storedSignature = readFileSync(signaturePath, "utf8").trim();
132
+ if (!safeEqualHex(storedSignature, expectedSignature)) fail("feature state signature verification failed.");
133
+
134
+ if (
135
+ state.feature?.number !== requestedFeatureNumber ||
136
+ state.feature?.name !== featureName ||
137
+ state.feature?.directory !== featureDirectory
138
+ ) {
139
+ fail(`feature state identity does not match ${featureDirectory}.`);
140
+ }
141
+ if (!state.contract || fingerprintContract(state.contract) !== state.contract.fingerprint) {
142
+ fail("feature contract fingerprint verification failed.");
143
+ }
144
+ if (!Array.isArray(state.contract.phases) || !state.contract.phases.includes(state.current_phase)) {
145
+ fail(`current phase ${String(state.current_phase)} is not enabled by the feature contract.`);
146
+ }
147
+
148
+ const capabilities = Array.isArray(state.contract.capabilities) ? state.contract.capabilities : [];
149
+ const capabilityConfig = state.contract.capability_config ?? {};
150
+ const configuredCapabilities = Object.keys(capabilityConfig).sort();
151
+ const declaredCapabilities = [...new Set(capabilities)].sort();
152
+ if (JSON.stringify(configuredCapabilities) !== JSON.stringify(declaredCapabilities)) {
153
+ fail("capabilities and capability_config keys do not match.");
154
+ }
155
+
156
+ return {
157
+ active: true,
158
+ workspace,
159
+ specDir,
160
+ featureNumber: requestedFeatureNumber,
161
+ featureName,
162
+ featureDirectory,
163
+ statePath: relative(workspace, statePath).split(sep).join("/"),
164
+ phase: state.current_phase,
165
+ contract: state.contract,
166
+ gateDecision: state.gate_decision?.decision ?? "",
167
+ };
168
+ }
169
+
170
+ function printShell(context) {
171
+ const contract = context.contract ?? {};
172
+ const capabilities = Array.isArray(contract.capabilities) ? contract.capabilities : [];
173
+ const release = contract.capability_config?.release;
174
+ const tdd = contract.capability_config?.tdd;
175
+ const compliance = contract.capability_config?.compliance;
176
+ const development = contract.capability_config?.["dev-environment"];
177
+ const iac = contract.capability_config?.iac;
178
+ const values = {
179
+ SPECKY_CONTEXT_ACTIVE: context.active ? "1" : "0",
180
+ SPECKY_CONTEXT_REASON: context.reason ?? "",
181
+ SPECKY_SPEC_DIR: context.specDir ?? "",
182
+ SPECKY_FEATURE_NUMBER: context.featureNumber ?? "",
183
+ SPECKY_FEATURE_NAME: context.featureName ?? "",
184
+ SPECKY_FEATURE_DIR: context.featureDirectory ?? "",
185
+ SPECKY_STATE_FILE: context.statePath ?? "",
186
+ SPECKY_PHASE: context.phase ?? "",
187
+ SPECKY_CONTRACT_ID: contract.id ?? "",
188
+ SPECKY_CONTRACT_FINGERPRINT: contract.fingerprint ?? "",
189
+ SPECKY_LIFECYCLE: contract.lifecycle ?? "",
190
+ SPECKY_WORKLOAD: contract.workload ?? "",
191
+ SPECKY_EXECUTION_MODE: contract.execution_mode ?? "",
192
+ SPECKY_CAPABILITIES: capabilities.join(","),
193
+ SPECKY_GATE_DECISION: context.gateDecision ?? "",
194
+ SPECKY_RELEASE_ENABLED: release ? "1" : "0",
195
+ SPECKY_BRANCH_PREFIX: release?.branch_prefix ?? "",
196
+ SPECKY_BASE_BRANCH: release?.base_branch ?? "",
197
+ SPECKY_CHECKPOINTS_REQUIRED: release?.checkpoints ? "1" : "0",
198
+ SPECKY_TDD_ENABLED: tdd ? "1" : "0",
199
+ SPECKY_TDD_THRESHOLD: tdd ? String(tdd.coverage_threshold) : "",
200
+ SPECKY_COMPLIANCE_ENABLED: compliance ? "1" : "0",
201
+ SPECKY_COMPLIANCE_FRAMEWORKS: compliance?.frameworks?.join(",") ?? "",
202
+ SPECKY_DEV_ENV_ENABLED: development ? "1" : "0",
203
+ SPECKY_DEV_LANGUAGE: development?.language ?? "",
204
+ SPECKY_IAC_ENABLED: iac ? "1" : "0",
205
+ SPECKY_IAC_PROVIDER: iac?.provider ?? "",
206
+ SPECKY_IAC_CLOUD: iac?.cloud ?? "",
207
+ };
208
+ for (const [key, value] of Object.entries(values)) console.log(`${key}=${shellQuote(value)}`);
209
+ }
210
+
211
+ const command = process.argv[2] ?? "shell";
212
+ const context = resolveContext();
213
+ if (command === "json") {
214
+ console.log(JSON.stringify(context));
215
+ } else if (command === "shell") {
216
+ printShell(context);
217
+ } else {
218
+ fail(`unknown command ${command}`);
219
+ }
@@ -5,14 +5,17 @@
5
5
  # Paper: arXiv:2602.20478, arXiv:2603.22106
6
6
 
7
7
  set -euo pipefail
8
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
9
+ . "$SCRIPT_DIR/specky-contract-context.bash"
10
+ specky_load_contract_context || exit $?
11
+ [ "${SPECKY_CONTEXT_ACTIVE:-0}" = "1" ] || exit 0
8
12
 
9
- LATEST=$(ls -td .specs/*/ 2>/dev/null | head -1 || true)
10
- [ -z "$LATEST" ] && exit 0
13
+ LATEST="$SPECKY_FEATURE_DIR"
11
14
  CONST="$LATEST/CONSTITUTION.md"
12
15
  SPEC="$LATEST/SPECIFICATION.md"
13
16
  [ -f "$CONST" ] && [ -f "$SPEC" ] || exit 0
14
17
 
15
- echo "🧭 Drift Monitor: $(basename "$LATEST")"
18
+ echo "🧭 Drift Monitor: ${SPECKY_FEATURE_NUMBER}-${SPECKY_FEATURE_NAME} ($SPECKY_CONTRACT_ID)"
16
19
 
17
20
  # Simple drift: compare key terms in constitution vs spec (POSIX ERE for portability)
18
21
  CONST_TERMS=$(grep -oE '[A-Z][a-z]+([[:space:]][A-Z][a-z]+)+' "$CONST" 2>/dev/null | sort -u | wc -l)
@@ -10,9 +10,12 @@
10
10
  # plain `set -eu` instead of bash-only `set -o pipefail`.
11
11
 
12
12
  set -eu
13
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
14
+ . "$SCRIPT_DIR/specky-contract-context.bash"
15
+ specky_load_contract_context || exit $?
16
+ [ "${SPECKY_CONTEXT_ACTIVE:-0}" = "1" ] || exit 0
13
17
 
14
- LATEST=$(ls -td .specs/*/ 2>/dev/null | head -1 || true)
15
- [ -z "$LATEST" ] && exit 0
18
+ LATEST="$SPECKY_FEATURE_DIR"
16
19
  SPEC="$LATEST/SPECIFICATION.md"
17
20
 
18
21
  if [ ! -f "$SPEC" ] || [ ! -r "$SPEC" ]; then
@@ -4,13 +4,15 @@
4
4
  # Summarizes artifact and prompts for LGTM before phase advancement
5
5
 
6
6
  set -euo pipefail
7
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
8
+ . "$SCRIPT_DIR/specky-contract-context.bash"
9
+ specky_load_contract_context || exit $?
10
+ [ "${SPECKY_CONTEXT_ACTIVE:-0}" = "1" ] || exit 0
7
11
 
8
12
  TOOL="${SDD_TOOL_NAME:-unknown}"
9
- LATEST=$(ls -td .specs/*/ 2>/dev/null | head -1 || true)
13
+ LATEST="$SPECKY_FEATURE_DIR"
10
14
 
11
- [ -z "$LATEST" ] && exit 0
12
-
13
- FEATURE=$(basename "$LATEST")
15
+ FEATURE="${SPECKY_FEATURE_NUMBER}-${SPECKY_FEATURE_NAME}"
14
16
 
15
17
  print_summary() {
16
18
  local file="$1" label="$2"
@@ -29,25 +31,25 @@ case "$TOOL" in
29
31
  sdd_write_spec|sdd_turnkey_spec|sdd_figma_to_spec)
30
32
  print_summary "SPECIFICATION.md" "SPECIFICATION.md"
31
33
  echo ""
32
- echo "⏸ LGTM GATEPhase 3 (Specify)"
34
+ echo "⏸ LGTM REVIEWSpecify ($SPECKY_CONTRACT_ID)"
33
35
  echo " Review SPECIFICATION.md above. Are the requirements correct?"
34
- echo " Reply 'LGTM' to proceed to Phase 4 (Design)."
36
+ echo " If workspace policy requires LGTM, pass lgtm:true to sdd_advance_phase."
35
37
  echo " Reply with feedback to revise."
36
38
  ;;
37
39
  sdd_write_design)
38
40
  print_summary "DESIGN.md" "DESIGN.md"
39
41
  echo ""
40
- echo "⏸ LGTM GATEPhase 4 (Design)"
42
+ echo "⏸ LGTM REVIEWDesign ($SPECKY_CONTRACT_ID)"
41
43
  echo " Review DESIGN.md above. Is the architecture sound?"
42
- echo " Reply 'LGTM' to proceed to Phase 5 (Tasks)."
44
+ echo " If workspace policy requires LGTM, pass lgtm:true to sdd_advance_phase."
43
45
  echo " Reply with feedback to revise."
44
46
  ;;
45
47
  sdd_write_tasks)
46
48
  print_summary "TASKS.md" "TASKS.md"
47
49
  echo ""
48
- echo "⏸ LGTM GATEPhase 5 (Tasks)"
50
+ echo "⏸ LGTM REVIEWTasks ($SPECKY_CONTRACT_ID)"
49
51
  echo " Review TASKS.md above. Is the task breakdown complete?"
50
- echo " Reply 'LGTM' to proceed to Phase 6 (Implement)."
52
+ echo " If workspace policy requires LGTM, pass lgtm:true to sdd_advance_phase."
51
53
  echo " Reply with feedback to revise."
52
54
  ;;
53
55
  *)
@@ -5,9 +5,12 @@
5
5
  # Paper: arXiv:2507.09089 — AI productivity paradox
6
6
 
7
7
  set -euo pipefail
8
+ SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
9
+ . "$SCRIPT_DIR/specky-contract-context.bash"
10
+ specky_load_contract_context || exit $?
11
+ [ "${SPECKY_CONTEXT_ACTIVE:-0}" = "1" ] || exit 0
8
12
 
9
- LATEST=$(ls -td .specs/*/ 2>/dev/null | head -1 || true)
10
- [ -z "$LATEST" ] && exit 0
13
+ LATEST="$SPECKY_FEATURE_DIR"
11
14
 
12
15
  # Check if analysis is done but metrics not generated
13
16
  if [ -f "$LATEST/ANALYSIS.md" ] && [ ! -f "$LATEST/specky-metrics-dashboard.html" ]; then