cleargate 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/MANIFEST.json +72 -16
  3. package/dist/admin-api/index.cjs +0 -1
  4. package/dist/admin-api/index.js +1 -2
  5. package/dist/auth/factory.cjs +0 -1
  6. package/dist/auth/factory.js +2 -3
  7. package/dist/auth/require-token.cjs +0 -1
  8. package/dist/auth/require-token.js +1 -2
  9. package/dist/auth/token-store.cjs +0 -1
  10. package/dist/auth/token-store.js +1 -2
  11. package/dist/{bootstrap-root-QKSA5V75.js → bootstrap-root-2H5HVTCC.js} +1 -2
  12. package/dist/{chunk-PDE37WFQ.js → chunk-A7MSQUU7.js} +2 -3
  13. package/dist/{chunk-BTSZOEWC.js → chunk-P6KEDAK2.js} +0 -1
  14. package/dist/{chunk-E3X7IE5E.js → chunk-PY6FHGV5.js} +1 -2
  15. package/dist/{chunk-5DI2Z3C2.js → chunk-Y53ZZYYU.js} +1 -2
  16. package/dist/cli.cjs +1564 -1414
  17. package/dist/cli.js +1514 -1364
  18. package/dist/lib/ledger.cjs +0 -1
  19. package/dist/lib/ledger.js +1 -2
  20. package/dist/lib/lifecycle-reconcile.cjs +0 -1
  21. package/dist/lib/lifecycle-reconcile.js +2 -3
  22. package/dist/{whoami-EANGN46Z.js → whoami-JKQQPABQ.js} +3 -4
  23. package/package.json +4 -3
  24. package/templates/cleargate-planning/.claude/agents/architect-synth.md +2 -0
  25. package/templates/cleargate-planning/.claude/agents/architect.md +4 -2
  26. package/templates/cleargate-planning/.claude/agents/developer.md +4 -11
  27. package/templates/cleargate-planning/.claude/agents/qa.md +14 -6
  28. package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +2 -2
  29. package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +19 -1
  30. package/templates/cleargate-planning/.cleargate/config.example.yml +16 -0
  31. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.deferred-verify.red.node.test.ts +245 -0
  32. package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +227 -0
  33. package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +5 -4
  34. package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +75 -2
  35. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +48 -0
  36. package/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +57 -1
  37. package/templates/cleargate-planning/.cleargate/scripts/provision_worktree_config.sh +155 -0
  38. package/templates/cleargate-planning/.cleargate/scripts/qa_red_lint.mjs +380 -0
  39. package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +34 -1
  40. package/templates/cleargate-planning/.cleargate/scripts/test/cr077_eviction.red.sh +113 -0
  41. package/templates/cleargate-planning/.cleargate/scripts/test/cr078_init.test.sh +309 -0
  42. package/templates/cleargate-planning/.cleargate/scripts/test/cr079_provision.red.sh +262 -0
  43. package/templates/cleargate-planning/.cleargate/scripts/test/cr080_wrapper.test.sh +177 -0
  44. package/templates/cleargate-planning/.cleargate/scripts/test/cr081_qa_red_lint.red.sh +348 -0
  45. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/.session-totals.json +1 -0
  46. package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/token-ledger.jsonl +222 -0
  47. package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +17 -0
  48. package/templates/cleargate-planning/.cleargate/templates/story.md +1 -0
  49. package/templates/cleargate-planning/MANIFEST.json +72 -16
  50. package/dist/admin-api/index.cjs.map +0 -1
  51. package/dist/admin-api/index.js.map +0 -1
  52. package/dist/auth/factory.cjs.map +0 -1
  53. package/dist/auth/factory.js.map +0 -1
  54. package/dist/auth/require-token.cjs.map +0 -1
  55. package/dist/auth/require-token.js.map +0 -1
  56. package/dist/auth/token-store.cjs.map +0 -1
  57. package/dist/auth/token-store.js.map +0 -1
  58. package/dist/bootstrap-root-QKSA5V75.js.map +0 -1
  59. package/dist/chunk-5DI2Z3C2.js.map +0 -1
  60. package/dist/chunk-BTSZOEWC.js.map +0 -1
  61. package/dist/chunk-E3X7IE5E.js.map +0 -1
  62. package/dist/chunk-PDE37WFQ.js.map +0 -1
  63. package/dist/cli.cjs.map +0 -1
  64. package/dist/cli.js.map +0 -1
  65. package/dist/lib/ledger.cjs.map +0 -1
  66. package/dist/lib/ledger.js.map +0 -1
  67. package/dist/lib/lifecycle-reconcile.cjs.map +0 -1
  68. package/dist/lib/lifecycle-reconcile.js.map +0 -1
  69. package/dist/templates/cleargate-planning/.claude/agents/architect-reader.md +0 -61
  70. package/dist/templates/cleargate-planning/.claude/agents/architect-synth.md +0 -124
  71. package/dist/templates/cleargate-planning/.claude/agents/architect.md +0 -230
  72. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +0 -108
  73. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +0 -194
  74. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +0 -261
  75. package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +0 -143
  76. package/dist/templates/cleargate-planning/.claude/agents/developer.md +0 -185
  77. package/dist/templates/cleargate-planning/.claude/agents/devops.md +0 -257
  78. package/dist/templates/cleargate-planning/.claude/agents/qa.md +0 -171
  79. package/dist/templates/cleargate-planning/.claude/agents/reporter.md +0 -274
  80. package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +0 -209
  81. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +0 -33
  82. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-test-ratchet.sh +0 -58
  83. package/dist/templates/cleargate-planning/.claude/hooks/pre-commit.sh +0 -19
  84. package/dist/templates/cleargate-planning/.claude/hooks/pre-edit-gate.sh +0 -162
  85. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-autonomy.sh +0 -58
  86. package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +0 -148
  87. package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +0 -75
  88. package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +0 -43
  89. package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +0 -590
  90. package/dist/templates/cleargate-planning/.claude/settings.json +0 -68
  91. package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +0 -102
  92. package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +0 -742
  93. package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +0 -7
  94. package/dist/templates/cleargate-planning/.cleargate/config.example.yml +0 -67
  95. package/dist/templates/cleargate-planning/.cleargate/config.yml +0 -18
  96. package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
  97. package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
  98. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +0 -551
  99. package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +0 -878
  100. package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +0 -160
  101. package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +0 -213
  102. package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +0 -71
  103. package/dist/templates/cleargate-planning/.cleargate/scripts/_migrate-schema-v3.mjs +0 -120
  104. package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +0 -265
  105. package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +0 -1012
  106. package/dist/templates/cleargate-planning/.cleargate/scripts/collision_surface.sh +0 -114
  107. package/dist/templates/cleargate-planning/.cleargate/scripts/constants.mjs +0 -62
  108. package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +0 -219
  109. package/dist/templates/cleargate-planning/.cleargate/scripts/file_surface_diff.sh +0 -320
  110. package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +0 -15
  111. package/dist/templates/cleargate-planning/.cleargate/scripts/init_gate_config.sh +0 -38
  112. package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +0 -240
  113. package/dist/templates/cleargate-planning/.cleargate/scripts/launch_wave.mjs +0 -341
  114. package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +0 -54
  115. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +0 -206
  116. package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +0 -371
  117. package/dist/templates/cleargate-planning/.cleargate/scripts/prefill_report.mjs +0 -280
  118. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +0 -378
  119. package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +0 -888
  120. package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +0 -209
  121. package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +0 -71
  122. package/dist/templates/cleargate-planning/.cleargate/scripts/state.schema.json +0 -127
  123. package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +0 -717
  124. package/dist/templates/cleargate-planning/.cleargate/scripts/surface-whitelist.txt +0 -27
  125. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh +0 -261
  126. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_file_surface.sh +0 -210
  127. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +0 -190
  128. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +0 -482
  129. package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_test_ratchet.sh +0 -327
  130. package/dist/templates/cleargate-planning/.cleargate/scripts/test_ratchet.mjs +0 -261
  131. package/dist/templates/cleargate-planning/.cleargate/scripts/update_state.mjs +0 -246
  132. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_bounce_readiness.mjs +0 -111
  133. package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +0 -184
  134. package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +0 -172
  135. package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +0 -126
  136. package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +0 -130
  137. package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +0 -137
  138. package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +0 -166
  139. package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +0 -111
  140. package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +0 -122
  141. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +0 -50
  142. package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +0 -224
  143. package/dist/templates/cleargate-planning/.cleargate/templates/story.md +0 -213
  144. package/dist/templates/cleargate-planning/CLAUDE.md +0 -66
  145. package/dist/templates/cleargate-planning/MANIFEST.json +0 -503
  146. package/dist/templates/synthesis/active-sprint.md +0 -30
  147. package/dist/templates/synthesis/open-gates.md +0 -38
  148. package/dist/templates/synthesis/product-state.md +0 -31
  149. package/dist/templates/synthesis/roadmap.md +0 -63
  150. package/dist/whoami-EANGN46Z.js.map +0 -1
@@ -1,482 +0,0 @@
1
- #!/usr/bin/env bash
2
- # test_prep_qa_context.sh
3
- # Tests for prep_qa_context.mjs — 6 Gherkin scenarios:
4
- # 1. Happy path — all sections present, size ≤20KB, schema_version:1
5
- # 2. Missing story file — degrades to one-liner, exit 0
6
- # 3. Missing baseline cache — baseline_unavailable:true, exit 0
7
- # 4. Bundle size cap warning — oversized fixture warns stderr, still writes
8
- # 5. Legacy STATUS=done — format:legacy in JSON, SCHEMA_INCOMPLETE in prose
9
- # 6. Usage error — no args → exit 2, stderr contains "Usage:"
10
- #
11
- # Fixtures use mktemp -d. CLEARGATE_SPRINT_DIR + CLEARGATE_PENDING_SYNC_DIR
12
- # env overrides for test isolation (FLASHCARD 2026-04-21 #test-harness #scripts #env).
13
- # macOS bash 3.2 portable: no mapfile/readarray (FLASHCARD 2026-04-21 #bash #macos #portability).
14
- # Exit 0 = all pass; exit 1 = one or more failures.
15
- set -uo pipefail
16
-
17
- REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
18
- SCRIPTS_DIR="${REPO_ROOT}/.cleargate/scripts"
19
- PREP_SCRIPT="${SCRIPTS_DIR}/prep_qa_context.mjs"
20
-
21
- PASS=0
22
- FAIL=0
23
-
24
- pass() {
25
- echo "PASS: $1"
26
- PASS=$((PASS + 1))
27
- }
28
-
29
- fail() {
30
- echo "FAIL: $1"
31
- echo " detail: $2"
32
- FAIL=$((FAIL + 1))
33
- }
34
-
35
- make_tmpdir() {
36
- mktemp -d
37
- }
38
-
39
- # ── Fixture helpers ────────────────────────────────────────────────────────────
40
-
41
- # Write a minimal valid state.json with one Active story
42
- write_state_json() {
43
- local dir="$1"
44
- local story_id="${2:-STORY-AAA-01}"
45
- local story_state="${3:-Bouncing}"
46
- local lane="${4:-standard}"
47
- cat > "${dir}/state.json" << EOF
48
- {
49
- "schema_version": 2,
50
- "sprint_id": "SPRINT-fixture",
51
- "execution_mode": "v2",
52
- "sprint_status": "Active",
53
- "stories": {
54
- "${story_id}": {
55
- "state": "${story_state}",
56
- "qa_bounces": 0,
57
- "arch_bounces": 0,
58
- "worktree": null,
59
- "updated_at": "2026-05-01T00:00:00Z",
60
- "notes": "",
61
- "lane": "${lane}",
62
- "lane_assigned_by": "test",
63
- "lane_demoted_at": null,
64
- "lane_demotion_reason": null
65
- }
66
- },
67
- "last_action": "test setup",
68
- "updated_at": "2026-05-01T00:00:00Z"
69
- }
70
- EOF
71
- }
72
-
73
- # Write a minimal milestone plan
74
- write_milestone_plan() {
75
- local dir="$1"
76
- local story_id="${2:-STORY-AAA-01}"
77
- mkdir -p "${dir}/plans"
78
- cat > "${dir}/plans/M1.md" << EOF
79
- # Milestone M1 — test fixture
80
-
81
- ### ${story_id} — test story
82
-
83
- - This is a test blueprint.
84
- - Some content here.
85
-
86
- ## Another Section
87
- EOF
88
- }
89
-
90
- # Write a minimal story file in the pendingsync dir
91
- write_story_file() {
92
- local dir="$1"
93
- local story_id="${2:-STORY-AAA-01}"
94
- cat > "${dir}/${story_id}_Test_Story.md" << EOF
95
- ---
96
- story_id: ${story_id}
97
- status: Approved
98
- ---
99
-
100
- # ${story_id}: Test Story
101
-
102
- ## Gherkin
103
-
104
- Given a test fixture
105
- When the script runs
106
- Then it should pass
107
- EOF
108
- }
109
-
110
- # Write a .baseline-failures.json file
111
- write_baseline_failures() {
112
- local dir="$1"
113
- cat > "${dir}/.baseline-failures.json" << 'EOF'
114
- [
115
- {"file": "cleargate-cli/test/sprint.test.ts", "count": 1}
116
- ]
117
- EOF
118
- }
119
-
120
- # Create a fake git worktree in tmpdir
121
- # Sets up .git as a file pointing to a real git repo for git -C to work
122
- setup_fake_worktree() {
123
- local worktree_dir="$1"
124
- local story_id="${2:-STORY-AAA-01}"
125
-
126
- # Use the real repo but pretend we're checking the story branch
127
- # The worktree dir has a .git file (linked worktree style)
128
- # For simplicity, we just create a real git repo with one commit
129
-
130
- local git_dir="${worktree_dir}/.git_fake_$$"
131
- mkdir -p "${git_dir}"
132
- git -C "${worktree_dir}" init --quiet 2>/dev/null || true
133
- git -C "${worktree_dir}" config user.email "test@test.com" 2>/dev/null || true
134
- git -C "${worktree_dir}" config user.name "Test" 2>/dev/null || true
135
-
136
- # Create a dummy file and commit
137
- echo "test" > "${worktree_dir}/test-fixture.txt"
138
- git -C "${worktree_dir}" add test-fixture.txt 2>/dev/null || true
139
- git -C "${worktree_dir}" commit --quiet -m "test(fixture): initial commit
140
-
141
- STATUS: done
142
- COMMIT: abc1234
143
- TYPECHECK: pass
144
- TESTS: 3 passed, 0 failed
145
- FILES_CHANGED: test-fixture.txt
146
- NOTES: test fixture commit" 2>/dev/null || true
147
-
148
- # Create a 'main' branch alias (local ref) so diff --name-only main..HEAD works
149
- git -C "${worktree_dir}" branch -f main HEAD 2>/dev/null || true
150
- }
151
-
152
- # Create worktree with a legacy STATUS=done commit
153
- setup_legacy_status_worktree() {
154
- local worktree_dir="$1"
155
-
156
- git -C "${worktree_dir}" init --quiet 2>/dev/null || true
157
- git -C "${worktree_dir}" config user.email "test@test.com" 2>/dev/null || true
158
- git -C "${worktree_dir}" config user.name "Test" 2>/dev/null || true
159
-
160
- echo "test" > "${worktree_dir}/test-file.txt"
161
- git -C "${worktree_dir}" add test-file.txt 2>/dev/null || true
162
- git -C "${worktree_dir}" commit --quiet -m "feat(test): legacy commit
163
-
164
- STATUS: done
165
- COMMIT: def5678
166
- TYPECHECK: pass
167
- TESTS: 2 passed, 0 failed
168
- FILES_CHANGED: test-file.txt
169
- NOTES: legacy format without r_coverage or plan_deviations" 2>/dev/null || true
170
-
171
- git -C "${worktree_dir}" branch -f main HEAD 2>/dev/null || true
172
- }
173
-
174
- # ─── Scenario 1: Happy path ───────────────────────────────────────────────────
175
-
176
- run_scenario_1() {
177
- local tmpdir pendingsync_dir worktree_dir output_path
178
- tmpdir="$(make_tmpdir)"
179
- pendingsync_dir="$(make_tmpdir)"
180
- worktree_dir="$(make_tmpdir)"
181
-
182
- write_state_json "${tmpdir}" "STORY-AAA-01" "Bouncing" "standard"
183
- write_milestone_plan "${tmpdir}" "STORY-AAA-01"
184
- write_story_file "${pendingsync_dir}" "STORY-AAA-01"
185
- write_baseline_failures "${tmpdir}"
186
- setup_fake_worktree "${worktree_dir}" "STORY-AAA-01"
187
-
188
- output_path="${tmpdir}/.qa-context-STORY-AAA-01.md"
189
-
190
- local exit_code stderr_out
191
- stderr_out=$(CLEARGATE_SPRINT_DIR="${tmpdir}" CLEARGATE_PENDING_SYNC_DIR="${pendingsync_dir}" \
192
- node "${PREP_SCRIPT}" STORY-AAA-01 "${worktree_dir}" --output "${output_path}" 2>&1 >/dev/null)
193
- exit_code=$?
194
-
195
- if [ "${exit_code}" -ne 0 ]; then
196
- fail "Scenario 1: happy path — expected exit 0, got ${exit_code}" "${stderr_out}"
197
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
198
- fi
199
-
200
- if [ ! -f "${output_path}" ]; then
201
- fail "Scenario 1: happy path — output file not written at ${output_path}" "file missing"
202
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
203
- fi
204
-
205
- # Check size ≤20KB (20480 bytes)
206
- local bundle_size
207
- bundle_size=$(wc -c < "${output_path}" | tr -d ' ')
208
- if [ "${bundle_size}" -gt 20480 ]; then
209
- fail "Scenario 1: happy path — bundle size ${bundle_size} bytes exceeds 20KB" "too large"
210
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
211
- fi
212
-
213
- # Check all 8 section headers
214
- local section
215
- for section in "Worktree + Commit" "Spec Sources" "Baseline" "Adjacent Files" "Cross-Story Map" "Flashcard Slice" "Lane" "Dev Handoff"; do
216
- if ! grep -qF "${section}" "${output_path}"; then
217
- fail "Scenario 1: happy path — missing section '${section}' in bundle" "$(head -30 "${output_path}")"
218
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
219
- fi
220
- done
221
-
222
- # Check JSON block parses to schema_version: 1
223
- local schema_version
224
- schema_version=$(node -e "
225
- const fs = require('fs');
226
- const content = fs.readFileSync('${output_path}', 'utf8');
227
- const m = content.match(/\`\`\`json\\n([\\s\\S]*?)\\n\`\`\`/);
228
- if (!m) { process.stdout.write('NO_JSON\\n'); process.exit(0); }
229
- const obj = JSON.parse(m[1]);
230
- process.stdout.write(String(obj.schema_version) + '\\n');
231
- " 2>/dev/null)
232
-
233
- if [ "${schema_version}" != "1" ]; then
234
- fail "Scenario 1: happy path — expected schema_version 1, got '${schema_version}'" "json parse issue"
235
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
236
- fi
237
-
238
- pass "Scenario 1: prep_qa_context happy path — all 8 sections, ≤20KB, schema_version:1"
239
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"
240
- }
241
-
242
- # ─── Scenario 2: Missing story file → one-liner ───────────────────────────────
243
-
244
- run_scenario_2() {
245
- local tmpdir pendingsync_dir worktree_dir output_path
246
- tmpdir="$(make_tmpdir)"
247
- pendingsync_dir="$(make_tmpdir)"
248
- worktree_dir="$(make_tmpdir)"
249
-
250
- write_state_json "${tmpdir}" "STORY-AAA-01" "Bouncing" "standard"
251
- write_milestone_plan "${tmpdir}" "STORY-AAA-01"
252
- # Deliberately NO story file in pendingsync_dir
253
- write_baseline_failures "${tmpdir}"
254
- setup_fake_worktree "${worktree_dir}" "STORY-AAA-01"
255
-
256
- output_path="${tmpdir}/.qa-context-STORY-AAA-01.md"
257
-
258
- local exit_code
259
- CLEARGATE_SPRINT_DIR="${tmpdir}" CLEARGATE_PENDING_SYNC_DIR="${pendingsync_dir}" \
260
- node "${PREP_SCRIPT}" STORY-AAA-01 "${worktree_dir}" --output "${output_path}" >/dev/null 2>&1
261
- exit_code=$?
262
-
263
- if [ "${exit_code}" -ne 0 ]; then
264
- fail "Scenario 2: missing story — expected exit 0, got ${exit_code}" "exit code mismatch"
265
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
266
- fi
267
-
268
- if [ ! -f "${output_path}" ]; then
269
- fail "Scenario 2: missing story — output file not written" "file missing"
270
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
271
- fi
272
-
273
- # Spec Sources section must contain the story-not-found one-liner
274
- if ! grep -qF "Story file not found" "${output_path}"; then
275
- fail "Scenario 2: missing story — expected 'Story file not found' one-liner in Spec Sources" \
276
- "$(grep -A5 'Spec Sources' "${output_path}" | head -10)"
277
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
278
- fi
279
-
280
- # Other sections still present (not impacted)
281
- if ! grep -qF "## Baseline" "${output_path}"; then
282
- fail "Scenario 2: missing story — Baseline section missing (other sections impacted)" "missing section"
283
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
284
- fi
285
-
286
- pass "Scenario 2: missing story file degrades to one-liner, other sections unaffected"
287
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"
288
- }
289
-
290
- # ─── Scenario 3: Missing baseline cache → baseline_unavailable:true ──────────
291
-
292
- run_scenario_3() {
293
- local tmpdir pendingsync_dir worktree_dir output_path
294
- tmpdir="$(make_tmpdir)"
295
- pendingsync_dir="$(make_tmpdir)"
296
- worktree_dir="$(make_tmpdir)"
297
-
298
- write_state_json "${tmpdir}" "STORY-AAA-01" "Bouncing" "standard"
299
- write_milestone_plan "${tmpdir}" "STORY-AAA-01"
300
- write_story_file "${pendingsync_dir}" "STORY-AAA-01"
301
- # Deliberately NO .baseline-failures.json
302
- setup_fake_worktree "${worktree_dir}" "STORY-AAA-01"
303
-
304
- output_path="${tmpdir}/.qa-context-STORY-AAA-01.md"
305
-
306
- local exit_code
307
- CLEARGATE_SPRINT_DIR="${tmpdir}" CLEARGATE_PENDING_SYNC_DIR="${pendingsync_dir}" \
308
- node "${PREP_SCRIPT}" STORY-AAA-01 "${worktree_dir}" --output "${output_path}" >/dev/null 2>&1
309
- exit_code=$?
310
-
311
- if [ "${exit_code}" -ne 0 ]; then
312
- fail "Scenario 3: missing baseline — expected exit 0, got ${exit_code}" "exit code mismatch"
313
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
314
- fi
315
-
316
- # Check JSON baseline_unavailable === true
317
- local baseline_unavailable
318
- baseline_unavailable=$(node -e "
319
- const fs = require('fs');
320
- const content = fs.readFileSync('${output_path}', 'utf8');
321
- const m = content.match(/\`\`\`json\\n([\\s\\S]*?)\\n\`\`\`/);
322
- if (!m) { process.stdout.write('NO_JSON\\n'); process.exit(0); }
323
- const obj = JSON.parse(m[1]);
324
- process.stdout.write(String(obj.baseline.baseline_unavailable) + '\\n');
325
- " 2>/dev/null)
326
-
327
- if [ "${baseline_unavailable}" != "true" ]; then
328
- fail "Scenario 3: missing baseline — expected baseline_unavailable=true, got '${baseline_unavailable}'" "json check"
329
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
330
- fi
331
-
332
- # Prose should contain recompute one-liner
333
- if ! grep -q "cleargate gate test" "${output_path}"; then
334
- fail "Scenario 3: missing baseline — expected recompute one-liner in Baseline section" \
335
- "$(grep -A5 '## Baseline' "${output_path}" | head -10)"
336
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
337
- fi
338
-
339
- pass "Scenario 3: missing baseline cache → baseline_unavailable:true, recompute one-liner present"
340
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"
341
- }
342
-
343
- # ─── Scenario 4: Bundle size cap warning ─────────────────────────────────────
344
-
345
- run_scenario_4() {
346
- local tmpdir pendingsync_dir worktree_dir output_path
347
- tmpdir="$(make_tmpdir)"
348
- pendingsync_dir="$(make_tmpdir)"
349
- worktree_dir="$(make_tmpdir)"
350
-
351
- write_state_json "${tmpdir}" "STORY-AAA-01" "Bouncing" "standard"
352
- write_milestone_plan "${tmpdir}" "STORY-AAA-01"
353
- write_story_file "${pendingsync_dir}" "STORY-AAA-01"
354
-
355
- # Create an oversized fixture: write a very large baseline-failures.json
356
- # with 500+ entries to bloat the JSON block past 20KB
357
- local big_json="${tmpdir}/.baseline-failures.json"
358
- printf '[' > "${big_json}"
359
- local i=0
360
- while [ $i -lt 400 ]; do
361
- if [ $i -gt 0 ]; then printf ',' >> "${big_json}"; fi
362
- printf '{"file":"cleargate-cli/test/very/long/path/to/some/test/file/number_%d_with_extra_padding_so_it_is_bigger/test.spec.ts","count":%d}' $i $i >> "${big_json}"
363
- i=$((i + 1))
364
- done
365
- printf ']' >> "${big_json}"
366
-
367
- setup_fake_worktree "${worktree_dir}" "STORY-AAA-01"
368
-
369
- output_path="${tmpdir}/.qa-context-STORY-AAA-01.md"
370
-
371
- local exit_code stderr_out
372
- stderr_out=$(CLEARGATE_SPRINT_DIR="${tmpdir}" CLEARGATE_PENDING_SYNC_DIR="${pendingsync_dir}" \
373
- node "${PREP_SCRIPT}" STORY-AAA-01 "${worktree_dir}" --output "${output_path}" 2>&1 >/dev/null)
374
- exit_code=$?
375
-
376
- # Must still exit 0 (R4: write anyway)
377
- if [ "${exit_code}" -ne 0 ]; then
378
- fail "Scenario 4: size cap — expected exit 0 even when oversized, got ${exit_code}" "${stderr_out}"
379
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
380
- fi
381
-
382
- # Bundle must still be written
383
- if [ ! -f "${output_path}" ]; then
384
- fail "Scenario 4: size cap — bundle not written even when oversized" "file missing"
385
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
386
- fi
387
-
388
- # Stderr must contain warning about exceeding 20KB
389
- if ! echo "${stderr_out}" | grep -qi "exceeds 20KB"; then
390
- fail "Scenario 4: size cap — expected stderr warning about 20KB target" "stderr: ${stderr_out}"
391
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
392
- fi
393
-
394
- pass "Scenario 4: oversized fixture → exit 0, bundle written, stderr warns about 20KB"
395
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"
396
- }
397
-
398
- # ─── Scenario 5: Legacy STATUS=done → format:legacy ──────────────────────────
399
-
400
- run_scenario_5() {
401
- local tmpdir pendingsync_dir worktree_dir output_path
402
- tmpdir="$(make_tmpdir)"
403
- pendingsync_dir="$(make_tmpdir)"
404
- worktree_dir="$(make_tmpdir)"
405
-
406
- write_state_json "${tmpdir}" "STORY-AAA-01" "Bouncing" "standard"
407
- write_milestone_plan "${tmpdir}" "STORY-AAA-01"
408
- write_story_file "${pendingsync_dir}" "STORY-AAA-01"
409
- setup_legacy_status_worktree "${worktree_dir}"
410
-
411
- output_path="${tmpdir}/.qa-context-STORY-AAA-01.md"
412
-
413
- local exit_code
414
- CLEARGATE_SPRINT_DIR="${tmpdir}" CLEARGATE_PENDING_SYNC_DIR="${pendingsync_dir}" \
415
- node "${PREP_SCRIPT}" STORY-AAA-01 "${worktree_dir}" --output "${output_path}" >/dev/null 2>&1
416
- exit_code=$?
417
-
418
- if [ "${exit_code}" -ne 0 ]; then
419
- fail "Scenario 5: legacy handoff — expected exit 0, got ${exit_code}" "exit code mismatch"
420
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
421
- fi
422
-
423
- # Check JSON dev_handoff.format === "legacy"
424
- local handoff_format
425
- handoff_format=$(node -e "
426
- const fs = require('fs');
427
- const content = fs.readFileSync('${output_path}', 'utf8');
428
- const m = content.match(/\`\`\`json\\n([\\s\\S]*?)\\n\`\`\`/);
429
- if (!m) { process.stdout.write('NO_JSON\\n'); process.exit(0); }
430
- const obj = JSON.parse(m[1]);
431
- process.stdout.write(String(obj.dev_handoff.format) + '\\n');
432
- " 2>/dev/null)
433
-
434
- if [ "${handoff_format}" != "legacy" ]; then
435
- fail "Scenario 5: legacy handoff — expected dev_handoff.format=legacy, got '${handoff_format}'" "json check"
436
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
437
- fi
438
-
439
- # Prose must contain SCHEMA_INCOMPLETE warning
440
- if ! grep -qF "SCHEMA_INCOMPLETE" "${output_path}"; then
441
- fail "Scenario 5: legacy handoff — expected SCHEMA_INCOMPLETE in Dev Handoff section" \
442
- "$(grep -A5 '## Dev Handoff' "${output_path}" | head -10)"
443
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"; return
444
- fi
445
-
446
- pass "Scenario 5: legacy STATUS=done → format:legacy in JSON, SCHEMA_INCOMPLETE in prose"
447
- rm -rf "${tmpdir}" "${pendingsync_dir}" "${worktree_dir}"
448
- }
449
-
450
- # ─── Scenario 6: Usage error — no args ────────────────────────────────────────
451
-
452
- run_scenario_6() {
453
- local exit_code stderr_out
454
-
455
- stderr_out=$(node "${PREP_SCRIPT}" 2>&1 >/dev/null)
456
- exit_code=$?
457
-
458
- if [ "${exit_code}" -ne 2 ]; then
459
- fail "Scenario 6: usage error — expected exit 2, got ${exit_code}" "exit code mismatch"
460
- return
461
- fi
462
-
463
- if ! echo "${stderr_out}" | grep -qi "Usage:"; then
464
- fail "Scenario 6: usage error — stderr must contain 'Usage:'" "stderr: ${stderr_out}"
465
- return
466
- fi
467
-
468
- pass "Scenario 6: no args → exit 2, stderr contains 'Usage:'"
469
- }
470
-
471
- # ─── Run all scenarios ────────────────────────────────────────────────────────
472
-
473
- run_scenario_1
474
- run_scenario_2
475
- run_scenario_3
476
- run_scenario_4
477
- run_scenario_5
478
- run_scenario_6
479
-
480
- echo ""
481
- echo "Results: ${PASS} passed, ${FAIL} failed"
482
- [ "${FAIL}" -eq 0 ] && exit 0 || exit 1