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.
- package/CHANGELOG.md +21 -0
- package/dist/MANIFEST.json +72 -16
- package/dist/admin-api/index.cjs +0 -1
- package/dist/admin-api/index.js +1 -2
- package/dist/auth/factory.cjs +0 -1
- package/dist/auth/factory.js +2 -3
- package/dist/auth/require-token.cjs +0 -1
- package/dist/auth/require-token.js +1 -2
- package/dist/auth/token-store.cjs +0 -1
- package/dist/auth/token-store.js +1 -2
- package/dist/{bootstrap-root-QKSA5V75.js → bootstrap-root-2H5HVTCC.js} +1 -2
- package/dist/{chunk-PDE37WFQ.js → chunk-A7MSQUU7.js} +2 -3
- package/dist/{chunk-BTSZOEWC.js → chunk-P6KEDAK2.js} +0 -1
- package/dist/{chunk-E3X7IE5E.js → chunk-PY6FHGV5.js} +1 -2
- package/dist/{chunk-5DI2Z3C2.js → chunk-Y53ZZYYU.js} +1 -2
- package/dist/cli.cjs +1564 -1414
- package/dist/cli.js +1514 -1364
- package/dist/lib/ledger.cjs +0 -1
- package/dist/lib/ledger.js +1 -2
- package/dist/lib/lifecycle-reconcile.cjs +0 -1
- package/dist/lib/lifecycle-reconcile.js +2 -3
- package/dist/{whoami-EANGN46Z.js → whoami-JKQQPABQ.js} +3 -4
- package/package.json +4 -3
- package/templates/cleargate-planning/.claude/agents/architect-synth.md +2 -0
- package/templates/cleargate-planning/.claude/agents/architect.md +4 -2
- package/templates/cleargate-planning/.claude/agents/developer.md +4 -11
- package/templates/cleargate-planning/.claude/agents/qa.md +14 -6
- package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +2 -2
- package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +19 -1
- package/templates/cleargate-planning/.cleargate/config.example.yml +16 -0
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.deferred-verify.red.node.test.ts +245 -0
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +227 -0
- package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +5 -4
- package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +75 -2
- package/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +48 -0
- package/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +57 -1
- package/templates/cleargate-planning/.cleargate/scripts/provision_worktree_config.sh +155 -0
- package/templates/cleargate-planning/.cleargate/scripts/qa_red_lint.mjs +380 -0
- package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +34 -1
- package/templates/cleargate-planning/.cleargate/scripts/test/cr077_eviction.red.sh +113 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr078_init.test.sh +309 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr079_provision.red.sh +262 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr080_wrapper.test.sh +177 -0
- package/templates/cleargate-planning/.cleargate/scripts/test/cr081_qa_red_lint.red.sh +348 -0
- package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/.session-totals.json +1 -0
- package/templates/cleargate-planning/.cleargate/sprint-runs/_off-sprint/token-ledger.jsonl +222 -0
- package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +17 -0
- package/templates/cleargate-planning/.cleargate/templates/story.md +1 -0
- package/templates/cleargate-planning/MANIFEST.json +72 -16
- package/dist/admin-api/index.cjs.map +0 -1
- package/dist/admin-api/index.js.map +0 -1
- package/dist/auth/factory.cjs.map +0 -1
- package/dist/auth/factory.js.map +0 -1
- package/dist/auth/require-token.cjs.map +0 -1
- package/dist/auth/require-token.js.map +0 -1
- package/dist/auth/token-store.cjs.map +0 -1
- package/dist/auth/token-store.js.map +0 -1
- package/dist/bootstrap-root-QKSA5V75.js.map +0 -1
- package/dist/chunk-5DI2Z3C2.js.map +0 -1
- package/dist/chunk-BTSZOEWC.js.map +0 -1
- package/dist/chunk-E3X7IE5E.js.map +0 -1
- package/dist/chunk-PDE37WFQ.js.map +0 -1
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/lib/ledger.cjs.map +0 -1
- package/dist/lib/ledger.js.map +0 -1
- package/dist/lib/lifecycle-reconcile.cjs.map +0 -1
- package/dist/lib/lifecycle-reconcile.js.map +0 -1
- package/dist/templates/cleargate-planning/.claude/agents/architect-reader.md +0 -61
- package/dist/templates/cleargate-planning/.claude/agents/architect-synth.md +0 -124
- package/dist/templates/cleargate-planning/.claude/agents/architect.md +0 -230
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-contradict.md +0 -108
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-ingest.md +0 -194
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +0 -261
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-query.md +0 -143
- package/dist/templates/cleargate-planning/.claude/agents/developer.md +0 -185
- package/dist/templates/cleargate-planning/.claude/agents/devops.md +0 -257
- package/dist/templates/cleargate-planning/.claude/agents/qa.md +0 -171
- package/dist/templates/cleargate-planning/.claude/agents/reporter.md +0 -274
- package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +0 -209
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +0 -33
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-test-ratchet.sh +0 -58
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit.sh +0 -19
- package/dist/templates/cleargate-planning/.claude/hooks/pre-edit-gate.sh +0 -162
- package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-autonomy.sh +0 -58
- package/dist/templates/cleargate-planning/.claude/hooks/pre-tool-use-task.sh +0 -148
- package/dist/templates/cleargate-planning/.claude/hooks/session-start.sh +0 -75
- package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +0 -43
- package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +0 -590
- package/dist/templates/cleargate-planning/.claude/settings.json +0 -68
- package/dist/templates/cleargate-planning/.claude/skills/flashcard/SKILL.md +0 -102
- package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +0 -742
- package/dist/templates/cleargate-planning/.cleargate/FLASHCARD.md +0 -7
- package/dist/templates/cleargate-planning/.cleargate/config.example.yml +0 -67
- package/dist/templates/cleargate-planning/.cleargate/config.yml +0 -18
- package/dist/templates/cleargate-planning/.cleargate/delivery/archive/.gitkeep +0 -0
- package/dist/templates/cleargate-planning/.cleargate/delivery/pending-sync/.gitkeep +0 -0
- package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-enforcement.md +0 -551
- package/dist/templates/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md +0 -878
- package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +0 -160
- package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +0 -213
- package/dist/templates/cleargate-planning/.cleargate/knowledge/sprint-closeout-checklist.md +0 -71
- package/dist/templates/cleargate-planning/.cleargate/scripts/_migrate-schema-v3.mjs +0 -120
- package/dist/templates/cleargate-planning/.cleargate/scripts/assert_story_files.mjs +0 -265
- package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +0 -1012
- package/dist/templates/cleargate-planning/.cleargate/scripts/collision_surface.sh +0 -114
- package/dist/templates/cleargate-planning/.cleargate/scripts/constants.mjs +0 -62
- package/dist/templates/cleargate-planning/.cleargate/scripts/dedupe_frontmatter.mjs +0 -219
- package/dist/templates/cleargate-planning/.cleargate/scripts/file_surface_diff.sh +0 -320
- package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +0 -15
- package/dist/templates/cleargate-planning/.cleargate/scripts/init_gate_config.sh +0 -38
- package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +0 -240
- package/dist/templates/cleargate-planning/.cleargate/scripts/launch_wave.mjs +0 -341
- package/dist/templates/cleargate-planning/.cleargate/scripts/lib/report-filename.mjs +0 -54
- package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_common.sh +0 -206
- package/dist/templates/cleargate-planning/.cleargate/scripts/pre_gate_runner.sh +0 -371
- package/dist/templates/cleargate-planning/.cleargate/scripts/prefill_report.mjs +0 -280
- package/dist/templates/cleargate-planning/.cleargate/scripts/prep_doc_refresh.mjs +0 -378
- package/dist/templates/cleargate-planning/.cleargate/scripts/prep_qa_context.mjs +0 -888
- package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +0 -209
- package/dist/templates/cleargate-planning/.cleargate/scripts/sprint_trends.mjs +0 -71
- package/dist/templates/cleargate-planning/.cleargate/scripts/state.schema.json +0 -127
- package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +0 -717
- package/dist/templates/cleargate-planning/.cleargate/scripts/surface-whitelist.txt +0 -27
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh +0 -261
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_file_surface.sh +0 -210
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +0 -190
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_prep_qa_context.sh +0 -482
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_test_ratchet.sh +0 -327
- package/dist/templates/cleargate-planning/.cleargate/scripts/test_ratchet.mjs +0 -261
- package/dist/templates/cleargate-planning/.cleargate/scripts/update_state.mjs +0 -246
- package/dist/templates/cleargate-planning/.cleargate/scripts/validate_bounce_readiness.mjs +0 -111
- package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +0 -184
- package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +0 -172
- package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +0 -126
- package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +0 -130
- package/dist/templates/cleargate-planning/.cleargate/templates/Sprint Plan Template.md +0 -137
- package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +0 -166
- package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +0 -111
- package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +0 -122
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +0 -50
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +0 -224
- package/dist/templates/cleargate-planning/.cleargate/templates/story.md +0 -213
- package/dist/templates/cleargate-planning/CLAUDE.md +0 -66
- package/dist/templates/cleargate-planning/MANIFEST.json +0 -503
- package/dist/templates/synthesis/active-sprint.md +0 -30
- package/dist/templates/synthesis/open-gates.md +0 -38
- package/dist/templates/synthesis/product-state.md +0 -31
- package/dist/templates/synthesis/roadmap.md +0 -63
- package/dist/whoami-EANGN46Z.js.map +0 -1
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# surface-whitelist.txt — Files always admitted by the pre-commit surface gate
|
|
2
|
-
# regardless of the active story's §3.1 declared surface.
|
|
3
|
-
#
|
|
4
|
-
# Format: one pattern per line. Supports bash glob patterns.
|
|
5
|
-
# * matches any non-path-separator sequence
|
|
6
|
-
# ** matches any sequence (including path separators)
|
|
7
|
-
# Lines starting with # are comments; blank lines are ignored.
|
|
8
|
-
#
|
|
9
|
-
# These patterns are matched against repo-root-relative staged file paths.
|
|
10
|
-
|
|
11
|
-
# Build manifest (regenerated by npm run build)
|
|
12
|
-
cleargate-planning/MANIFEST.json
|
|
13
|
-
|
|
14
|
-
# Hook execution logs
|
|
15
|
-
.cleargate/hook-log/*
|
|
16
|
-
|
|
17
|
-
# Token ledger files (auto-generated by SubagentStop hook)
|
|
18
|
-
.cleargate/sprint-runs/**/token-ledger.jsonl
|
|
19
|
-
|
|
20
|
-
# Pending-task sentinel files (auto-generated by PreToolUse hook)
|
|
21
|
-
.cleargate/sprint-runs/**/.pending-task-*.json
|
|
22
|
-
|
|
23
|
-
# Sprint state files (auto-managed)
|
|
24
|
-
.cleargate/sprint-runs/**/state.json
|
|
25
|
-
|
|
26
|
-
# Gate check log (auto-generated)
|
|
27
|
-
.cleargate/hook-log/gate-check.log
|
package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_assert_story_files.sh
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# test_assert_story_files.sh — 4-scenario Gherkin test for STORY-014-02
|
|
3
|
-
#
|
|
4
|
-
# Tests:
|
|
5
|
-
# Scenario 1: v2 init refuses when stories are missing
|
|
6
|
-
# Scenario 2: v2 init succeeds when all stories exist
|
|
7
|
-
# Scenario 3: v1 init warns but does not block
|
|
8
|
-
# Scenario 4: assert_story_files standalone CLI
|
|
9
|
-
#
|
|
10
|
-
# Run: bash .cleargate/scripts/test/test_assert_story_files.sh
|
|
11
|
-
# Requires Node 24+.
|
|
12
|
-
#
|
|
13
|
-
# Story IDs must use digit-only parts (STORY-\d+-\d+), e.g. STORY-099-01.
|
|
14
|
-
|
|
15
|
-
set -euo pipefail
|
|
16
|
-
|
|
17
|
-
SCRIPTS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
18
|
-
REPO_ROOT="$(cd "${SCRIPTS_DIR}/../.." && pwd)"
|
|
19
|
-
|
|
20
|
-
PASS=0
|
|
21
|
-
FAIL=0
|
|
22
|
-
ERRORS=()
|
|
23
|
-
|
|
24
|
-
assert_eq() {
|
|
25
|
-
local label="$1" expected="$2" actual="$3"
|
|
26
|
-
if [ "$expected" = "$actual" ]; then
|
|
27
|
-
echo " PASS: $label"
|
|
28
|
-
PASS=$((PASS + 1))
|
|
29
|
-
else
|
|
30
|
-
echo " FAIL: $label"
|
|
31
|
-
echo " expected: $expected"
|
|
32
|
-
echo " actual: $actual"
|
|
33
|
-
FAIL=$((FAIL + 1))
|
|
34
|
-
ERRORS+=("$label")
|
|
35
|
-
fi
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
assert_contains() {
|
|
39
|
-
local label="$1" needle="$2" haystack="$3"
|
|
40
|
-
if echo "$haystack" | grep -qF "$needle"; then
|
|
41
|
-
echo " PASS: $label"
|
|
42
|
-
PASS=$((PASS + 1))
|
|
43
|
-
else
|
|
44
|
-
echo " FAIL: $label (needle not found)"
|
|
45
|
-
echo " needle: $needle"
|
|
46
|
-
echo " haystack: $haystack"
|
|
47
|
-
FAIL=$((FAIL + 1))
|
|
48
|
-
ERRORS+=("$label")
|
|
49
|
-
fi
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
assert_not_exists() {
|
|
53
|
-
local label="$1" filepath="$2"
|
|
54
|
-
if [ ! -e "$filepath" ]; then
|
|
55
|
-
echo " PASS: $label"
|
|
56
|
-
PASS=$((PASS + 1))
|
|
57
|
-
else
|
|
58
|
-
echo " FAIL: $label (file exists but should not)"
|
|
59
|
-
echo " path: $filepath"
|
|
60
|
-
FAIL=$((FAIL + 1))
|
|
61
|
-
ERRORS+=("$label")
|
|
62
|
-
fi
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
assert_exists() {
|
|
66
|
-
local label="$1" filepath="$2"
|
|
67
|
-
if [ -e "$filepath" ]; then
|
|
68
|
-
echo " PASS: $label"
|
|
69
|
-
PASS=$((PASS + 1))
|
|
70
|
-
else
|
|
71
|
-
echo " FAIL: $label (file does not exist)"
|
|
72
|
-
echo " path: $filepath"
|
|
73
|
-
FAIL=$((FAIL + 1))
|
|
74
|
-
ERRORS+=("$label")
|
|
75
|
-
fi
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
# Create a minimal sprint file with given execution_mode
|
|
79
|
-
# Story IDs must be STORY-\d+-\d+ (all numeric parts) for the regex to match.
|
|
80
|
-
# Usage: make_sprint_file <dir> <sprint-id> <execution_mode> <story-id-1> [<story-id-2> ...]
|
|
81
|
-
make_sprint_file() {
|
|
82
|
-
local dir="$1" sprint_id="$2" exec_mode="$3"
|
|
83
|
-
shift 3
|
|
84
|
-
local story_ids=("$@")
|
|
85
|
-
|
|
86
|
-
local sprint_file="${dir}/.cleargate/delivery/pending-sync/${sprint_id}_Test_Sprint.md"
|
|
87
|
-
mkdir -p "$(dirname "$sprint_file")"
|
|
88
|
-
|
|
89
|
-
{
|
|
90
|
-
echo "---"
|
|
91
|
-
echo "sprint_id: \"${sprint_id}\""
|
|
92
|
-
echo "execution_mode: \"${exec_mode}\""
|
|
93
|
-
echo "approved: true"
|
|
94
|
-
echo "---"
|
|
95
|
-
echo ""
|
|
96
|
-
echo "# ${sprint_id}: Test Sprint"
|
|
97
|
-
echo ""
|
|
98
|
-
echo "## 1. Consolidated Deliverables"
|
|
99
|
-
echo ""
|
|
100
|
-
echo "| Story | Complexity | Milestone |"
|
|
101
|
-
echo "|---|---|---|"
|
|
102
|
-
for sid in "${story_ids[@]}"; do
|
|
103
|
-
echo "| [\`${sid}\`](${sid}_Placeholder.md) Placeholder | L2 | M1 |"
|
|
104
|
-
done
|
|
105
|
-
echo ""
|
|
106
|
-
echo "## 2. Other Section"
|
|
107
|
-
echo ""
|
|
108
|
-
echo "Some content here."
|
|
109
|
-
} > "$sprint_file"
|
|
110
|
-
|
|
111
|
-
echo "$sprint_file"
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
# Create a minimal story file in pending-sync/
|
|
115
|
-
make_story_file() {
|
|
116
|
-
local dir="$1" story_id="$2"
|
|
117
|
-
local pending_sync="${dir}/.cleargate/delivery/pending-sync"
|
|
118
|
-
mkdir -p "$pending_sync"
|
|
119
|
-
echo "# ${story_id}: Placeholder" > "${pending_sync}/${story_id}_Placeholder.md"
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
# ---------------------------------------------------------------------------
|
|
123
|
-
echo ""
|
|
124
|
-
echo "=== Scenario 1: v2 init refuses when stories are missing ==="
|
|
125
|
-
# ---------------------------------------------------------------------------
|
|
126
|
-
TMP1="$(mktemp -d)"
|
|
127
|
-
trap 'rm -rf "$TMP1"' EXIT
|
|
128
|
-
|
|
129
|
-
SPRINT_ID="SPRINT-099"
|
|
130
|
-
make_sprint_file "$TMP1" "$SPRINT_ID" "v2" \
|
|
131
|
-
"STORY-099-01" "STORY-099-02" "STORY-099-03" > /dev/null
|
|
132
|
-
|
|
133
|
-
# Only create STORY-099-01, leave 02 and 03 missing
|
|
134
|
-
make_story_file "$TMP1" "STORY-099-01"
|
|
135
|
-
|
|
136
|
-
STATE_JSON="${TMP1}/.cleargate/sprint-runs/${SPRINT_ID}/state.json"
|
|
137
|
-
|
|
138
|
-
STDERR_OUT=""
|
|
139
|
-
EXIT_CODE=0
|
|
140
|
-
STDERR_OUT="$(CLEARGATE_REPO_ROOT="$TMP1" node "$SCRIPTS_DIR/init_sprint.mjs" \
|
|
141
|
-
"$SPRINT_ID" --stories "STORY-099-01,STORY-099-02,STORY-099-03" 2>&1 >/dev/null)" || EXIT_CODE=$?
|
|
142
|
-
|
|
143
|
-
assert_eq "Sc1: exit code non-zero" "1" "$EXIT_CODE"
|
|
144
|
-
assert_contains "Sc1: stderr mentions STORY-099-02" "STORY-099-02" "$STDERR_OUT"
|
|
145
|
-
assert_contains "Sc1: stderr mentions STORY-099-03" "STORY-099-03" "$STDERR_OUT"
|
|
146
|
-
assert_not_exists "Sc1: state.json NOT created" "$STATE_JSON"
|
|
147
|
-
|
|
148
|
-
trap - EXIT
|
|
149
|
-
rm -rf "$TMP1"
|
|
150
|
-
|
|
151
|
-
# ---------------------------------------------------------------------------
|
|
152
|
-
echo ""
|
|
153
|
-
echo "=== Scenario 2: v2 init succeeds when all stories exist ==="
|
|
154
|
-
# ---------------------------------------------------------------------------
|
|
155
|
-
TMP2="$(mktemp -d)"
|
|
156
|
-
trap 'rm -rf "$TMP2"' EXIT
|
|
157
|
-
|
|
158
|
-
SPRINT_ID="SPRINT-098"
|
|
159
|
-
make_sprint_file "$TMP2" "$SPRINT_ID" "v2" \
|
|
160
|
-
"STORY-098-01" "STORY-098-02" "STORY-098-03" > /dev/null
|
|
161
|
-
|
|
162
|
-
make_story_file "$TMP2" "STORY-098-01"
|
|
163
|
-
make_story_file "$TMP2" "STORY-098-02"
|
|
164
|
-
make_story_file "$TMP2" "STORY-098-03"
|
|
165
|
-
|
|
166
|
-
STATE_JSON="${TMP2}/.cleargate/sprint-runs/${SPRINT_ID}/state.json"
|
|
167
|
-
|
|
168
|
-
EXIT_CODE=0
|
|
169
|
-
CLEARGATE_REPO_ROOT="$TMP2" node "$SCRIPTS_DIR/init_sprint.mjs" \
|
|
170
|
-
"$SPRINT_ID" --stories "STORY-098-01,STORY-098-02,STORY-098-03" 2>/dev/null || EXIT_CODE=$?
|
|
171
|
-
|
|
172
|
-
assert_eq "Sc2: exit code 0" "0" "$EXIT_CODE"
|
|
173
|
-
assert_exists "Sc2: state.json created" "$STATE_JSON"
|
|
174
|
-
|
|
175
|
-
# Verify execution_mode in state.json is v2
|
|
176
|
-
if [ -f "$STATE_JSON" ]; then
|
|
177
|
-
EM="$(node -e "const s=JSON.parse(require('fs').readFileSync('$STATE_JSON','utf8')); console.log(s.execution_mode)")"
|
|
178
|
-
assert_eq "Sc2: state.json execution_mode=v2" "v2" "$EM"
|
|
179
|
-
fi
|
|
180
|
-
|
|
181
|
-
trap - EXIT
|
|
182
|
-
rm -rf "$TMP2"
|
|
183
|
-
|
|
184
|
-
# ---------------------------------------------------------------------------
|
|
185
|
-
echo ""
|
|
186
|
-
echo "=== Scenario 3: v1 init warns but does not block ==="
|
|
187
|
-
# ---------------------------------------------------------------------------
|
|
188
|
-
TMP3="$(mktemp -d)"
|
|
189
|
-
trap 'rm -rf "$TMP3"' EXIT
|
|
190
|
-
|
|
191
|
-
SPRINT_ID="SPRINT-097"
|
|
192
|
-
make_sprint_file "$TMP3" "$SPRINT_ID" "v1" \
|
|
193
|
-
"STORY-097-01" "STORY-097-02" > /dev/null
|
|
194
|
-
|
|
195
|
-
# Only create STORY-097-01, leave 02 missing
|
|
196
|
-
make_story_file "$TMP3" "STORY-097-01"
|
|
197
|
-
|
|
198
|
-
STATE_JSON="${TMP3}/.cleargate/sprint-runs/${SPRINT_ID}/state.json"
|
|
199
|
-
|
|
200
|
-
EXIT_CODE=0
|
|
201
|
-
STDERR_OUT="$(CLEARGATE_REPO_ROOT="$TMP3" node "$SCRIPTS_DIR/init_sprint.mjs" \
|
|
202
|
-
"$SPRINT_ID" --stories "STORY-097-01,STORY-097-02" 2>&1 >/dev/null)" || EXIT_CODE=$?
|
|
203
|
-
|
|
204
|
-
assert_eq "Sc3: exit code 0 (v1 warns but continues)" "0" "$EXIT_CODE"
|
|
205
|
-
assert_exists "Sc3: state.json created despite missing file" "$STATE_JSON"
|
|
206
|
-
assert_contains "Sc3: stderr contains WARN" "WARN" "$STDERR_OUT"
|
|
207
|
-
assert_contains "Sc3: stderr mentions STORY-097-02" "STORY-097-02" "$STDERR_OUT"
|
|
208
|
-
|
|
209
|
-
trap - EXIT
|
|
210
|
-
rm -rf "$TMP3"
|
|
211
|
-
|
|
212
|
-
# ---------------------------------------------------------------------------
|
|
213
|
-
echo ""
|
|
214
|
-
echo "=== Scenario 4: assert_story_files standalone CLI ==="
|
|
215
|
-
# ---------------------------------------------------------------------------
|
|
216
|
-
TMP4="$(mktemp -d)"
|
|
217
|
-
trap 'rm -rf "$TMP4"' EXIT
|
|
218
|
-
|
|
219
|
-
SPRINT_ID="SPRINT-096"
|
|
220
|
-
SPRINT_FILE="$(make_sprint_file "$TMP4" "$SPRINT_ID" "v2" \
|
|
221
|
-
"STORY-096-01" "STORY-096-02")"
|
|
222
|
-
|
|
223
|
-
# Only create STORY-096-01, leave 02 missing
|
|
224
|
-
make_story_file "$TMP4" "STORY-096-01"
|
|
225
|
-
|
|
226
|
-
# Run standalone assert_story_files.mjs — should exit 1 with missing list
|
|
227
|
-
STDERR_OUT=""
|
|
228
|
-
EXIT_CODE=0
|
|
229
|
-
STDERR_OUT="$(CLEARGATE_REPO_ROOT="$TMP4" node "$SCRIPTS_DIR/assert_story_files.mjs" \
|
|
230
|
-
"$SPRINT_FILE" 2>&1 >/dev/null)" || EXIT_CODE=$?
|
|
231
|
-
|
|
232
|
-
assert_eq "Sc4: standalone exits non-zero when missing" "1" "$EXIT_CODE"
|
|
233
|
-
assert_contains "Sc4: stderr lists STORY-096-02 as missing" "STORY-096-02" "$STDERR_OUT"
|
|
234
|
-
|
|
235
|
-
# Now add the missing story file and re-run — should exit 0
|
|
236
|
-
make_story_file "$TMP4" "STORY-096-02"
|
|
237
|
-
|
|
238
|
-
EXIT_CODE=0
|
|
239
|
-
STDOUT_OUT="$(CLEARGATE_REPO_ROOT="$TMP4" node "$SCRIPTS_DIR/assert_story_files.mjs" \
|
|
240
|
-
"$SPRINT_FILE" 2>/dev/null)" || EXIT_CODE=$?
|
|
241
|
-
|
|
242
|
-
assert_eq "Sc4: standalone exits 0 when all present" "0" "$EXIT_CODE"
|
|
243
|
-
assert_contains "Sc4: stdout confirms all present" "OK:" "$STDOUT_OUT"
|
|
244
|
-
|
|
245
|
-
trap - EXIT
|
|
246
|
-
rm -rf "$TMP4"
|
|
247
|
-
|
|
248
|
-
# ---------------------------------------------------------------------------
|
|
249
|
-
echo ""
|
|
250
|
-
echo "=== Summary ==="
|
|
251
|
-
echo "Passed: $PASS"
|
|
252
|
-
echo "Failed: $FAIL"
|
|
253
|
-
if [ ${#ERRORS[@]} -gt 0 ]; then
|
|
254
|
-
echo "Failing scenarios:"
|
|
255
|
-
for e in "${ERRORS[@]}"; do
|
|
256
|
-
echo " - $e"
|
|
257
|
-
done
|
|
258
|
-
exit 1
|
|
259
|
-
fi
|
|
260
|
-
echo "All tests passed."
|
|
261
|
-
exit 0
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# test_file_surface.sh — Gherkin-style tests for file_surface_diff.sh
|
|
3
|
-
# Tests all 4 scenarios from STORY-014-01 §2.1
|
|
4
|
-
#
|
|
5
|
-
# Usage: bash .cleargate/scripts/test/test_file_surface.sh
|
|
6
|
-
# Exit: 0 if all pass, 1 if any fail
|
|
7
|
-
|
|
8
|
-
set -euo pipefail
|
|
9
|
-
|
|
10
|
-
# Navigate up 3 levels: test/ -> scripts/ -> .cleargate/ -> repo-root/
|
|
11
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
12
|
-
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
13
|
-
SCRIPT="${REPO_ROOT}/.cleargate/scripts/file_surface_diff.sh"
|
|
14
|
-
PASS=0
|
|
15
|
-
FAIL=0
|
|
16
|
-
TOTAL=0
|
|
17
|
-
|
|
18
|
-
pass() { echo " PASS: $1"; PASS=$((PASS+1)); TOTAL=$((TOTAL+1)); }
|
|
19
|
-
fail() { echo " FAIL: $1 --- $2"; FAIL=$((FAIL+1)); TOTAL=$((TOTAL+1)); }
|
|
20
|
-
|
|
21
|
-
echo "REPO_ROOT: ${REPO_ROOT}"
|
|
22
|
-
echo "SCRIPT: ${SCRIPT}"
|
|
23
|
-
if [[ ! -f "${SCRIPT}" ]]; then
|
|
24
|
-
echo "ERROR: file_surface_diff.sh not found at ${SCRIPT}"
|
|
25
|
-
exit 1
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
# ============================================================================
|
|
29
|
-
# Setup helpers
|
|
30
|
-
# ============================================================================
|
|
31
|
-
|
|
32
|
-
setup_git_repo() {
|
|
33
|
-
local dir="$1"
|
|
34
|
-
git init -q "${dir}"
|
|
35
|
-
git -C "${dir}" config user.email "test@test.com"
|
|
36
|
-
git -C "${dir}" config user.name "Test"
|
|
37
|
-
git -C "${dir}" commit -q --allow-empty -m "init"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
create_story_file() {
|
|
41
|
-
local dir="$1"
|
|
42
|
-
shift
|
|
43
|
-
# remaining args are file paths to declare in §3.1
|
|
44
|
-
mkdir -p "${dir}/.cleargate/delivery/pending-sync"
|
|
45
|
-
local story="${dir}/.cleargate/delivery/pending-sync/STORY-014-01_Test.md"
|
|
46
|
-
{
|
|
47
|
-
echo "---"
|
|
48
|
-
echo "story_id: STORY-014-01"
|
|
49
|
-
echo "---"
|
|
50
|
-
echo ""
|
|
51
|
-
echo "# Test Story"
|
|
52
|
-
echo ""
|
|
53
|
-
echo "## 3. Implementation Guide"
|
|
54
|
-
echo ""
|
|
55
|
-
echo "### 3.1 Context & Files"
|
|
56
|
-
echo ""
|
|
57
|
-
echo "| Item | Value |"
|
|
58
|
-
echo "|---|---|"
|
|
59
|
-
for f in "$@"; do
|
|
60
|
-
echo "| New script | \`${f}\` |"
|
|
61
|
-
done
|
|
62
|
-
echo ""
|
|
63
|
-
echo "### 3.2 Technical Logic"
|
|
64
|
-
echo "test"
|
|
65
|
-
} > "${story}"
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
create_sprint_state() {
|
|
69
|
-
local dir="$1"
|
|
70
|
-
local mode="${2:-v2}"
|
|
71
|
-
mkdir -p "${dir}/.cleargate/sprint-runs/SPRINT-10"
|
|
72
|
-
echo "SPRINT-10" > "${dir}/.cleargate/sprint-runs/.active"
|
|
73
|
-
echo "{\"execution_mode\":\"${mode}\",\"stories\":{\"STORY-014-01\":{\"state\":\"In Progress\",\"updated_at\":\"2026-04-21T12:00:00Z\"}}}" > "${dir}/.cleargate/sprint-runs/SPRINT-10/state.json"
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
# ============================================================================
|
|
77
|
-
# Scenario 1: Gate catches off-surface edit
|
|
78
|
-
# ============================================================================
|
|
79
|
-
|
|
80
|
-
echo ""
|
|
81
|
-
echo "Scenario 1: Gate catches off-surface edit"
|
|
82
|
-
|
|
83
|
-
TMPDIR1="$(mktemp -d)"
|
|
84
|
-
setup_git_repo "${TMPDIR1}"
|
|
85
|
-
create_story_file "${TMPDIR1}" "hello.mjs" "README.md"
|
|
86
|
-
create_sprint_state "${TMPDIR1}" "v2"
|
|
87
|
-
|
|
88
|
-
touch "${TMPDIR1}/hello.mjs" "${TMPDIR1}/README.md" "${TMPDIR1}/unrelated.txt"
|
|
89
|
-
git -C "${TMPDIR1}" add hello.mjs README.md unrelated.txt
|
|
90
|
-
|
|
91
|
-
EXIT_CODE=0
|
|
92
|
-
STDERR_OUT="$(CLEARGATE_REPO_ROOT="${TMPDIR1}" bash "${SCRIPT}" 2>&1 >/dev/null)" || EXIT_CODE=$?
|
|
93
|
-
|
|
94
|
-
if [[ "${EXIT_CODE}" -ne 0 ]]; then
|
|
95
|
-
pass "exit code is non-zero"
|
|
96
|
-
else
|
|
97
|
-
fail "exit code is non-zero" "got exit 0"
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
if echo "${STDERR_OUT}" | grep -q "unrelated.txt"; then
|
|
101
|
-
pass "stderr lists unrelated.txt as off-surface"
|
|
102
|
-
else
|
|
103
|
-
fail "stderr lists unrelated.txt as off-surface" "stderr was: ${STDERR_OUT}"
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
rm -rf "${TMPDIR1}"
|
|
107
|
-
|
|
108
|
-
# ============================================================================
|
|
109
|
-
# Scenario 2: Gate passes when staged files match surface
|
|
110
|
-
# ============================================================================
|
|
111
|
-
|
|
112
|
-
echo ""
|
|
113
|
-
echo "Scenario 2: Gate passes when staged files match surface"
|
|
114
|
-
|
|
115
|
-
TMPDIR2="$(mktemp -d)"
|
|
116
|
-
setup_git_repo "${TMPDIR2}"
|
|
117
|
-
create_story_file "${TMPDIR2}" "hello.mjs" "README.md"
|
|
118
|
-
create_sprint_state "${TMPDIR2}" "v2"
|
|
119
|
-
|
|
120
|
-
touch "${TMPDIR2}/hello.mjs" "${TMPDIR2}/README.md"
|
|
121
|
-
git -C "${TMPDIR2}" add hello.mjs README.md
|
|
122
|
-
|
|
123
|
-
EXIT_CODE=0
|
|
124
|
-
CLEARGATE_REPO_ROOT="${TMPDIR2}" bash "${SCRIPT}" 2>/dev/null || EXIT_CODE=$?
|
|
125
|
-
|
|
126
|
-
if [[ "${EXIT_CODE}" -eq 0 ]]; then
|
|
127
|
-
pass "exit code is 0"
|
|
128
|
-
else
|
|
129
|
-
fail "exit code is 0" "got exit ${EXIT_CODE}"
|
|
130
|
-
fi
|
|
131
|
-
|
|
132
|
-
rm -rf "${TMPDIR2}"
|
|
133
|
-
|
|
134
|
-
# ============================================================================
|
|
135
|
-
# Scenario 3: Whitelist admits generated files
|
|
136
|
-
# ============================================================================
|
|
137
|
-
|
|
138
|
-
echo ""
|
|
139
|
-
echo "Scenario 3: Whitelist admits generated files"
|
|
140
|
-
|
|
141
|
-
TMPDIR3="$(mktemp -d)"
|
|
142
|
-
setup_git_repo "${TMPDIR3}"
|
|
143
|
-
create_story_file "${TMPDIR3}" "hello.mjs"
|
|
144
|
-
create_sprint_state "${TMPDIR3}" "v2"
|
|
145
|
-
|
|
146
|
-
mkdir -p "${TMPDIR3}/.cleargate/scripts"
|
|
147
|
-
{
|
|
148
|
-
echo "cleargate-planning/MANIFEST.json"
|
|
149
|
-
echo ".cleargate/hook-log/*"
|
|
150
|
-
} > "${TMPDIR3}/.cleargate/scripts/surface-whitelist.txt"
|
|
151
|
-
|
|
152
|
-
touch "${TMPDIR3}/hello.mjs"
|
|
153
|
-
mkdir -p "${TMPDIR3}/cleargate-planning"
|
|
154
|
-
touch "${TMPDIR3}/cleargate-planning/MANIFEST.json"
|
|
155
|
-
git -C "${TMPDIR3}" add hello.mjs cleargate-planning/MANIFEST.json
|
|
156
|
-
|
|
157
|
-
EXIT_CODE=0
|
|
158
|
-
CLEARGATE_REPO_ROOT="${TMPDIR3}" bash "${SCRIPT}" 2>/dev/null || EXIT_CODE=$?
|
|
159
|
-
|
|
160
|
-
if [[ "${EXIT_CODE}" -eq 0 ]]; then
|
|
161
|
-
pass "MANIFEST.json not flagged (whitelisted)"
|
|
162
|
-
else
|
|
163
|
-
fail "MANIFEST.json not flagged (whitelisted)" "got exit ${EXIT_CODE}"
|
|
164
|
-
fi
|
|
165
|
-
|
|
166
|
-
rm -rf "${TMPDIR3}"
|
|
167
|
-
|
|
168
|
-
# ============================================================================
|
|
169
|
-
# Scenario 4: v1 mode is advisory
|
|
170
|
-
# ============================================================================
|
|
171
|
-
|
|
172
|
-
echo ""
|
|
173
|
-
echo "Scenario 4: v1 mode is advisory"
|
|
174
|
-
|
|
175
|
-
TMPDIR4="$(mktemp -d)"
|
|
176
|
-
setup_git_repo "${TMPDIR4}"
|
|
177
|
-
create_story_file "${TMPDIR4}" "hello.mjs"
|
|
178
|
-
create_sprint_state "${TMPDIR4}" "v1"
|
|
179
|
-
|
|
180
|
-
touch "${TMPDIR4}/hello.mjs" "${TMPDIR4}/unrelated.txt"
|
|
181
|
-
git -C "${TMPDIR4}" add hello.mjs unrelated.txt
|
|
182
|
-
|
|
183
|
-
EXIT_CODE=0
|
|
184
|
-
STDERR_OUT="$(CLEARGATE_REPO_ROOT="${TMPDIR4}" bash "${SCRIPT}" 2>&1 >/dev/null)" || EXIT_CODE=$?
|
|
185
|
-
|
|
186
|
-
if [[ "${EXIT_CODE}" -eq 0 ]]; then
|
|
187
|
-
pass "v1 mode exits 0 (advisory)"
|
|
188
|
-
else
|
|
189
|
-
fail "v1 mode exits 0" "got exit ${EXIT_CODE}"
|
|
190
|
-
fi
|
|
191
|
-
|
|
192
|
-
if echo "${STDERR_OUT}" | grep -qi "warning"; then
|
|
193
|
-
pass "v1 mode prints warning"
|
|
194
|
-
else
|
|
195
|
-
fail "v1 mode prints warning" "stderr was: ${STDERR_OUT}"
|
|
196
|
-
fi
|
|
197
|
-
|
|
198
|
-
rm -rf "${TMPDIR4}"
|
|
199
|
-
|
|
200
|
-
# ============================================================================
|
|
201
|
-
# Summary
|
|
202
|
-
# ============================================================================
|
|
203
|
-
|
|
204
|
-
echo ""
|
|
205
|
-
echo "Results: ${PASS}/${TOTAL} passed, ${FAIL} failed"
|
|
206
|
-
|
|
207
|
-
if [[ "${FAIL}" -gt 0 ]]; then
|
|
208
|
-
exit 1
|
|
209
|
-
fi
|
|
210
|
-
exit 0
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# test_flashcard_gate.sh — STORY-013-06: Immediate Flashcard Hard-Gate
|
|
3
|
-
# Gherkin scenario: "Gate blocks next worktree creation until flashcards processed"
|
|
4
|
-
#
|
|
5
|
-
# Strategy: grep-based. Creates a synthetic dev-report fixture with
|
|
6
|
-
# flashcards_flagged, simulates a mock worktree-creation step, and asserts
|
|
7
|
-
# the gate contract documented in protocol §18 and the agent output-shape
|
|
8
|
-
# blocks in developer.md + qa.md.
|
|
9
|
-
#
|
|
10
|
-
# Usage: bash .cleargate/scripts/test/test_flashcard_gate.sh
|
|
11
|
-
# Exit: 0 if all assertions pass, 1 on first failure.
|
|
12
|
-
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
REPO_ROOT="${CLEARGATE_REPO_ROOT:-$(cd "$(dirname "$0")/../../.." && pwd)}"
|
|
16
|
-
PASS=0
|
|
17
|
-
FAIL=0
|
|
18
|
-
|
|
19
|
-
pass() { echo "PASS: $1"; PASS=$((PASS + 1)); }
|
|
20
|
-
fail() { echo "FAIL: $1"; FAIL=$((FAIL + 1)); }
|
|
21
|
-
|
|
22
|
-
# ---------------------------------------------------------------------------
|
|
23
|
-
# Scenario: Gate blocks next worktree creation until flashcards processed
|
|
24
|
-
# ---------------------------------------------------------------------------
|
|
25
|
-
# §2.1 Gherkin from STORY-013-06:
|
|
26
|
-
# Given STORY-014-05 has just merged into sprint/S-XX
|
|
27
|
-
# And STORY-014-05-dev.md has flashcards_flagged: [...]
|
|
28
|
-
# When the orchestrator attempts to create .worktrees/STORY-014-06/
|
|
29
|
-
# Then the gate presents each flagged flashcard to the user for approval
|
|
30
|
-
# And upon approval each card is appended to .cleargate/FLASHCARD.md
|
|
31
|
-
# And only then does worktree creation proceed
|
|
32
|
-
#
|
|
33
|
-
# This script validates the contract (protocol §18 + output-shape fields)
|
|
34
|
-
# that makes the scenario enforceable. The gate logic itself is orchestrator-
|
|
35
|
-
# out-of-band (v1: informational; v2: mandatory). The test therefore checks:
|
|
36
|
-
# (a) developer.md output-shape contains flashcards_flagged field
|
|
37
|
-
# (b) qa.md output-shape contains flashcards_flagged field
|
|
38
|
-
# (c) protocol.md §18 exists with the correct heading
|
|
39
|
-
# (d) §18 specifies the approve/reject processing rule
|
|
40
|
-
# (e) §18 specifies the worktree creation gate
|
|
41
|
-
# (f) live vs mirror diff is empty for all three files
|
|
42
|
-
|
|
43
|
-
DEV_MD="$REPO_ROOT/.claude/agents/developer.md"
|
|
44
|
-
QA_MD="$REPO_ROOT/.claude/agents/qa.md"
|
|
45
|
-
PROTOCOL_MD="$REPO_ROOT/.cleargate/knowledge/cleargate-protocol.md"
|
|
46
|
-
|
|
47
|
-
PLANNING_DEV_MD="$REPO_ROOT/cleargate-planning/.claude/agents/developer.md"
|
|
48
|
-
PLANNING_QA_MD="$REPO_ROOT/cleargate-planning/.claude/agents/qa.md"
|
|
49
|
-
PLANNING_PROTOCOL_MD="$REPO_ROOT/cleargate-planning/.cleargate/knowledge/cleargate-protocol.md"
|
|
50
|
-
|
|
51
|
-
# (a) developer.md has flashcards_flagged in output-shape block
|
|
52
|
-
if grep -q "flashcards_flagged:" "$DEV_MD"; then
|
|
53
|
-
pass "developer.md output-shape contains flashcards_flagged field"
|
|
54
|
-
else
|
|
55
|
-
fail "developer.md missing flashcards_flagged field in output-shape"
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
# (b) qa.md has flashcards_flagged in output-shape block
|
|
59
|
-
if grep -q "flashcards_flagged:" "$QA_MD"; then
|
|
60
|
-
pass "qa.md output-shape contains flashcards_flagged field"
|
|
61
|
-
else
|
|
62
|
-
fail "qa.md missing flashcards_flagged field in output-shape"
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
# (c) protocol.md §18 heading exists
|
|
66
|
-
if grep -q "^## 18. Immediate Flashcard Gate (v2)" "$PROTOCOL_MD"; then
|
|
67
|
-
pass "protocol.md contains ## 18. Immediate Flashcard Gate (v2)"
|
|
68
|
-
else
|
|
69
|
-
fail "protocol.md missing ## 18. Immediate Flashcard Gate (v2)"
|
|
70
|
-
fi
|
|
71
|
-
|
|
72
|
-
# (d) §18 specifies approve + reject processing
|
|
73
|
-
if grep -q "Approve" "$PROTOCOL_MD" && grep -q "Reject" "$PROTOCOL_MD"; then
|
|
74
|
-
pass "protocol §18 documents Approve/Reject processing rule"
|
|
75
|
-
else
|
|
76
|
-
fail "protocol §18 missing Approve/Reject processing rule"
|
|
77
|
-
fi
|
|
78
|
-
|
|
79
|
-
# (e) §18 specifies the worktree creation gate
|
|
80
|
-
if grep -q "Worktree creation gate\|worktree creation gate\|MUST NOT.*worktree\|worktree.*MUST NOT" "$PROTOCOL_MD"; then
|
|
81
|
-
pass "protocol §18 documents worktree creation gate"
|
|
82
|
-
else
|
|
83
|
-
fail "protocol §18 missing worktree creation gate rule"
|
|
84
|
-
fi
|
|
85
|
-
|
|
86
|
-
# (f) qa.md says QA list is additive to Developer's
|
|
87
|
-
if grep -q "additive" "$QA_MD"; then
|
|
88
|
-
pass "qa.md notes that flashcards_flagged list is additive to Developer's"
|
|
89
|
-
else
|
|
90
|
-
fail "qa.md missing note that flashcards_flagged is additive"
|
|
91
|
-
fi
|
|
92
|
-
|
|
93
|
-
# (g) developer.md references protocol §18
|
|
94
|
-
if grep -q "protocol §18\|§18" "$DEV_MD"; then
|
|
95
|
-
pass "developer.md references protocol §18"
|
|
96
|
-
else
|
|
97
|
-
fail "developer.md does not reference protocol §18"
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
# (h) qa.md references protocol §18
|
|
101
|
-
if grep -q "protocol §18\|§18" "$QA_MD"; then
|
|
102
|
-
pass "qa.md references protocol §18"
|
|
103
|
-
else
|
|
104
|
-
fail "qa.md does not reference protocol §18"
|
|
105
|
-
fi
|
|
106
|
-
|
|
107
|
-
# (i) three-surface diff: live developer.md vs mirror
|
|
108
|
-
if diff -q "$DEV_MD" "$PLANNING_DEV_MD" > /dev/null 2>&1; then
|
|
109
|
-
pass "developer.md live vs mirror diff is empty"
|
|
110
|
-
else
|
|
111
|
-
fail "developer.md live vs mirror diff is NOT empty"
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
# (j) three-surface diff: live qa.md vs mirror
|
|
115
|
-
if diff -q "$QA_MD" "$PLANNING_QA_MD" > /dev/null 2>&1; then
|
|
116
|
-
pass "qa.md live vs mirror diff is empty"
|
|
117
|
-
else
|
|
118
|
-
fail "qa.md live vs mirror diff is NOT empty"
|
|
119
|
-
fi
|
|
120
|
-
|
|
121
|
-
# (k) three-surface diff: live protocol.md vs mirror
|
|
122
|
-
if diff -q "$PROTOCOL_MD" "$PLANNING_PROTOCOL_MD" > /dev/null 2>&1; then
|
|
123
|
-
pass "cleargate-protocol.md live vs mirror diff is empty"
|
|
124
|
-
else
|
|
125
|
-
fail "cleargate-protocol.md live vs mirror diff is NOT empty"
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
# (l) synthetic fixture: dev report with flashcards_flagged triggers gate
|
|
129
|
-
# Simulate: write a temp dev report with flashcards_flagged, grep for it
|
|
130
|
-
TMPDIR_FIXTURE="$(mktemp -d)"
|
|
131
|
-
trap 'rm -rf "$TMPDIR_FIXTURE"' EXIT
|
|
132
|
-
|
|
133
|
-
cat > "$TMPDIR_FIXTURE/STORY-014-05-dev.md" << 'FIXTURE'
|
|
134
|
-
STORY: STORY-014-05
|
|
135
|
-
STATUS: done
|
|
136
|
-
COMMIT: abc1234
|
|
137
|
-
TYPECHECK: pass
|
|
138
|
-
TESTS: 5 passed, 0 failed
|
|
139
|
-
FILES_CHANGED: src/foo.ts
|
|
140
|
-
NOTES: all green
|
|
141
|
-
flashcards_flagged:
|
|
142
|
-
- "2026-04-22 · #test-harness · vitest fake-timers conflict with worker.spawn"
|
|
143
|
-
FIXTURE
|
|
144
|
-
|
|
145
|
-
# Assert the fixture has the flashcard entry
|
|
146
|
-
if grep -q "flashcards_flagged:" "$TMPDIR_FIXTURE/STORY-014-05-dev.md"; then
|
|
147
|
-
pass "synthetic dev-report fixture contains flashcards_flagged field"
|
|
148
|
-
else
|
|
149
|
-
fail "synthetic dev-report fixture missing flashcards_flagged field"
|
|
150
|
-
fi
|
|
151
|
-
|
|
152
|
-
# Assert extraction of the flagged card matches the FLASHCARD.md format
|
|
153
|
-
EXTRACTED=$(grep -A1 "flashcards_flagged:" "$TMPDIR_FIXTURE/STORY-014-05-dev.md" | tail -1 | sed 's/^[[:space:]]*- "//' | sed 's/"$//')
|
|
154
|
-
if echo "$EXTRACTED" | grep -qE "^[0-9]{4}-[0-9]{2}-[0-9]{2} · #[a-z-]+ · .+"; then
|
|
155
|
-
pass "extracted flashcard matches YYYY-MM-DD · #tag · lesson format"
|
|
156
|
-
else
|
|
157
|
-
fail "extracted flashcard does NOT match expected format: '$EXTRACTED'"
|
|
158
|
-
fi
|
|
159
|
-
|
|
160
|
-
# Mock worktree guard: confirm the gate would block by checking the field is non-empty
|
|
161
|
-
FLAGGED_COUNT=$(grep -c " - " "$TMPDIR_FIXTURE/STORY-014-05-dev.md" || true)
|
|
162
|
-
if [ "$FLAGGED_COUNT" -gt 0 ]; then
|
|
163
|
-
pass "gate detects non-empty flashcards_flagged — worktree creation would be blocked"
|
|
164
|
-
else
|
|
165
|
-
fail "gate failed to detect non-empty flashcards_flagged list"
|
|
166
|
-
fi
|
|
167
|
-
|
|
168
|
-
# Mock approval: append to a temp FLASHCARD.md and confirm it was written
|
|
169
|
-
TEMP_FLASHCARD="$TMPDIR_FIXTURE/FLASHCARD.md"
|
|
170
|
-
echo "# ClearGate Flashcards" > "$TEMP_FLASHCARD"
|
|
171
|
-
echo "" >> "$TEMP_FLASHCARD"
|
|
172
|
-
echo "$EXTRACTED" >> "$TEMP_FLASHCARD"
|
|
173
|
-
|
|
174
|
-
if grep -q "vitest fake-timers conflict" "$TEMP_FLASHCARD"; then
|
|
175
|
-
pass "approved flashcard appended to FLASHCARD.md mock"
|
|
176
|
-
else
|
|
177
|
-
fail "approved flashcard NOT found in FLASHCARD.md mock"
|
|
178
|
-
fi
|
|
179
|
-
|
|
180
|
-
# ---------------------------------------------------------------------------
|
|
181
|
-
# Summary
|
|
182
|
-
# ---------------------------------------------------------------------------
|
|
183
|
-
TOTAL=$((PASS + FAIL))
|
|
184
|
-
echo ""
|
|
185
|
-
echo "Results: $PASS/$TOTAL passed"
|
|
186
|
-
|
|
187
|
-
if [ "$FAIL" -gt 0 ]; then
|
|
188
|
-
exit 1
|
|
189
|
-
fi
|
|
190
|
-
exit 0
|