qualia-framework 2.6.0 → 3.1.0

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 (328) hide show
  1. package/CLAUDE.md +63 -0
  2. package/README.md +108 -30
  3. package/agents/builder.md +110 -0
  4. package/agents/planner.md +186 -0
  5. package/agents/qa-browser.md +186 -0
  6. package/agents/verifier.md +369 -0
  7. package/bin/cli.js +691 -492
  8. package/bin/install.js +622 -0
  9. package/bin/qualia-ui.js +284 -0
  10. package/bin/state.js +824 -0
  11. package/bin/statusline.js +252 -0
  12. package/docs/erp-contract.md +161 -0
  13. package/guide.md +63 -0
  14. package/hooks/auto-update.js +117 -0
  15. package/hooks/block-env-edit.js +52 -0
  16. package/hooks/branch-guard.js +68 -0
  17. package/hooks/migration-guard.js +83 -0
  18. package/hooks/pre-compact.js +52 -0
  19. package/hooks/pre-deploy-gate.js +149 -0
  20. package/hooks/pre-push.js +53 -0
  21. package/hooks/session-start.js +126 -0
  22. package/package.json +30 -20
  23. package/rules/design-reference.md +179 -0
  24. package/rules/frontend.md +126 -0
  25. package/rules/infrastructure.md +87 -0
  26. package/skills/qualia/SKILL.md +88 -0
  27. package/skills/qualia-build/SKILL.md +115 -0
  28. package/skills/qualia-debug/SKILL.md +87 -0
  29. package/skills/qualia-design/SKILL.md +99 -0
  30. package/skills/qualia-handoff/SKILL.md +66 -0
  31. package/skills/qualia-help/SKILL.md +60 -0
  32. package/skills/qualia-idk/SKILL.md +8 -0
  33. package/skills/qualia-learn/SKILL.md +111 -0
  34. package/skills/qualia-new/SKILL.md +323 -0
  35. package/skills/qualia-pause/SKILL.md +63 -0
  36. package/skills/qualia-plan/SKILL.md +101 -0
  37. package/skills/qualia-polish/SKILL.md +207 -0
  38. package/skills/qualia-quick/SKILL.md +37 -0
  39. package/skills/qualia-report/SKILL.md +114 -0
  40. package/skills/qualia-resume/SKILL.md +49 -0
  41. package/skills/qualia-review/SKILL.md +161 -0
  42. package/skills/qualia-ship/SKILL.md +90 -0
  43. package/skills/qualia-skill-new/SKILL.md +167 -0
  44. package/skills/qualia-task/SKILL.md +91 -0
  45. package/skills/qualia-test/SKILL.md +134 -0
  46. package/skills/qualia-verify/SKILL.md +113 -0
  47. package/templates/DESIGN.md +475 -0
  48. package/templates/help.html +476 -0
  49. package/templates/plan.md +42 -0
  50. package/templates/project.md +22 -0
  51. package/templates/state.md +27 -0
  52. package/templates/tracking.json +20 -0
  53. package/tests/bin.test.sh +687 -0
  54. package/tests/hooks.test.sh +384 -0
  55. package/tests/runner.js +1956 -0
  56. package/tests/state.test.sh +713 -0
  57. package/tests/statusline.test.sh +243 -0
  58. package/bin/collect-metrics.sh +0 -62
  59. package/framework/.claudeignore +0 -51
  60. package/framework/CLAUDE.md +0 -51
  61. package/framework/MCP_SETUP.md +0 -229
  62. package/framework/agents/architecture-strategist.md +0 -53
  63. package/framework/agents/backend-agent.md +0 -150
  64. package/framework/agents/code-simplicity-reviewer.md +0 -86
  65. package/framework/agents/frontend-agent.md +0 -111
  66. package/framework/agents/kieran-typescript-reviewer.md +0 -96
  67. package/framework/agents/performance-oracle.md +0 -111
  68. package/framework/agents/qualia-codebase-mapper.md +0 -761
  69. package/framework/agents/qualia-debugger.md +0 -1204
  70. package/framework/agents/qualia-executor.md +0 -882
  71. package/framework/agents/qualia-integration-checker.md +0 -424
  72. package/framework/agents/qualia-phase-researcher.md +0 -457
  73. package/framework/agents/qualia-plan-checker.md +0 -700
  74. package/framework/agents/qualia-planner.md +0 -1245
  75. package/framework/agents/qualia-project-researcher.md +0 -603
  76. package/framework/agents/qualia-research-synthesizer.md +0 -200
  77. package/framework/agents/qualia-roadmapper.md +0 -606
  78. package/framework/agents/qualia-verifier.md +0 -686
  79. package/framework/agents/red-team-qa.md +0 -130
  80. package/framework/agents/security-auditor.md +0 -72
  81. package/framework/agents/team-orchestrator.md +0 -229
  82. package/framework/agents/teams/framework-audit-team.md +0 -66
  83. package/framework/agents/teams/full-stack-team.md +0 -48
  84. package/framework/agents/teams/optimize-team.md +0 -53
  85. package/framework/agents/teams/review-team.md +0 -70
  86. package/framework/agents/teams/ship-team.md +0 -86
  87. package/framework/agents/test-agent.md +0 -182
  88. package/framework/hooks/auto-format.sh +0 -54
  89. package/framework/hooks/block-env-edit.sh +0 -42
  90. package/framework/hooks/branch-guard.sh +0 -43
  91. package/framework/hooks/confirm-delete.sh +0 -59
  92. package/framework/hooks/migration-validate.sh +0 -77
  93. package/framework/hooks/notification-speak.sh +0 -16
  94. package/framework/hooks/pre-commit.sh +0 -100
  95. package/framework/hooks/pre-compact.sh +0 -56
  96. package/framework/hooks/pre-deploy-gate.sh +0 -160
  97. package/framework/hooks/qualia-colors.sh +0 -32
  98. package/framework/hooks/retention-cleanup.sh +0 -62
  99. package/framework/hooks/save-session-state.sh +0 -185
  100. package/framework/hooks/session-context-loader.sh +0 -96
  101. package/framework/hooks/session-learn.sh +0 -32
  102. package/framework/hooks/skill-announce.sh +0 -123
  103. package/framework/hooks/tool-error-announce.sh +0 -27
  104. package/framework/install.ps1 +0 -323
  105. package/framework/install.sh +0 -313
  106. package/framework/qualia-framework/VERSION +0 -1
  107. package/framework/qualia-framework/assets/qualia-logo.png +0 -0
  108. package/framework/qualia-framework/bin/collect-metrics.sh +0 -67
  109. package/framework/qualia-framework/bin/generate-report-docx.py +0 -429
  110. package/framework/qualia-framework/bin/qualia-tools.js +0 -2201
  111. package/framework/qualia-framework/bin/qualia-tools.test.js +0 -1054
  112. package/framework/qualia-framework/references/checkpoints.md +0 -775
  113. package/framework/qualia-framework/references/completion-checklists.md +0 -359
  114. package/framework/qualia-framework/references/continuation-format.md +0 -249
  115. package/framework/qualia-framework/references/continuation-prompt.md +0 -97
  116. package/framework/qualia-framework/references/decimal-phase-calculation.md +0 -65
  117. package/framework/qualia-framework/references/design-quality.md +0 -56
  118. package/framework/qualia-framework/references/employee-guide.md +0 -167
  119. package/framework/qualia-framework/references/git-integration.md +0 -254
  120. package/framework/qualia-framework/references/git-planning-commit.md +0 -50
  121. package/framework/qualia-framework/references/model-profile-resolution.md +0 -32
  122. package/framework/qualia-framework/references/model-profiles.md +0 -73
  123. package/framework/qualia-framework/references/phase-argument-parsing.md +0 -61
  124. package/framework/qualia-framework/references/planning-config.md +0 -195
  125. package/framework/qualia-framework/references/questioning.md +0 -141
  126. package/framework/qualia-framework/references/tdd.md +0 -263
  127. package/framework/qualia-framework/references/ui-brand.md +0 -160
  128. package/framework/qualia-framework/references/verification-patterns.md +0 -612
  129. package/framework/qualia-framework/templates/DEBUG.md +0 -159
  130. package/framework/qualia-framework/templates/DESIGN.md +0 -81
  131. package/framework/qualia-framework/templates/UAT.md +0 -247
  132. package/framework/qualia-framework/templates/codebase/architecture.md +0 -255
  133. package/framework/qualia-framework/templates/codebase/concerns.md +0 -310
  134. package/framework/qualia-framework/templates/codebase/conventions.md +0 -307
  135. package/framework/qualia-framework/templates/codebase/integrations.md +0 -280
  136. package/framework/qualia-framework/templates/codebase/stack.md +0 -186
  137. package/framework/qualia-framework/templates/codebase/structure.md +0 -285
  138. package/framework/qualia-framework/templates/codebase/testing.md +0 -480
  139. package/framework/qualia-framework/templates/config.json +0 -35
  140. package/framework/qualia-framework/templates/context.md +0 -283
  141. package/framework/qualia-framework/templates/continue-here.md +0 -78
  142. package/framework/qualia-framework/templates/debug-subagent-prompt.md +0 -91
  143. package/framework/qualia-framework/templates/discovery.md +0 -146
  144. package/framework/qualia-framework/templates/lab-notes.md +0 -16
  145. package/framework/qualia-framework/templates/milestone-archive.md +0 -123
  146. package/framework/qualia-framework/templates/milestone.md +0 -115
  147. package/framework/qualia-framework/templates/phase-prompt.md +0 -567
  148. package/framework/qualia-framework/templates/planner-subagent-prompt.md +0 -117
  149. package/framework/qualia-framework/templates/project.md +0 -184
  150. package/framework/qualia-framework/templates/projects/ai-agent.md +0 -156
  151. package/framework/qualia-framework/templates/projects/mobile-app.md +0 -181
  152. package/framework/qualia-framework/templates/projects/voice-agent.md +0 -134
  153. package/framework/qualia-framework/templates/projects/website.md +0 -137
  154. package/framework/qualia-framework/templates/requirements.md +0 -231
  155. package/framework/qualia-framework/templates/research-project/ARCHITECTURE.md +0 -204
  156. package/framework/qualia-framework/templates/research-project/FEATURES.md +0 -147
  157. package/framework/qualia-framework/templates/research-project/PITFALLS.md +0 -200
  158. package/framework/qualia-framework/templates/research-project/STACK.md +0 -120
  159. package/framework/qualia-framework/templates/research-project/SUMMARY.md +0 -170
  160. package/framework/qualia-framework/templates/research.md +0 -552
  161. package/framework/qualia-framework/templates/roadmap.md +0 -206
  162. package/framework/qualia-framework/templates/state.md +0 -179
  163. package/framework/qualia-framework/templates/summary-complex.md +0 -59
  164. package/framework/qualia-framework/templates/summary-minimal.md +0 -41
  165. package/framework/qualia-framework/templates/summary-standard.md +0 -48
  166. package/framework/qualia-framework/templates/summary.md +0 -246
  167. package/framework/qualia-framework/templates/user-setup.md +0 -311
  168. package/framework/qualia-framework/templates/verification-report.md +0 -322
  169. package/framework/qualia-framework/workflows/add-phase.md +0 -179
  170. package/framework/qualia-framework/workflows/add-todo.md +0 -157
  171. package/framework/qualia-framework/workflows/audit-milestone.md +0 -241
  172. package/framework/qualia-framework/workflows/check-todos.md +0 -176
  173. package/framework/qualia-framework/workflows/complete-milestone.md +0 -858
  174. package/framework/qualia-framework/workflows/diagnose-issues.md +0 -219
  175. package/framework/qualia-framework/workflows/discovery-phase.md +0 -289
  176. package/framework/qualia-framework/workflows/discuss-phase.md +0 -534
  177. package/framework/qualia-framework/workflows/execute-phase.md +0 -559
  178. package/framework/qualia-framework/workflows/execute-plan.md +0 -438
  179. package/framework/qualia-framework/workflows/help.md +0 -470
  180. package/framework/qualia-framework/workflows/insert-phase.md +0 -220
  181. package/framework/qualia-framework/workflows/list-phase-assumptions.md +0 -178
  182. package/framework/qualia-framework/workflows/map-codebase.md +0 -327
  183. package/framework/qualia-framework/workflows/new-milestone.md +0 -363
  184. package/framework/qualia-framework/workflows/new-project.md +0 -982
  185. package/framework/qualia-framework/workflows/pause-work.md +0 -122
  186. package/framework/qualia-framework/workflows/plan-milestone-gaps.md +0 -256
  187. package/framework/qualia-framework/workflows/plan-phase.md +0 -422
  188. package/framework/qualia-framework/workflows/progress.md +0 -389
  189. package/framework/qualia-framework/workflows/quick.md +0 -252
  190. package/framework/qualia-framework/workflows/remove-phase.md +0 -326
  191. package/framework/qualia-framework/workflows/research-phase.md +0 -74
  192. package/framework/qualia-framework/workflows/resume-project.md +0 -306
  193. package/framework/qualia-framework/workflows/set-profile.md +0 -80
  194. package/framework/qualia-framework/workflows/settings.md +0 -145
  195. package/framework/qualia-framework/workflows/transition.md +0 -556
  196. package/framework/qualia-framework/workflows/update.md +0 -197
  197. package/framework/qualia-framework/workflows/verify-phase.md +0 -195
  198. package/framework/qualia-framework/workflows/verify-work.md +0 -625
  199. package/framework/rules/context7.md +0 -14
  200. package/framework/rules/frontend.md +0 -33
  201. package/framework/rules/speed.md +0 -23
  202. package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
  203. package/framework/scripts/apply-retention.sh +0 -120
  204. package/framework/scripts/bootstrap-pop-os.sh +0 -354
  205. package/framework/scripts/claude-voice +0 -13
  206. package/framework/scripts/cleanup.sh +0 -131
  207. package/framework/scripts/cowork-mode.sh +0 -141
  208. package/framework/scripts/generate-project-claude-md.sh +0 -153
  209. package/framework/scripts/load-test-webhook.js +0 -172
  210. package/framework/scripts/say.py +0 -236
  211. package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +0 -167
  212. package/framework/scripts/showcase-video-recorder/playwright-helpers.js +0 -216
  213. package/framework/scripts/speak.py +0 -55
  214. package/framework/scripts/speak.sh +0 -18
  215. package/framework/scripts/status.sh +0 -138
  216. package/framework/scripts/sync-to-framework.sh +0 -65
  217. package/framework/scripts/voice-hotkey.py +0 -227
  218. package/framework/scripts/voice-input.sh +0 -51
  219. package/framework/skills/animate/SKILL.md +0 -202
  220. package/framework/skills/bolder/SKILL.md +0 -144
  221. package/framework/skills/browser-qa/SKILL.md +0 -536
  222. package/framework/skills/clarify/SKILL.md +0 -179
  223. package/framework/skills/client-handoff/SKILL.md +0 -135
  224. package/framework/skills/collab-onboard/SKILL.md +0 -111
  225. package/framework/skills/colorize/SKILL.md +0 -170
  226. package/framework/skills/critique/SKILL.md +0 -126
  227. package/framework/skills/deep-research/SKILL.md +0 -240
  228. package/framework/skills/delight/SKILL.md +0 -329
  229. package/framework/skills/deploy/SKILL.md +0 -261
  230. package/framework/skills/deploy-verify/SKILL.md +0 -377
  231. package/framework/skills/deploy-verify/scripts/canary-check.sh +0 -206
  232. package/framework/skills/deploy-verify/scripts/check-console-errors.js +0 -147
  233. package/framework/skills/deploy-verify/scripts/check-cwv.js +0 -139
  234. package/framework/skills/deploy-verify/scripts/project-detect.sh +0 -84
  235. package/framework/skills/deploy-verify/scripts/verify.sh +0 -548
  236. package/framework/skills/design-quieter/SKILL.md +0 -130
  237. package/framework/skills/distill/SKILL.md +0 -149
  238. package/framework/skills/docs-lookup/SKILL.md +0 -79
  239. package/framework/skills/fcm-notifications/SKILL.md +0 -125
  240. package/framework/skills/financial-ledger/SKILL.md +0 -1039
  241. package/framework/skills/frontend-master/NOTICE.md +0 -4
  242. package/framework/skills/frontend-master/SKILL.md +0 -127
  243. package/framework/skills/frontend-master/reference/color-and-contrast.md +0 -132
  244. package/framework/skills/frontend-master/reference/interaction-design.md +0 -123
  245. package/framework/skills/frontend-master/reference/motion-design.md +0 -99
  246. package/framework/skills/frontend-master/reference/responsive-design.md +0 -114
  247. package/framework/skills/frontend-master/reference/spatial-design.md +0 -100
  248. package/framework/skills/frontend-master/reference/typography.md +0 -131
  249. package/framework/skills/frontend-master/reference/ux-writing.md +0 -107
  250. package/framework/skills/harden/SKILL.md +0 -357
  251. package/framework/skills/i18n-rtl/SKILL.md +0 -752
  252. package/framework/skills/learn/SKILL.md +0 -95
  253. package/framework/skills/memory/SKILL.md +0 -50
  254. package/framework/skills/mobile-expo/SKILL.md +0 -977
  255. package/framework/skills/mobile-expo/references/store-checklist.md +0 -550
  256. package/framework/skills/nestjs-backend/README.md +0 -73
  257. package/framework/skills/nestjs-backend/SKILL.md +0 -446
  258. package/framework/skills/nestjs-backend/references/templates.md +0 -1173
  259. package/framework/skills/normalize/SKILL.md +0 -79
  260. package/framework/skills/onboard/SKILL.md +0 -242
  261. package/framework/skills/openrouter-agent/SKILL.md +0 -922
  262. package/framework/skills/polish/SKILL.md +0 -209
  263. package/framework/skills/pr/SKILL.md +0 -66
  264. package/framework/skills/qualia/SKILL.md +0 -199
  265. package/framework/skills/qualia-add-todo/SKILL.md +0 -68
  266. package/framework/skills/qualia-audit-milestone/SKILL.md +0 -95
  267. package/framework/skills/qualia-check-todos/SKILL.md +0 -55
  268. package/framework/skills/qualia-complete-milestone/SKILL.md +0 -134
  269. package/framework/skills/qualia-debug/SKILL.md +0 -149
  270. package/framework/skills/qualia-design/SKILL.md +0 -203
  271. package/framework/skills/qualia-discuss-phase/SKILL.md +0 -72
  272. package/framework/skills/qualia-evolve/SKILL.md +0 -200
  273. package/framework/skills/qualia-execute-phase/SKILL.md +0 -89
  274. package/framework/skills/qualia-framework-audit/SKILL.md +0 -604
  275. package/framework/skills/qualia-guide/SKILL.md +0 -32
  276. package/framework/skills/qualia-help/SKILL.md +0 -114
  277. package/framework/skills/qualia-idk/SKILL.md +0 -352
  278. package/framework/skills/qualia-list-phase-assumptions/SKILL.md +0 -67
  279. package/framework/skills/qualia-new-milestone/SKILL.md +0 -72
  280. package/framework/skills/qualia-new-project/SKILL.md +0 -232
  281. package/framework/skills/qualia-optimize/SKILL.md +0 -417
  282. package/framework/skills/qualia-pause-work/SKILL.md +0 -96
  283. package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +0 -57
  284. package/framework/skills/qualia-plan-phase/SKILL.md +0 -104
  285. package/framework/skills/qualia-production-check/SKILL.md +0 -0
  286. package/framework/skills/qualia-progress/SKILL.md +0 -53
  287. package/framework/skills/qualia-quick/SKILL.md +0 -89
  288. package/framework/skills/qualia-report/SKILL.md +0 -166
  289. package/framework/skills/qualia-research-phase/SKILL.md +0 -88
  290. package/framework/skills/qualia-resume-work/SKILL.md +0 -62
  291. package/framework/skills/qualia-review/SKILL.md +0 -263
  292. package/framework/skills/qualia-start/SKILL.md +0 -161
  293. package/framework/skills/qualia-verify-work/SKILL.md +0 -132
  294. package/framework/skills/rag/SKILL.md +0 -750
  295. package/framework/skills/responsive/SKILL.md +0 -231
  296. package/framework/skills/retro/SKILL.md +0 -284
  297. package/framework/skills/sakani-conventions/SKILL.md +0 -136
  298. package/framework/skills/sakani-conventions/evals/evals.json +0 -23
  299. package/framework/skills/sakani-conventions/references/entities.md +0 -365
  300. package/framework/skills/sakani-conventions/references/error-codes.md +0 -95
  301. package/framework/skills/seo-master/SKILL.md +0 -490
  302. package/framework/skills/seo-master/references/checklist.md +0 -199
  303. package/framework/skills/seo-master/references/structured-data.md +0 -609
  304. package/framework/skills/ship/SKILL.md +0 -239
  305. package/framework/skills/stack-researcher/SKILL.md +0 -215
  306. package/framework/skills/status/SKILL.md +0 -154
  307. package/framework/skills/status/scripts/health-check.sh +0 -562
  308. package/framework/skills/subscription-payments/SKILL.md +0 -250
  309. package/framework/skills/supabase/SKILL.md +0 -973
  310. package/framework/skills/supabase/references/templates.md +0 -159
  311. package/framework/skills/team/SKILL.md +0 -67
  312. package/framework/skills/test-runner/SKILL.md +0 -202
  313. package/framework/skills/voice-agent/SKILL.md +0 -1312
  314. package/framework/skills/zoho-workflow/SKILL.md +0 -51
  315. package/framework/statusline-command.sh +0 -117
  316. package/framework/teams/default/inboxes/plan-04.json +0 -9
  317. package/framework/teams/review-team.md +0 -75
  318. package/framework/teams/ship-team.md +0 -86
  319. package/profiles/fawzi.json +0 -16
  320. package/profiles/hasan.json +0 -16
  321. package/profiles/moayad.json +0 -16
  322. package/templates/CLAUDE-owner.md +0 -52
  323. package/templates/CLAUDE.md.hbs +0 -58
  324. package/templates/env.claude.template +0 -12
  325. package/templates/settings.json +0 -172
  326. package/uninstall.sh +0 -90
  327. /package/{framework/rules → rules}/deployment.md +0 -0
  328. /package/{framework/rules → rules}/security.md +0 -0
@@ -0,0 +1,713 @@
1
+ #!/bin/bash
2
+ # Qualia Framework v2 — state.js behavioral tests
3
+ # Run: bash tests/state.test.sh
4
+
5
+ PASS=0
6
+ FAIL=0
7
+ # Resolve STATE_JS to an ABSOLUTE path so `cd` inside subshells doesn't break it.
8
+ STATE_JS="$(cd "$(dirname "$0")/../bin" && pwd)/state.js"
9
+ NODE="${NODE:-node}"
10
+
11
+ # Track tmp dirs we create so we can clean them up on exit
12
+ TMP_DIRS=()
13
+ cleanup() {
14
+ for d in "${TMP_DIRS[@]}"; do
15
+ [ -d "$d" ] && rm -rf "$d"
16
+ done
17
+ }
18
+ trap cleanup EXIT
19
+
20
+ # Make a fresh temp project with 2 phases, already initialized.
21
+ # Prints the absolute path to the new tmp dir (does NOT cd).
22
+ make_project() {
23
+ local TMP
24
+ TMP=$(mktemp -d)
25
+ TMP_DIRS+=("$TMP")
26
+ (
27
+ cd "$TMP" || exit 1
28
+ $NODE "$STATE_JS" init \
29
+ --project "TestProject" \
30
+ --phases '[{"name":"Foundation","goal":"Auth"},{"name":"Core","goal":"Features"}]' \
31
+ >/dev/null 2>&1
32
+ )
33
+ echo "$TMP"
34
+ }
35
+
36
+ # pass "name" — record a passing assertion
37
+ pass() {
38
+ echo " ✓ $1"
39
+ PASS=$((PASS + 1))
40
+ }
41
+
42
+ # fail "name" "detail"
43
+ fail_case() {
44
+ echo " ✗ $1${2:+ — $2}"
45
+ FAIL=$((FAIL + 1))
46
+ }
47
+
48
+ # Write a minimal valid plan file (passes content validation).
49
+ # Usage: make_valid_plan "$TMP" 1
50
+ make_valid_plan() {
51
+ local dir="$1"
52
+ local phase="${2:-1}"
53
+ cat > "$dir/.planning/phase-${phase}-plan.md" <<'PLAN'
54
+ ---
55
+ phase: 1
56
+ goal: "Test goal"
57
+ tasks: 1
58
+ waves: 1
59
+ ---
60
+
61
+ # Phase 1: Test
62
+
63
+ Goal: Test goal
64
+
65
+ ## Task 1 — Test task
66
+ **Wave:** 1
67
+ **Files:** src/test.ts
68
+ **Action:** Create test file
69
+ **Done when:** File exists
70
+
71
+ ## Success Criteria
72
+ - [ ] Test passes
73
+ PLAN
74
+ }
75
+
76
+ echo "=== state.js Behavioral Tests ==="
77
+ echo ""
78
+
79
+ # Sanity check
80
+ if [ ! -f "$STATE_JS" ]; then
81
+ echo "FATAL: state.js not found at $STATE_JS"
82
+ exit 1
83
+ fi
84
+
85
+ # ─── Basic I/O ───────────────────────────────────────────
86
+ echo "basic I/O:"
87
+
88
+ # 1. cmdInit produces valid tracking.json + STATE.md
89
+ TMP=$(mktemp -d); TMP_DIRS+=("$TMP")
90
+ (
91
+ cd "$TMP" || exit 1
92
+ $NODE "$STATE_JS" init \
93
+ --project "TestProject" \
94
+ --phases '[{"name":"Foundation","goal":"Auth"},{"name":"Core","goal":"Features"}]' \
95
+ >/tmp/qualia-state-test.out 2>&1
96
+ )
97
+ INIT_EXIT=$?
98
+ if [ "$INIT_EXIT" -eq 0 ] \
99
+ && [ -f "$TMP/.planning/tracking.json" ] \
100
+ && [ -f "$TMP/.planning/STATE.md" ] \
101
+ && grep -q '"ok": true' /tmp/qualia-state-test.out \
102
+ && grep -q '"action": "init"' /tmp/qualia-state-test.out; then
103
+ pass "cmdInit creates tracking.json + STATE.md"
104
+ else
105
+ fail_case "cmdInit creates tracking.json + STATE.md" "exit=$INIT_EXIT"
106
+ fi
107
+
108
+ # tracking.json content sanity
109
+ if grep -q '"project": "TestProject"' "$TMP/.planning/tracking.json" \
110
+ && grep -q '"total_phases": 2' "$TMP/.planning/tracking.json" \
111
+ && grep -q '"phase": 1' "$TMP/.planning/tracking.json" \
112
+ && grep -q '"status": "setup"' "$TMP/.planning/tracking.json"; then
113
+ pass "cmdInit tracking.json has correct fields"
114
+ else
115
+ fail_case "cmdInit tracking.json fields"
116
+ fi
117
+
118
+ # STATE.md content sanity
119
+ if grep -q 'Phase: 1 of 2 — Foundation' "$TMP/.planning/STATE.md" \
120
+ && grep -q 'Status: setup' "$TMP/.planning/STATE.md"; then
121
+ pass "cmdInit STATE.md has correct header"
122
+ else
123
+ fail_case "cmdInit STATE.md header"
124
+ fi
125
+
126
+ # 2. cmdCheck reads back init state
127
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
128
+ CHECK_EXIT=$?
129
+ if [ "$CHECK_EXIT" -eq 0 ] \
130
+ && echo "$OUT" | grep -q '"ok": true' \
131
+ && echo "$OUT" | grep -q '"phase": 1' \
132
+ && echo "$OUT" | grep -q '"status": "setup"' \
133
+ && echo "$OUT" | grep -q '"total_phases": 2'; then
134
+ pass "cmdCheck returns phase=1 status=setup total_phases=2"
135
+ else
136
+ fail_case "cmdCheck returns init state" "exit=$CHECK_EXIT"
137
+ fi
138
+
139
+ # 3. cmdCheck with no project → ok:false NO_PROJECT, exit 1
140
+ TMP2=$(mktemp -d); TMP_DIRS+=("$TMP2")
141
+ OUT=$(cd "$TMP2" && $NODE "$STATE_JS" check 2>&1)
142
+ CHECK_EXIT=$?
143
+ if [ "$CHECK_EXIT" -eq 1 ] \
144
+ && echo "$OUT" | grep -q '"ok": false' \
145
+ && echo "$OUT" | grep -q '"error": "NO_PROJECT"'; then
146
+ pass "cmdCheck without .planning → NO_PROJECT, exit 1"
147
+ else
148
+ fail_case "cmdCheck NO_PROJECT" "exit=$CHECK_EXIT"
149
+ fi
150
+
151
+ # ─── Happy path transitions ──────────────────────────────
152
+ echo ""
153
+ echo "happy path transitions:"
154
+
155
+ # 4. setup → planned (with plan file)
156
+ TMP=$(make_project)
157
+ make_valid_plan "$TMP" 1
158
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
159
+ EXIT=$?
160
+ if [ "$EXIT" -eq 0 ] \
161
+ && echo "$OUT" | grep -q '"ok": true' \
162
+ && echo "$OUT" | grep -q '"status": "planned"' \
163
+ && echo "$OUT" | grep -q '"previous_status": "setup"'; then
164
+ pass "setup → planned succeeds with plan file"
165
+ else
166
+ fail_case "setup → planned" "exit=$EXIT out=$OUT"
167
+ fi
168
+
169
+ # 5. planned → built (records tasks_done/tasks_total)
170
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 5 --tasks-total 5 2>&1)
171
+ EXIT=$?
172
+ if [ "$EXIT" -eq 0 ] \
173
+ && echo "$OUT" | grep -q '"ok": true' \
174
+ && echo "$OUT" | grep -q '"status": "built"' \
175
+ && grep -q '"tasks_done": 5' "$TMP/.planning/tracking.json" \
176
+ && grep -q '"tasks_total": 5' "$TMP/.planning/tracking.json"; then
177
+ pass "planned → built records tasks_done/tasks_total"
178
+ else
179
+ fail_case "planned → built" "exit=$EXIT"
180
+ fi
181
+
182
+ # 6. built → verified(pass) auto-advances to phase 2, resets status to setup
183
+ touch "$TMP/.planning/phase-1-verification.md"
184
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification pass 2>&1)
185
+ EXIT=$?
186
+ if [ "$EXIT" -eq 0 ] \
187
+ && echo "$OUT" | grep -q '"ok": true' \
188
+ && echo "$OUT" | grep -q '"phase": 2' \
189
+ && echo "$OUT" | grep -q '"status": "setup"'; then
190
+ pass "built → verified(pass) auto-advances phase and resets to setup"
191
+ else
192
+ fail_case "built → verified(pass) auto-advance" "exit=$EXIT out=$OUT"
193
+ fi
194
+
195
+ # 7. built → verified(fail) stays on phase 1, records verification=fail
196
+ TMP=$(make_project)
197
+ make_valid_plan "$TMP" 1
198
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
199
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 3 --tasks-total 5 >/dev/null 2>&1)
200
+ touch "$TMP/.planning/phase-1-verification.md"
201
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail 2>&1)
202
+ EXIT=$?
203
+ if [ "$EXIT" -eq 0 ] \
204
+ && echo "$OUT" | grep -q '"ok": true' \
205
+ && echo "$OUT" | grep -q '"phase": 1' \
206
+ && echo "$OUT" | grep -q '"status": "verified"' \
207
+ && echo "$OUT" | grep -q '"verification": "fail"'; then
208
+ pass "built → verified(fail) stays on phase 1"
209
+ else
210
+ fail_case "built → verified(fail)" "exit=$EXIT out=$OUT"
211
+ fi
212
+
213
+ # ─── Precondition failures ───────────────────────────────
214
+ echo ""
215
+ echo "precondition failures:"
216
+
217
+ # 8. setup → built fails with PRECONDITION_FAILED
218
+ TMP=$(make_project)
219
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to built 2>&1)
220
+ EXIT=$?
221
+ if [ "$EXIT" -eq 1 ] \
222
+ && echo "$OUT" | grep -q '"ok": false' \
223
+ && echo "$OUT" | grep -q '"error": "PRECONDITION_FAILED"' \
224
+ && echo "$OUT" | grep -q "Cannot go from 'setup' to 'built'"; then
225
+ pass "setup → built fails with PRECONDITION_FAILED"
226
+ else
227
+ fail_case "setup → built precondition" "exit=$EXIT out=$OUT"
228
+ fi
229
+
230
+ # 9. planned → verified fails (requires status=built)
231
+ TMP=$(make_project)
232
+ make_valid_plan "$TMP" 1
233
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
234
+ touch "$TMP/.planning/phase-1-verification.md"
235
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification pass 2>&1)
236
+ EXIT=$?
237
+ if [ "$EXIT" -eq 1 ] \
238
+ && echo "$OUT" | grep -q '"error": "PRECONDITION_FAILED"' \
239
+ && echo "$OUT" | grep -q "Cannot go from 'planned' to 'verified'"; then
240
+ pass "planned → verified fails (requires built)"
241
+ else
242
+ fail_case "planned → verified precondition" "exit=$EXIT out=$OUT"
243
+ fi
244
+
245
+ # 10. planned with missing plan file → MISSING_FILE
246
+ TMP=$(make_project)
247
+ # no phase-1-plan.md created
248
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
249
+ EXIT=$?
250
+ if [ "$EXIT" -eq 1 ] \
251
+ && echo "$OUT" | grep -q '"error": "MISSING_FILE"' \
252
+ && echo "$OUT" | grep -q "phase-1-plan.md"; then
253
+ pass "setup → planned fails without plan file (MISSING_FILE)"
254
+ else
255
+ fail_case "setup → planned MISSING_FILE" "exit=$EXIT out=$OUT"
256
+ fi
257
+
258
+ # 11. built → verified with missing verification file → MISSING_FILE
259
+ TMP=$(make_project)
260
+ make_valid_plan "$TMP" 1
261
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
262
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
263
+ # NO verification file
264
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification pass 2>&1)
265
+ EXIT=$?
266
+ if [ "$EXIT" -eq 1 ] \
267
+ && echo "$OUT" | grep -q '"error": "MISSING_FILE"' \
268
+ && echo "$OUT" | grep -q "phase-1-verification.md"; then
269
+ pass "built → verified fails without verification file (MISSING_FILE)"
270
+ else
271
+ fail_case "built → verified MISSING_FILE" "exit=$EXIT out=$OUT"
272
+ fi
273
+
274
+ # 12. built → verified without --verification → MISSING_ARG
275
+ TMP=$(make_project)
276
+ make_valid_plan "$TMP" 1
277
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
278
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
279
+ touch "$TMP/.planning/phase-1-verification.md"
280
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to verified 2>&1)
281
+ EXIT=$?
282
+ if [ "$EXIT" -eq 1 ] \
283
+ && echo "$OUT" | grep -q '"error": "MISSING_ARG"' \
284
+ && echo "$OUT" | grep -q "verification"; then
285
+ pass "built → verified without --verification → MISSING_ARG"
286
+ else
287
+ fail_case "built → verified MISSING_ARG" "exit=$EXIT out=$OUT"
288
+ fi
289
+
290
+ # 13. → shipped without --deployed-url → MISSING_ARG
291
+ # Must go through polished first, so fabricate state by transitioning through the full path.
292
+ TMP=$(make_project)
293
+ make_valid_plan "$TMP" 1
294
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
295
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
296
+ touch "$TMP/.planning/phase-1-verification.md"
297
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification pass >/dev/null 2>&1)
298
+ # Now on phase 2, status=setup. Run phase 2 to completion.
299
+ make_valid_plan "$TMP" 2
300
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
301
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
302
+ touch "$TMP/.planning/phase-2-verification.md"
303
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification pass >/dev/null 2>&1)
304
+ # Status should now be "verified" on last phase (no auto-advance past last phase)
305
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to polished >/dev/null 2>&1)
306
+ # Now try ship without deployed-url
307
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to shipped 2>&1)
308
+ EXIT=$?
309
+ if [ "$EXIT" -eq 1 ] \
310
+ && echo "$OUT" | grep -q '"error": "MISSING_ARG"' \
311
+ && echo "$OUT" | grep -q "deployed-url"; then
312
+ pass "→ shipped without --deployed-url → MISSING_ARG"
313
+ else
314
+ fail_case "→ shipped MISSING_ARG" "exit=$EXIT out=$OUT"
315
+ fi
316
+
317
+ # 14. Unknown target --to frobnicate → INVALID_STATUS
318
+ TMP=$(make_project)
319
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to frobnicate 2>&1)
320
+ EXIT=$?
321
+ if [ "$EXIT" -eq 1 ] \
322
+ && echo "$OUT" | grep -q '"error": "INVALID_STATUS"'; then
323
+ pass "--to frobnicate → INVALID_STATUS"
324
+ else
325
+ fail_case "invalid target" "exit=$EXIT out=$OUT"
326
+ fi
327
+
328
+ # ─── Gap cycle circuit breaker ───────────────────────────
329
+ echo ""
330
+ echo "gap cycle circuit breaker:"
331
+
332
+ # 15. First gap closure: verified(fail) → planned, gap_cycles[1]=1
333
+ TMP=$(make_project)
334
+ make_valid_plan "$TMP" 1
335
+ touch "$TMP/.planning/phase-1-verification.md"
336
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
337
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
338
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail >/dev/null 2>&1)
339
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
340
+ EXIT=$?
341
+ if [ "$EXIT" -eq 0 ] \
342
+ && echo "$OUT" | grep -q '"ok": true' \
343
+ && echo "$OUT" | grep -q '"gap_cycles": 1'; then
344
+ pass "first gap closure: verified(fail) → planned, gap_cycles=1"
345
+ else
346
+ fail_case "first gap closure" "exit=$EXIT out=$OUT"
347
+ fi
348
+
349
+ # 16. Second gap closure: gap_cycles[1]=2
350
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
351
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail >/dev/null 2>&1)
352
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
353
+ EXIT=$?
354
+ if [ "$EXIT" -eq 0 ] \
355
+ && echo "$OUT" | grep -q '"ok": true' \
356
+ && echo "$OUT" | grep -q '"gap_cycles": 2'; then
357
+ pass "second gap closure: gap_cycles=2"
358
+ else
359
+ fail_case "second gap closure" "exit=$EXIT out=$OUT"
360
+ fi
361
+
362
+ # 17. Third gap closure attempt → GAP_CYCLE_LIMIT
363
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
364
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail >/dev/null 2>&1)
365
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
366
+ EXIT=$?
367
+ if [ "$EXIT" -eq 1 ] \
368
+ && echo "$OUT" | grep -q '"error": "GAP_CYCLE_LIMIT"'; then
369
+ pass "third gap closure attempt blocked (GAP_CYCLE_LIMIT)"
370
+ else
371
+ fail_case "gap cycle limit" "exit=$EXIT out=$OUT"
372
+ fi
373
+
374
+ # 18. verified(pass) resets gap_cycles[1] to 0
375
+ # Set up a fresh project, do ONE failed cycle, then pass on the next attempt.
376
+ TMP=$(make_project)
377
+ make_valid_plan "$TMP" 1
378
+ touch "$TMP/.planning/phase-1-verification.md"
379
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
380
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
381
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail >/dev/null 2>&1)
382
+ # gap_cycles[1] is now 0 before the gap closure; becomes 1 after
383
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
384
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
385
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification pass >/dev/null 2>&1)
386
+ # After pass, gap_cycles[1] should be reset to 0 in tracking.json
387
+ if grep -q '"1": 0' "$TMP/.planning/tracking.json"; then
388
+ pass "verified(pass) resets gap_cycles[1] to 0"
389
+ else
390
+ fail_case "gap cycle reset on pass"
391
+ fi
392
+
393
+ # ─── Special transitions ─────────────────────────────────
394
+ echo ""
395
+ echo "special transitions:"
396
+
397
+ # 19. --to note --notes "foo" succeeds, records notes
398
+ TMP=$(make_project)
399
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to note --notes "hello world" 2>&1)
400
+ EXIT=$?
401
+ if [ "$EXIT" -eq 0 ] \
402
+ && echo "$OUT" | grep -q '"ok": true' \
403
+ && echo "$OUT" | grep -q '"action": "note"' \
404
+ && echo "$OUT" | grep -q '"status": "setup"' \
405
+ && grep -q '"notes": "hello world"' "$TMP/.planning/tracking.json"; then
406
+ pass "--to note records notes, status unchanged"
407
+ else
408
+ fail_case "--to note" "exit=$EXIT out=$OUT"
409
+ fi
410
+
411
+ # 20. --to activity succeeds without status change
412
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to activity 2>&1)
413
+ EXIT=$?
414
+ if [ "$EXIT" -eq 0 ] \
415
+ && echo "$OUT" | grep -q '"ok": true' \
416
+ && echo "$OUT" | grep -q '"action": "activity"' \
417
+ && echo "$OUT" | grep -q '"status": "setup"'; then
418
+ pass "--to activity succeeds without status change"
419
+ else
420
+ fail_case "--to activity" "exit=$EXIT out=$OUT"
421
+ fi
422
+
423
+ # ─── Parse schema errors ─────────────────────────────────
424
+ echo ""
425
+ echo "parse schema errors:"
426
+
427
+ # 21. Well-formed STATE.md: no schema_errors field in check output
428
+ TMP=$(make_project)
429
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
430
+ EXIT=$?
431
+ if [ "$EXIT" -eq 0 ] \
432
+ && echo "$OUT" | grep -q '"ok": true' \
433
+ && ! echo "$OUT" | grep -q 'schema_errors'; then
434
+ pass "well-formed STATE.md: check has no schema_errors"
435
+ else
436
+ fail_case "well-formed no schema_errors" "exit=$EXIT out=$OUT"
437
+ fi
438
+
439
+ # 22. Missing Phase: header → schema_errors with phase_header (error)
440
+ TMP=$(make_project)
441
+ sed -i.bak '/^Phase:/d' "$TMP/.planning/STATE.md"
442
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
443
+ EXIT=$?
444
+ if [ "$EXIT" -eq 0 ] \
445
+ && echo "$OUT" | grep -q 'schema_errors' \
446
+ && echo "$OUT" | grep -q 'phase_header'; then
447
+ pass "missing Phase: header → schema_errors contains phase_header"
448
+ else
449
+ fail_case "missing phase header" "exit=$EXIT out=$OUT"
450
+ fi
451
+
452
+ # 23. Missing roadmap table header → schema_errors with roadmap_table
453
+ TMP=$(make_project)
454
+ sed -i.bak '/^| # | Phase | Goal | Status |$/d' "$TMP/.planning/STATE.md"
455
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
456
+ EXIT=$?
457
+ if [ "$EXIT" -eq 0 ] \
458
+ && echo "$OUT" | grep -q 'schema_errors' \
459
+ && echo "$OUT" | grep -q 'roadmap_table'; then
460
+ pass "missing roadmap table → schema_errors contains roadmap_table"
461
+ else
462
+ fail_case "missing roadmap_table" "exit=$EXIT out=$OUT"
463
+ fi
464
+
465
+ # 24. Missing Status: line → schema_errors warning status_field, ok:true
466
+ TMP=$(make_project)
467
+ sed -i.bak '/^Status:/d' "$TMP/.planning/STATE.md"
468
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
469
+ EXIT=$?
470
+ if [ "$EXIT" -eq 0 ] \
471
+ && echo "$OUT" | grep -q '"ok": true' \
472
+ && echo "$OUT" | grep -q 'schema_errors' \
473
+ && echo "$OUT" | grep -q 'status_field' \
474
+ && echo "$OUT" | grep -q '"severity": "warning"'; then
475
+ pass "missing Status: → warning status_field, ok:true"
476
+ else
477
+ fail_case "missing Status field" "exit=$EXIT out=$OUT"
478
+ fi
479
+
480
+ # 25. Roadmap row count mismatch → schema_errors warning roadmap_rows
481
+ # Hand-edit header to claim 3 phases when only 2 rows exist.
482
+ TMP=$(make_project)
483
+ sed -i.bak 's/^Phase: 1 of 2 — Foundation/Phase: 1 of 3 — Foundation/' "$TMP/.planning/STATE.md"
484
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
485
+ EXIT=$?
486
+ if [ "$EXIT" -eq 0 ] \
487
+ && echo "$OUT" | grep -q 'schema_errors' \
488
+ && echo "$OUT" | grep -q 'roadmap_rows'; then
489
+ pass "roadmap row count mismatch → warning roadmap_rows"
490
+ else
491
+ fail_case "roadmap row count mismatch" "exit=$EXIT out=$OUT"
492
+ fi
493
+
494
+ # 26. Transition refuses on severity=error (missing Phase: header)
495
+ TMP=$(make_project)
496
+ make_valid_plan "$TMP" 1
497
+ sed -i.bak '/^Phase:/d' "$TMP/.planning/STATE.md"
498
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
499
+ EXIT=$?
500
+ if [ "$EXIT" -eq 1 ] \
501
+ && echo "$OUT" | grep -q '"error": "STATE_SCHEMA_ERROR"'; then
502
+ pass "transition refused on severity=error (STATE_SCHEMA_ERROR)"
503
+ else
504
+ fail_case "transition STATE_SCHEMA_ERROR" "exit=$EXIT out=$OUT"
505
+ fi
506
+
507
+ # 27. fix rewrites malformed STATE.md into canonical form
508
+ TMP=$(make_project)
509
+ sed -i.bak '/^Phase:/d' "$TMP/.planning/STATE.md"
510
+ # Confirm it's broken first
511
+ (cd "$TMP" && $NODE "$STATE_JS" check 2>&1 | grep -q schema_errors) || \
512
+ fail_case "fix pretest: check should show errors"
513
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" fix 2>&1)
514
+ EXIT=$?
515
+ OUT2=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
516
+ if [ "$EXIT" -eq 0 ] \
517
+ && echo "$OUT" | grep -q '"action": "fix"' \
518
+ && echo "$OUT" | grep -q '"fixed": true' \
519
+ && echo "$OUT" | grep -q '"previous_errors": 1' \
520
+ && ! echo "$OUT2" | grep -q 'schema_errors'; then
521
+ pass "fix repairs malformed STATE.md"
522
+ else
523
+ fail_case "fix repair" "exit=$EXIT fix=$OUT check=$OUT2"
524
+ fi
525
+
526
+ # 28. fix on well-formed STATE.md is a no-op (still parses clean)
527
+ TMP=$(make_project)
528
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" fix 2>&1)
529
+ EXIT=$?
530
+ OUT2=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
531
+ if [ "$EXIT" -eq 0 ] \
532
+ && echo "$OUT" | grep -q '"action": "fix"' \
533
+ && echo "$OUT" | grep -q '"previous_errors": 0' \
534
+ && ! echo "$OUT2" | grep -q 'schema_errors' \
535
+ && echo "$OUT2" | grep -q '"phase": 1' \
536
+ && echo "$OUT2" | grep -q '"total_phases": 2'; then
537
+ pass "fix on well-formed STATE.md is idempotent"
538
+ else
539
+ fail_case "fix idempotent" "exit=$EXIT fix=$OUT check=$OUT2"
540
+ fi
541
+
542
+ # 29. After fix, transition that was previously blocked now works
543
+ TMP=$(make_project)
544
+ make_valid_plan "$TMP" 1
545
+ sed -i.bak '/^Phase:/d' "$TMP/.planning/STATE.md"
546
+ # Blocked before fix
547
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1 | grep -q STATE_SCHEMA_ERROR) || \
548
+ fail_case "fix unblock pretest: should be blocked"
549
+ (cd "$TMP" && $NODE "$STATE_JS" fix >/dev/null 2>&1)
550
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
551
+ EXIT=$?
552
+ if [ "$EXIT" -eq 0 ] \
553
+ && echo "$OUT" | grep -q '"ok": true' \
554
+ && echo "$OUT" | grep -q '"status": "planned"'; then
555
+ pass "after fix, blocked transition succeeds"
556
+ else
557
+ fail_case "after fix transition" "exit=$EXIT out=$OUT"
558
+ fi
559
+
560
+ # ─── Configurable gap cycle limit ────────────────────────
561
+ echo ""
562
+ echo "configurable gap cycle limit:"
563
+
564
+ # 30. gap_cycle_limit=5 allows 3rd gap closure (would fail at default 2)
565
+ TMP=$(make_project)
566
+ make_valid_plan "$TMP" 1
567
+ touch "$TMP/.planning/phase-1-verification.md"
568
+ # Set custom limit in tracking.json
569
+ TRACKING=$(cat "$TMP/.planning/tracking.json")
570
+ echo "$TRACKING" | $NODE -e "
571
+ const t = JSON.parse(require('fs').readFileSync(0,'utf8'));
572
+ t.gap_cycle_limit = 5;
573
+ process.stdout.write(JSON.stringify(t, null, 2));
574
+ " > "$TMP/.planning/tracking.json"
575
+ # Do 3 gap closure cycles
576
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
577
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
578
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail >/dev/null 2>&1)
579
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to planned >/dev/null 2>&1)
580
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to built --tasks-done 1 --tasks-total 1 >/dev/null 2>&1)
581
+ (cd "$TMP" && $NODE "$STATE_JS" transition --to verified --verification fail >/dev/null 2>&1)
582
+ # 3rd closure should succeed (limit is 5, we're at 2)
583
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
584
+ EXIT=$?
585
+ if [ "$EXIT" -eq 0 ] \
586
+ && echo "$OUT" | grep -q '"ok": true'; then
587
+ pass "gap_cycle_limit=5 allows 3rd closure (default would block)"
588
+ else
589
+ fail_case "custom gap limit" "exit=$EXIT out=$OUT"
590
+ fi
591
+
592
+ # 31. cmdCheck includes gap_cycle_limit in output
593
+ TMP=$(make_project)
594
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" check 2>&1)
595
+ if echo "$OUT" | grep -q '"gap_cycle_limit":'; then
596
+ pass "cmdCheck includes gap_cycle_limit in output"
597
+ else
598
+ fail_case "gap_cycle_limit in check" "out=$OUT"
599
+ fi
600
+
601
+ # ─── Plan content validation ────────────────────────────
602
+ echo ""
603
+ echo "plan content validation:"
604
+
605
+ # 32. validate-plan accepts well-formed plan
606
+ TMP=$(make_project)
607
+ make_valid_plan "$TMP" 1
608
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" validate-plan --phase 1 2>&1)
609
+ EXIT=$?
610
+ if [ "$EXIT" -eq 0 ] \
611
+ && echo "$OUT" | grep -q '"action": "validate-plan"' \
612
+ && echo "$OUT" | grep -q '"task_count": 1'; then
613
+ pass "validate-plan accepts well-formed plan"
614
+ else
615
+ fail_case "validate well-formed plan" "exit=$EXIT out=$OUT"
616
+ fi
617
+
618
+ # 33. validate-plan rejects empty plan
619
+ TMP=$(make_project)
620
+ echo "" > "$TMP/.planning/phase-1-plan.md"
621
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" validate-plan --phase 1 2>&1)
622
+ EXIT=$?
623
+ if [ "$EXIT" -eq 1 ] \
624
+ && echo "$OUT" | grep -q '"error": "PLAN_VALIDATION_FAILED"'; then
625
+ pass "validate-plan rejects empty plan"
626
+ else
627
+ fail_case "validate empty plan" "exit=$EXIT out=$OUT"
628
+ fi
629
+
630
+ # 34. validate-plan rejects plan missing Done when
631
+ TMP=$(make_project)
632
+ cat > "$TMP/.planning/phase-1-plan.md" <<'EOF'
633
+ ---
634
+ phase: 1
635
+ goal: "Test"
636
+ tasks: 1
637
+ waves: 1
638
+ ---
639
+ ## Task 1 — Incomplete
640
+ **Wave:** 1
641
+ **Files:** test.ts
642
+ **Action:** Do something
643
+
644
+ ## Success Criteria
645
+ - [ ] Works
646
+ EOF
647
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" validate-plan --phase 1 2>&1)
648
+ EXIT=$?
649
+ if [ "$EXIT" -eq 1 ] \
650
+ && echo "$OUT" | grep -q "PLAN_VALIDATION_FAILED" \
651
+ && echo "$OUT" | grep -q "Done when"; then
652
+ pass "validate-plan rejects plan missing 'Done when'"
653
+ else
654
+ fail_case "validate missing done-when" "exit=$EXIT out=$OUT"
655
+ fi
656
+
657
+ # 35. Transition to planned with invalid plan content → INVALID_PLAN
658
+ TMP=$(make_project)
659
+ echo "# Empty plan with no tasks" > "$TMP/.planning/phase-1-plan.md"
660
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned 2>&1)
661
+ EXIT=$?
662
+ if [ "$EXIT" -eq 1 ] \
663
+ && echo "$OUT" | grep -q '"error": "INVALID_PLAN"'; then
664
+ pass "transition → planned with invalid plan → INVALID_PLAN"
665
+ else
666
+ fail_case "transition invalid plan" "exit=$EXIT out=$OUT"
667
+ fi
668
+
669
+ # ─── Force flag ──────────────────────────────────────────
670
+ echo ""
671
+ echo "force flag:"
672
+
673
+ # 36. --force bypasses precondition failure
674
+ TMP=$(make_project)
675
+ # setup → built should fail (requires planned first)
676
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to built --force 2>&1)
677
+ EXIT=$?
678
+ if [ "$EXIT" -eq 0 ] \
679
+ && echo "$OUT" | grep -q '"ok": true' \
680
+ && echo "$OUT" | grep -q '"status": "built"'; then
681
+ pass "--force bypasses precondition (setup → built)"
682
+ else
683
+ fail_case "force flag" "exit=$EXIT out=$OUT"
684
+ fi
685
+
686
+ # 37. --force does NOT bypass MISSING_FILE (planned without plan file)
687
+ TMP=$(make_project)
688
+ # No plan file exists — force should NOT help
689
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned --force 2>&1)
690
+ EXIT=$?
691
+ if [ "$EXIT" -eq 1 ] \
692
+ && echo "$OUT" | grep -q '"error": "MISSING_FILE"'; then
693
+ pass "--force does NOT bypass MISSING_FILE"
694
+ else
695
+ fail_case "force vs MISSING_FILE" "exit=$EXIT out=$OUT"
696
+ fi
697
+
698
+ # 38. --force does NOT bypass INVALID_PLAN
699
+ TMP=$(make_project)
700
+ echo "# No tasks here" > "$TMP/.planning/phase-1-plan.md"
701
+ OUT=$(cd "$TMP" && $NODE "$STATE_JS" transition --to planned --force 2>&1)
702
+ EXIT=$?
703
+ if [ "$EXIT" -eq 1 ] \
704
+ && echo "$OUT" | grep -q '"error": "INVALID_PLAN"'; then
705
+ pass "--force does NOT bypass INVALID_PLAN"
706
+ else
707
+ fail_case "force vs INVALID_PLAN" "exit=$EXIT out=$OUT"
708
+ fi
709
+
710
+ # ─── Summary ─────────────────────────────────────────────
711
+ echo ""
712
+ echo "=== Results: $PASS passed, $FAIL failed ==="
713
+ [ "$FAIL" -eq 0 ] && exit 0 || exit 1