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.
- package/CLAUDE.md +63 -0
- package/README.md +108 -30
- package/agents/builder.md +110 -0
- package/agents/planner.md +186 -0
- package/agents/qa-browser.md +186 -0
- package/agents/verifier.md +369 -0
- package/bin/cli.js +691 -492
- package/bin/install.js +622 -0
- package/bin/qualia-ui.js +284 -0
- package/bin/state.js +824 -0
- package/bin/statusline.js +252 -0
- package/docs/erp-contract.md +161 -0
- package/guide.md +63 -0
- package/hooks/auto-update.js +117 -0
- package/hooks/block-env-edit.js +52 -0
- package/hooks/branch-guard.js +68 -0
- package/hooks/migration-guard.js +83 -0
- package/hooks/pre-compact.js +52 -0
- package/hooks/pre-deploy-gate.js +149 -0
- package/hooks/pre-push.js +53 -0
- package/hooks/session-start.js +126 -0
- package/package.json +30 -20
- package/rules/design-reference.md +179 -0
- package/rules/frontend.md +126 -0
- package/rules/infrastructure.md +87 -0
- package/skills/qualia/SKILL.md +88 -0
- package/skills/qualia-build/SKILL.md +115 -0
- package/skills/qualia-debug/SKILL.md +87 -0
- package/skills/qualia-design/SKILL.md +99 -0
- package/skills/qualia-handoff/SKILL.md +66 -0
- package/skills/qualia-help/SKILL.md +60 -0
- package/skills/qualia-idk/SKILL.md +8 -0
- package/skills/qualia-learn/SKILL.md +111 -0
- package/skills/qualia-new/SKILL.md +323 -0
- package/skills/qualia-pause/SKILL.md +63 -0
- package/skills/qualia-plan/SKILL.md +101 -0
- package/skills/qualia-polish/SKILL.md +207 -0
- package/skills/qualia-quick/SKILL.md +37 -0
- package/skills/qualia-report/SKILL.md +114 -0
- package/skills/qualia-resume/SKILL.md +49 -0
- package/skills/qualia-review/SKILL.md +161 -0
- package/skills/qualia-ship/SKILL.md +90 -0
- package/skills/qualia-skill-new/SKILL.md +167 -0
- package/skills/qualia-task/SKILL.md +91 -0
- package/skills/qualia-test/SKILL.md +134 -0
- package/skills/qualia-verify/SKILL.md +113 -0
- package/templates/DESIGN.md +475 -0
- package/templates/help.html +476 -0
- package/templates/plan.md +42 -0
- package/templates/project.md +22 -0
- package/templates/state.md +27 -0
- package/templates/tracking.json +20 -0
- package/tests/bin.test.sh +687 -0
- package/tests/hooks.test.sh +384 -0
- package/tests/runner.js +1956 -0
- package/tests/state.test.sh +713 -0
- package/tests/statusline.test.sh +243 -0
- package/bin/collect-metrics.sh +0 -62
- package/framework/.claudeignore +0 -51
- package/framework/CLAUDE.md +0 -51
- package/framework/MCP_SETUP.md +0 -229
- package/framework/agents/architecture-strategist.md +0 -53
- package/framework/agents/backend-agent.md +0 -150
- package/framework/agents/code-simplicity-reviewer.md +0 -86
- package/framework/agents/frontend-agent.md +0 -111
- package/framework/agents/kieran-typescript-reviewer.md +0 -96
- package/framework/agents/performance-oracle.md +0 -111
- package/framework/agents/qualia-codebase-mapper.md +0 -761
- package/framework/agents/qualia-debugger.md +0 -1204
- package/framework/agents/qualia-executor.md +0 -882
- package/framework/agents/qualia-integration-checker.md +0 -424
- package/framework/agents/qualia-phase-researcher.md +0 -457
- package/framework/agents/qualia-plan-checker.md +0 -700
- package/framework/agents/qualia-planner.md +0 -1245
- package/framework/agents/qualia-project-researcher.md +0 -603
- package/framework/agents/qualia-research-synthesizer.md +0 -200
- package/framework/agents/qualia-roadmapper.md +0 -606
- package/framework/agents/qualia-verifier.md +0 -686
- package/framework/agents/red-team-qa.md +0 -130
- package/framework/agents/security-auditor.md +0 -72
- package/framework/agents/team-orchestrator.md +0 -229
- package/framework/agents/teams/framework-audit-team.md +0 -66
- package/framework/agents/teams/full-stack-team.md +0 -48
- package/framework/agents/teams/optimize-team.md +0 -53
- package/framework/agents/teams/review-team.md +0 -70
- package/framework/agents/teams/ship-team.md +0 -86
- package/framework/agents/test-agent.md +0 -182
- package/framework/hooks/auto-format.sh +0 -54
- package/framework/hooks/block-env-edit.sh +0 -42
- package/framework/hooks/branch-guard.sh +0 -43
- package/framework/hooks/confirm-delete.sh +0 -59
- package/framework/hooks/migration-validate.sh +0 -77
- package/framework/hooks/notification-speak.sh +0 -16
- package/framework/hooks/pre-commit.sh +0 -100
- package/framework/hooks/pre-compact.sh +0 -56
- package/framework/hooks/pre-deploy-gate.sh +0 -160
- package/framework/hooks/qualia-colors.sh +0 -32
- package/framework/hooks/retention-cleanup.sh +0 -62
- package/framework/hooks/save-session-state.sh +0 -185
- package/framework/hooks/session-context-loader.sh +0 -96
- package/framework/hooks/session-learn.sh +0 -32
- package/framework/hooks/skill-announce.sh +0 -123
- package/framework/hooks/tool-error-announce.sh +0 -27
- package/framework/install.ps1 +0 -323
- package/framework/install.sh +0 -313
- package/framework/qualia-framework/VERSION +0 -1
- package/framework/qualia-framework/assets/qualia-logo.png +0 -0
- package/framework/qualia-framework/bin/collect-metrics.sh +0 -67
- package/framework/qualia-framework/bin/generate-report-docx.py +0 -429
- package/framework/qualia-framework/bin/qualia-tools.js +0 -2201
- package/framework/qualia-framework/bin/qualia-tools.test.js +0 -1054
- package/framework/qualia-framework/references/checkpoints.md +0 -775
- package/framework/qualia-framework/references/completion-checklists.md +0 -359
- package/framework/qualia-framework/references/continuation-format.md +0 -249
- package/framework/qualia-framework/references/continuation-prompt.md +0 -97
- package/framework/qualia-framework/references/decimal-phase-calculation.md +0 -65
- package/framework/qualia-framework/references/design-quality.md +0 -56
- package/framework/qualia-framework/references/employee-guide.md +0 -167
- package/framework/qualia-framework/references/git-integration.md +0 -254
- package/framework/qualia-framework/references/git-planning-commit.md +0 -50
- package/framework/qualia-framework/references/model-profile-resolution.md +0 -32
- package/framework/qualia-framework/references/model-profiles.md +0 -73
- package/framework/qualia-framework/references/phase-argument-parsing.md +0 -61
- package/framework/qualia-framework/references/planning-config.md +0 -195
- package/framework/qualia-framework/references/questioning.md +0 -141
- package/framework/qualia-framework/references/tdd.md +0 -263
- package/framework/qualia-framework/references/ui-brand.md +0 -160
- package/framework/qualia-framework/references/verification-patterns.md +0 -612
- package/framework/qualia-framework/templates/DEBUG.md +0 -159
- package/framework/qualia-framework/templates/DESIGN.md +0 -81
- package/framework/qualia-framework/templates/UAT.md +0 -247
- package/framework/qualia-framework/templates/codebase/architecture.md +0 -255
- package/framework/qualia-framework/templates/codebase/concerns.md +0 -310
- package/framework/qualia-framework/templates/codebase/conventions.md +0 -307
- package/framework/qualia-framework/templates/codebase/integrations.md +0 -280
- package/framework/qualia-framework/templates/codebase/stack.md +0 -186
- package/framework/qualia-framework/templates/codebase/structure.md +0 -285
- package/framework/qualia-framework/templates/codebase/testing.md +0 -480
- package/framework/qualia-framework/templates/config.json +0 -35
- package/framework/qualia-framework/templates/context.md +0 -283
- package/framework/qualia-framework/templates/continue-here.md +0 -78
- package/framework/qualia-framework/templates/debug-subagent-prompt.md +0 -91
- package/framework/qualia-framework/templates/discovery.md +0 -146
- package/framework/qualia-framework/templates/lab-notes.md +0 -16
- package/framework/qualia-framework/templates/milestone-archive.md +0 -123
- package/framework/qualia-framework/templates/milestone.md +0 -115
- package/framework/qualia-framework/templates/phase-prompt.md +0 -567
- package/framework/qualia-framework/templates/planner-subagent-prompt.md +0 -117
- package/framework/qualia-framework/templates/project.md +0 -184
- package/framework/qualia-framework/templates/projects/ai-agent.md +0 -156
- package/framework/qualia-framework/templates/projects/mobile-app.md +0 -181
- package/framework/qualia-framework/templates/projects/voice-agent.md +0 -134
- package/framework/qualia-framework/templates/projects/website.md +0 -137
- package/framework/qualia-framework/templates/requirements.md +0 -231
- package/framework/qualia-framework/templates/research-project/ARCHITECTURE.md +0 -204
- package/framework/qualia-framework/templates/research-project/FEATURES.md +0 -147
- package/framework/qualia-framework/templates/research-project/PITFALLS.md +0 -200
- package/framework/qualia-framework/templates/research-project/STACK.md +0 -120
- package/framework/qualia-framework/templates/research-project/SUMMARY.md +0 -170
- package/framework/qualia-framework/templates/research.md +0 -552
- package/framework/qualia-framework/templates/roadmap.md +0 -206
- package/framework/qualia-framework/templates/state.md +0 -179
- package/framework/qualia-framework/templates/summary-complex.md +0 -59
- package/framework/qualia-framework/templates/summary-minimal.md +0 -41
- package/framework/qualia-framework/templates/summary-standard.md +0 -48
- package/framework/qualia-framework/templates/summary.md +0 -246
- package/framework/qualia-framework/templates/user-setup.md +0 -311
- package/framework/qualia-framework/templates/verification-report.md +0 -322
- package/framework/qualia-framework/workflows/add-phase.md +0 -179
- package/framework/qualia-framework/workflows/add-todo.md +0 -157
- package/framework/qualia-framework/workflows/audit-milestone.md +0 -241
- package/framework/qualia-framework/workflows/check-todos.md +0 -176
- package/framework/qualia-framework/workflows/complete-milestone.md +0 -858
- package/framework/qualia-framework/workflows/diagnose-issues.md +0 -219
- package/framework/qualia-framework/workflows/discovery-phase.md +0 -289
- package/framework/qualia-framework/workflows/discuss-phase.md +0 -534
- package/framework/qualia-framework/workflows/execute-phase.md +0 -559
- package/framework/qualia-framework/workflows/execute-plan.md +0 -438
- package/framework/qualia-framework/workflows/help.md +0 -470
- package/framework/qualia-framework/workflows/insert-phase.md +0 -220
- package/framework/qualia-framework/workflows/list-phase-assumptions.md +0 -178
- package/framework/qualia-framework/workflows/map-codebase.md +0 -327
- package/framework/qualia-framework/workflows/new-milestone.md +0 -363
- package/framework/qualia-framework/workflows/new-project.md +0 -982
- package/framework/qualia-framework/workflows/pause-work.md +0 -122
- package/framework/qualia-framework/workflows/plan-milestone-gaps.md +0 -256
- package/framework/qualia-framework/workflows/plan-phase.md +0 -422
- package/framework/qualia-framework/workflows/progress.md +0 -389
- package/framework/qualia-framework/workflows/quick.md +0 -252
- package/framework/qualia-framework/workflows/remove-phase.md +0 -326
- package/framework/qualia-framework/workflows/research-phase.md +0 -74
- package/framework/qualia-framework/workflows/resume-project.md +0 -306
- package/framework/qualia-framework/workflows/set-profile.md +0 -80
- package/framework/qualia-framework/workflows/settings.md +0 -145
- package/framework/qualia-framework/workflows/transition.md +0 -556
- package/framework/qualia-framework/workflows/update.md +0 -197
- package/framework/qualia-framework/workflows/verify-phase.md +0 -195
- package/framework/qualia-framework/workflows/verify-work.md +0 -625
- package/framework/rules/context7.md +0 -14
- package/framework/rules/frontend.md +0 -33
- package/framework/rules/speed.md +0 -23
- package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
- package/framework/scripts/apply-retention.sh +0 -120
- package/framework/scripts/bootstrap-pop-os.sh +0 -354
- package/framework/scripts/claude-voice +0 -13
- package/framework/scripts/cleanup.sh +0 -131
- package/framework/scripts/cowork-mode.sh +0 -141
- package/framework/scripts/generate-project-claude-md.sh +0 -153
- package/framework/scripts/load-test-webhook.js +0 -172
- package/framework/scripts/say.py +0 -236
- package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +0 -167
- package/framework/scripts/showcase-video-recorder/playwright-helpers.js +0 -216
- package/framework/scripts/speak.py +0 -55
- package/framework/scripts/speak.sh +0 -18
- package/framework/scripts/status.sh +0 -138
- package/framework/scripts/sync-to-framework.sh +0 -65
- package/framework/scripts/voice-hotkey.py +0 -227
- package/framework/scripts/voice-input.sh +0 -51
- package/framework/skills/animate/SKILL.md +0 -202
- package/framework/skills/bolder/SKILL.md +0 -144
- package/framework/skills/browser-qa/SKILL.md +0 -536
- package/framework/skills/clarify/SKILL.md +0 -179
- package/framework/skills/client-handoff/SKILL.md +0 -135
- package/framework/skills/collab-onboard/SKILL.md +0 -111
- package/framework/skills/colorize/SKILL.md +0 -170
- package/framework/skills/critique/SKILL.md +0 -126
- package/framework/skills/deep-research/SKILL.md +0 -240
- package/framework/skills/delight/SKILL.md +0 -329
- package/framework/skills/deploy/SKILL.md +0 -261
- package/framework/skills/deploy-verify/SKILL.md +0 -377
- package/framework/skills/deploy-verify/scripts/canary-check.sh +0 -206
- package/framework/skills/deploy-verify/scripts/check-console-errors.js +0 -147
- package/framework/skills/deploy-verify/scripts/check-cwv.js +0 -139
- package/framework/skills/deploy-verify/scripts/project-detect.sh +0 -84
- package/framework/skills/deploy-verify/scripts/verify.sh +0 -548
- package/framework/skills/design-quieter/SKILL.md +0 -130
- package/framework/skills/distill/SKILL.md +0 -149
- package/framework/skills/docs-lookup/SKILL.md +0 -79
- package/framework/skills/fcm-notifications/SKILL.md +0 -125
- package/framework/skills/financial-ledger/SKILL.md +0 -1039
- package/framework/skills/frontend-master/NOTICE.md +0 -4
- package/framework/skills/frontend-master/SKILL.md +0 -127
- package/framework/skills/frontend-master/reference/color-and-contrast.md +0 -132
- package/framework/skills/frontend-master/reference/interaction-design.md +0 -123
- package/framework/skills/frontend-master/reference/motion-design.md +0 -99
- package/framework/skills/frontend-master/reference/responsive-design.md +0 -114
- package/framework/skills/frontend-master/reference/spatial-design.md +0 -100
- package/framework/skills/frontend-master/reference/typography.md +0 -131
- package/framework/skills/frontend-master/reference/ux-writing.md +0 -107
- package/framework/skills/harden/SKILL.md +0 -357
- package/framework/skills/i18n-rtl/SKILL.md +0 -752
- package/framework/skills/learn/SKILL.md +0 -95
- package/framework/skills/memory/SKILL.md +0 -50
- package/framework/skills/mobile-expo/SKILL.md +0 -977
- package/framework/skills/mobile-expo/references/store-checklist.md +0 -550
- package/framework/skills/nestjs-backend/README.md +0 -73
- package/framework/skills/nestjs-backend/SKILL.md +0 -446
- package/framework/skills/nestjs-backend/references/templates.md +0 -1173
- package/framework/skills/normalize/SKILL.md +0 -79
- package/framework/skills/onboard/SKILL.md +0 -242
- package/framework/skills/openrouter-agent/SKILL.md +0 -922
- package/framework/skills/polish/SKILL.md +0 -209
- package/framework/skills/pr/SKILL.md +0 -66
- package/framework/skills/qualia/SKILL.md +0 -199
- package/framework/skills/qualia-add-todo/SKILL.md +0 -68
- package/framework/skills/qualia-audit-milestone/SKILL.md +0 -95
- package/framework/skills/qualia-check-todos/SKILL.md +0 -55
- package/framework/skills/qualia-complete-milestone/SKILL.md +0 -134
- package/framework/skills/qualia-debug/SKILL.md +0 -149
- package/framework/skills/qualia-design/SKILL.md +0 -203
- package/framework/skills/qualia-discuss-phase/SKILL.md +0 -72
- package/framework/skills/qualia-evolve/SKILL.md +0 -200
- package/framework/skills/qualia-execute-phase/SKILL.md +0 -89
- package/framework/skills/qualia-framework-audit/SKILL.md +0 -604
- package/framework/skills/qualia-guide/SKILL.md +0 -32
- package/framework/skills/qualia-help/SKILL.md +0 -114
- package/framework/skills/qualia-idk/SKILL.md +0 -352
- package/framework/skills/qualia-list-phase-assumptions/SKILL.md +0 -67
- package/framework/skills/qualia-new-milestone/SKILL.md +0 -72
- package/framework/skills/qualia-new-project/SKILL.md +0 -232
- package/framework/skills/qualia-optimize/SKILL.md +0 -417
- package/framework/skills/qualia-pause-work/SKILL.md +0 -96
- package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +0 -57
- package/framework/skills/qualia-plan-phase/SKILL.md +0 -104
- package/framework/skills/qualia-production-check/SKILL.md +0 -0
- package/framework/skills/qualia-progress/SKILL.md +0 -53
- package/framework/skills/qualia-quick/SKILL.md +0 -89
- package/framework/skills/qualia-report/SKILL.md +0 -166
- package/framework/skills/qualia-research-phase/SKILL.md +0 -88
- package/framework/skills/qualia-resume-work/SKILL.md +0 -62
- package/framework/skills/qualia-review/SKILL.md +0 -263
- package/framework/skills/qualia-start/SKILL.md +0 -161
- package/framework/skills/qualia-verify-work/SKILL.md +0 -132
- package/framework/skills/rag/SKILL.md +0 -750
- package/framework/skills/responsive/SKILL.md +0 -231
- package/framework/skills/retro/SKILL.md +0 -284
- package/framework/skills/sakani-conventions/SKILL.md +0 -136
- package/framework/skills/sakani-conventions/evals/evals.json +0 -23
- package/framework/skills/sakani-conventions/references/entities.md +0 -365
- package/framework/skills/sakani-conventions/references/error-codes.md +0 -95
- package/framework/skills/seo-master/SKILL.md +0 -490
- package/framework/skills/seo-master/references/checklist.md +0 -199
- package/framework/skills/seo-master/references/structured-data.md +0 -609
- package/framework/skills/ship/SKILL.md +0 -239
- package/framework/skills/stack-researcher/SKILL.md +0 -215
- package/framework/skills/status/SKILL.md +0 -154
- package/framework/skills/status/scripts/health-check.sh +0 -562
- package/framework/skills/subscription-payments/SKILL.md +0 -250
- package/framework/skills/supabase/SKILL.md +0 -973
- package/framework/skills/supabase/references/templates.md +0 -159
- package/framework/skills/team/SKILL.md +0 -67
- package/framework/skills/test-runner/SKILL.md +0 -202
- package/framework/skills/voice-agent/SKILL.md +0 -1312
- package/framework/skills/zoho-workflow/SKILL.md +0 -51
- package/framework/statusline-command.sh +0 -117
- package/framework/teams/default/inboxes/plan-04.json +0 -9
- package/framework/teams/review-team.md +0 -75
- package/framework/teams/ship-team.md +0 -86
- package/profiles/fawzi.json +0 -16
- package/profiles/hasan.json +0 -16
- package/profiles/moayad.json +0 -16
- package/templates/CLAUDE-owner.md +0 -52
- package/templates/CLAUDE.md.hbs +0 -58
- package/templates/env.claude.template +0 -12
- package/templates/settings.json +0 -172
- package/uninstall.sh +0 -90
- /package/{framework/rules → rules}/deployment.md +0 -0
- /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
|