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
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cr078_init.test.sh — CR-078 verification harness.
|
|
3
|
+
#
|
|
4
|
+
# Verifies F1 (.active sentinel write) and F2 (SDR lane audit ingest) are
|
|
5
|
+
# correctly implemented in init_sprint.mjs.
|
|
6
|
+
#
|
|
7
|
+
# All assertions run in FULL ISOLATION — mktemp -d scratch project dirs with
|
|
8
|
+
# their own .cleargate/sprint-runs/ trees. The REAL repo .active is NEVER touched.
|
|
9
|
+
# Safety invariant: after this harness exits, cat <repo>/.cleargate/sprint-runs/.active
|
|
10
|
+
# MUST still read SPRINT-34 (the running sprint).
|
|
11
|
+
#
|
|
12
|
+
# Assertions:
|
|
13
|
+
# 1. .active write: init a scratch SPRINT-99 → cat <temp>/.active == SPRINT-99
|
|
14
|
+
# 2. WARN on differing prior: seed .active=SPRINT-50, init SPRINT-99 →
|
|
15
|
+
# stderr contains WARN, .active becomes SPRINT-99
|
|
16
|
+
# 3. Lane ingest via waves.json: seed lane_assignments marking one story fast →
|
|
17
|
+
# state.json lane==fast + lane_assigned_by==sdr-lane-audit; undeclared story stays standard
|
|
18
|
+
# 4. Lane ingest fallback via §2.4: no waves.json but Sprint Plan with §2.4 Lane Audit
|
|
19
|
+
# marking a story fast → same result
|
|
20
|
+
# 5. Regression: grep -c '\.active' init_sprint.mjs ≥ 1 (was 0 before CR-078)
|
|
21
|
+
#
|
|
22
|
+
# Exit 0 = PASS (all assertions pass); exit 1 = one or more FAIL.
|
|
23
|
+
#
|
|
24
|
+
# Harness self-cleans (trap EXIT removes temp dirs). NEVER touches the real repo .active.
|
|
25
|
+
# macOS bash 3.2 portable.
|
|
26
|
+
# FLASHCARD #test-harness #bash 2026-06-04: use CLEARGATE_REPO_ROOT + CLEARGATE_ADVISORY=1
|
|
27
|
+
# to isolate init_sprint.mjs into a scratch tmpdir without real delivery files.
|
|
28
|
+
set -uo pipefail
|
|
29
|
+
|
|
30
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
31
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
32
|
+
INIT_SCRIPT="${REPO_ROOT}/.cleargate/scripts/init_sprint.mjs"
|
|
33
|
+
CONSTANTS_SCRIPT="${REPO_ROOT}/.cleargate/scripts/constants.mjs"
|
|
34
|
+
|
|
35
|
+
PASS=0
|
|
36
|
+
FAIL=0
|
|
37
|
+
|
|
38
|
+
# Track temp dirs for cleanup
|
|
39
|
+
TEMP_DIRS=()
|
|
40
|
+
|
|
41
|
+
pass() {
|
|
42
|
+
echo "PASS: $1"
|
|
43
|
+
PASS=$((PASS + 1))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
fail() {
|
|
47
|
+
echo "FAIL: $1"
|
|
48
|
+
echo " detail: $2"
|
|
49
|
+
FAIL=$((FAIL + 1))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# ── Teardown / trap ───────────────────────────────────────────────────────────
|
|
53
|
+
cleanup() {
|
|
54
|
+
for d in "${TEMP_DIRS[@]+"${TEMP_DIRS[@]}"}"; do
|
|
55
|
+
if [[ -d "${d}" ]]; then
|
|
56
|
+
rm -rf "${d}"
|
|
57
|
+
fi
|
|
58
|
+
done
|
|
59
|
+
}
|
|
60
|
+
trap cleanup EXIT
|
|
61
|
+
|
|
62
|
+
# ── Helper: create a minimal scratch project dir ──────────────────────────────
|
|
63
|
+
# Each scratch dir gets its own .cleargate/sprint-runs/ tree.
|
|
64
|
+
# We seed a minimal constants.mjs symlink so the script can import it.
|
|
65
|
+
make_scratch() {
|
|
66
|
+
local tmpdir
|
|
67
|
+
tmpdir="$(mktemp -d)"
|
|
68
|
+
TEMP_DIRS+=("${tmpdir}")
|
|
69
|
+
# Create the sprint-runs dir
|
|
70
|
+
mkdir -p "${tmpdir}/.cleargate/sprint-runs"
|
|
71
|
+
# Create a minimal scripts dir (symlink to real scripts so import works)
|
|
72
|
+
mkdir -p "${tmpdir}/.cleargate/scripts"
|
|
73
|
+
# Symlink constants.mjs so the import resolves (init_sprint.mjs uses __dirname
|
|
74
|
+
# for the scripts dir, NOT CLEARGATE_REPO_ROOT — so we pass CLEARGATE_REPO_ROOT
|
|
75
|
+
# only for file-path resolution, not for module loading).
|
|
76
|
+
echo "${tmpdir}"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ── Pre-check: init_sprint.mjs must exist ────────────────────────────────────
|
|
80
|
+
if [[ ! -f "${INIT_SCRIPT}" ]]; then
|
|
81
|
+
fail "pre-check" "init_sprint.mjs not found at ${INIT_SCRIPT}"
|
|
82
|
+
echo ""
|
|
83
|
+
echo "cr078_init.test.sh: ${PASS} passed, ${FAIL} failed"
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# ── ASSERTION 5 (regression): grep count for .active references ───────────────
|
|
88
|
+
# Was 0 before CR-078; must be ≥ 1 after.
|
|
89
|
+
ACTIVE_COUNT="$(grep -c '\.active' "${INIT_SCRIPT}" || true)"
|
|
90
|
+
if [[ "${ACTIVE_COUNT}" -ge 1 ]]; then
|
|
91
|
+
pass "5-regression: init_sprint.mjs contains ≥1 .active reference (count=${ACTIVE_COUNT})"
|
|
92
|
+
else
|
|
93
|
+
fail "5-regression: init_sprint.mjs has 0 .active references — F1 not implemented" \
|
|
94
|
+
"grep -c '.active' returned ${ACTIVE_COUNT}"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
98
|
+
# ASSERTION 1: .active write — init SPRINT-99 in scratch dir → .active == SPRINT-99
|
|
99
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
100
|
+
SCRATCH1="$(make_scratch)"
|
|
101
|
+
mkdir -p "${SCRATCH1}/.cleargate/sprint-runs/SPRINT-99"
|
|
102
|
+
|
|
103
|
+
# Run init_sprint.mjs with CLEARGATE_REPO_ROOT pointing to scratch dir.
|
|
104
|
+
# CLEARGATE_ADVISORY=1 bypasses story-file assertion (no delivery/ in scratch dir).
|
|
105
|
+
INIT_STDERR1="$(
|
|
106
|
+
CLEARGATE_REPO_ROOT="${SCRATCH1}" CLEARGATE_ADVISORY=1 \
|
|
107
|
+
node "${INIT_SCRIPT}" SPRINT-99 --stories STORY-99-01 --force 2>&1 >/dev/null
|
|
108
|
+
)"
|
|
109
|
+
INIT_EXIT1=$?
|
|
110
|
+
|
|
111
|
+
ACTIVE_VAL1=""
|
|
112
|
+
if [[ -f "${SCRATCH1}/.cleargate/sprint-runs/.active" ]]; then
|
|
113
|
+
ACTIVE_VAL1="$(cat "${SCRATCH1}/.cleargate/sprint-runs/.active" | tr -d '\n')"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [[ "${ACTIVE_VAL1}" = "SPRINT-99" ]]; then
|
|
117
|
+
pass "1-active-write: .active == SPRINT-99 after init"
|
|
118
|
+
else
|
|
119
|
+
fail "1-active-write: .active not set to SPRINT-99" \
|
|
120
|
+
"got '${ACTIVE_VAL1}'; init exit=${INIT_EXIT1}; stderr: ${INIT_STDERR1}"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
124
|
+
# ASSERTION 2: WARN on differing prior — seed .active=SPRINT-50, init SPRINT-99
|
|
125
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
126
|
+
SCRATCH2="$(make_scratch)"
|
|
127
|
+
mkdir -p "${SCRATCH2}/.cleargate/sprint-runs/SPRINT-99"
|
|
128
|
+
# Pre-seed .active with a different sprint
|
|
129
|
+
printf 'SPRINT-50\n' > "${SCRATCH2}/.cleargate/sprint-runs/.active"
|
|
130
|
+
|
|
131
|
+
INIT_STDERR2="$(
|
|
132
|
+
CLEARGATE_REPO_ROOT="${SCRATCH2}" CLEARGATE_ADVISORY=1 \
|
|
133
|
+
node "${INIT_SCRIPT}" SPRINT-99 --stories STORY-99-01 --force 2>&1 >/dev/null
|
|
134
|
+
)"
|
|
135
|
+
|
|
136
|
+
ACTIVE_VAL2=""
|
|
137
|
+
if [[ -f "${SCRATCH2}/.cleargate/sprint-runs/.active" ]]; then
|
|
138
|
+
ACTIVE_VAL2="$(cat "${SCRATCH2}/.cleargate/sprint-runs/.active" | tr -d '\n')"
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Check .active updated
|
|
142
|
+
if [[ "${ACTIVE_VAL2}" = "SPRINT-99" ]]; then
|
|
143
|
+
pass "2a-warn-prior: .active updated to SPRINT-99 despite prior SPRINT-50"
|
|
144
|
+
else
|
|
145
|
+
fail "2a-warn-prior: .active not updated" \
|
|
146
|
+
"got '${ACTIVE_VAL2}'"
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Check WARN emitted
|
|
150
|
+
if echo "${INIT_STDERR2}" | grep -q "WARN: .active was SPRINT-50"; then
|
|
151
|
+
pass "2b-warn-prior: WARN message emitted on stderr"
|
|
152
|
+
else
|
|
153
|
+
fail "2b-warn-prior: expected WARN about prior .active on stderr" \
|
|
154
|
+
"stderr was: ${INIT_STDERR2}"
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
# ASSERTION 3: Lane ingest via waves.json
|
|
159
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
160
|
+
SCRATCH3="$(make_scratch)"
|
|
161
|
+
mkdir -p "${SCRATCH3}/.cleargate/sprint-runs/SPRINT-99/plans"
|
|
162
|
+
|
|
163
|
+
# Seed waves.json with lane_assignments marking STORY-99-01 as fast
|
|
164
|
+
cat > "${SCRATCH3}/.cleargate/sprint-runs/SPRINT-99/plans/waves.json" <<'EOF'
|
|
165
|
+
{
|
|
166
|
+
"sprint": "SPRINT-99",
|
|
167
|
+
"generated_at": "2026-06-04T00:00:00Z",
|
|
168
|
+
"waves": [
|
|
169
|
+
{
|
|
170
|
+
"wave": "wave1",
|
|
171
|
+
"stories": ["STORY-99-01", "STORY-99-02"],
|
|
172
|
+
"parallel": false,
|
|
173
|
+
"rationale": "test wave"
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"lane_assignments": {
|
|
177
|
+
"STORY-99-01": "fast"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
EOF
|
|
181
|
+
|
|
182
|
+
INIT_STDERR3="$(
|
|
183
|
+
CLEARGATE_REPO_ROOT="${SCRATCH3}" CLEARGATE_ADVISORY=1 \
|
|
184
|
+
node "${INIT_SCRIPT}" SPRINT-99 --stories STORY-99-01,STORY-99-02 --force 2>&1 >/dev/null
|
|
185
|
+
)"
|
|
186
|
+
|
|
187
|
+
STATE3="${SCRATCH3}/.cleargate/sprint-runs/SPRINT-99/state.json"
|
|
188
|
+
if [[ ! -f "${STATE3}" ]]; then
|
|
189
|
+
fail "3-waves-lane: state.json not written" \
|
|
190
|
+
"init stderr: ${INIT_STDERR3}"
|
|
191
|
+
else
|
|
192
|
+
LANE3_01="$(node -e "const s=require('${STATE3}'); process.stdout.write(s.stories['STORY-99-01'].lane)" 2>/dev/null || echo 'ERROR')"
|
|
193
|
+
LANE_BY3_01="$(node -e "const s=require('${STATE3}'); process.stdout.write(s.stories['STORY-99-01'].lane_assigned_by)" 2>/dev/null || echo 'ERROR')"
|
|
194
|
+
LANE3_02="$(node -e "const s=require('${STATE3}'); process.stdout.write(s.stories['STORY-99-02'].lane)" 2>/dev/null || echo 'ERROR')"
|
|
195
|
+
LANE_BY3_02="$(node -e "const s=require('${STATE3}'); process.stdout.write(s.stories['STORY-99-02'].lane_assigned_by)" 2>/dev/null || echo 'ERROR')"
|
|
196
|
+
|
|
197
|
+
if [[ "${LANE3_01}" = "fast" ]]; then
|
|
198
|
+
pass "3a-waves-lane: STORY-99-01 lane==fast (declared in waves.json)"
|
|
199
|
+
else
|
|
200
|
+
fail "3a-waves-lane: STORY-99-01 lane expected 'fast'" \
|
|
201
|
+
"got '${LANE3_01}'"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
if [[ "${LANE_BY3_01}" = "sdr-lane-audit" ]]; then
|
|
205
|
+
pass "3b-waves-lane: STORY-99-01 lane_assigned_by==sdr-lane-audit"
|
|
206
|
+
else
|
|
207
|
+
fail "3b-waves-lane: STORY-99-01 lane_assigned_by expected 'sdr-lane-audit'" \
|
|
208
|
+
"got '${LANE_BY3_01}'"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
if [[ "${LANE3_02}" = "standard" ]]; then
|
|
212
|
+
pass "3c-waves-lane: STORY-99-02 (undeclared) lane==standard"
|
|
213
|
+
else
|
|
214
|
+
fail "3c-waves-lane: STORY-99-02 lane expected 'standard' (undeclared)" \
|
|
215
|
+
"got '${LANE3_02}'"
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
if [[ "${LANE_BY3_02}" = "migration-default" ]]; then
|
|
219
|
+
pass "3d-waves-lane: STORY-99-02 lane_assigned_by==migration-default (undeclared)"
|
|
220
|
+
else
|
|
221
|
+
fail "3d-waves-lane: STORY-99-02 lane_assigned_by expected 'migration-default'" \
|
|
222
|
+
"got '${LANE_BY3_02}'"
|
|
223
|
+
fi
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
227
|
+
# ASSERTION 4: Lane ingest fallback via §2.4 — no waves.json, sprint plan with Lane Audit
|
|
228
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
229
|
+
SCRATCH4="$(make_scratch)"
|
|
230
|
+
mkdir -p "${SCRATCH4}/.cleargate/sprint-runs/SPRINT-99"
|
|
231
|
+
mkdir -p "${SCRATCH4}/.cleargate/delivery/pending-sync"
|
|
232
|
+
|
|
233
|
+
# Create a minimal sprint plan with a §2.4 Lane Audit table (no waves.json)
|
|
234
|
+
cat > "${SCRATCH4}/.cleargate/delivery/pending-sync/SPRINT-99_Test_Sprint.md" <<'EOF'
|
|
235
|
+
---
|
|
236
|
+
status: Active
|
|
237
|
+
approved: true
|
|
238
|
+
---
|
|
239
|
+
# SPRINT-99: Test Sprint
|
|
240
|
+
|
|
241
|
+
## 0. Frontmatter
|
|
242
|
+
- **Sprint Goal:** Test lane ingest fallback
|
|
243
|
+
|
|
244
|
+
## 2. Execution Strategy
|
|
245
|
+
|
|
246
|
+
### 2.4 Lane Audit
|
|
247
|
+
|
|
248
|
+
| Story | Lane | Rationale (≤80 chars) |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| `STORY-99-01` | fast | Isolated fix, no agent surface |
|
|
251
|
+
|
|
252
|
+
### 2.5 ADR-Conflict Flags
|
|
253
|
+
None.
|
|
254
|
+
EOF
|
|
255
|
+
|
|
256
|
+
INIT_STDERR4="$(
|
|
257
|
+
CLEARGATE_REPO_ROOT="${SCRATCH4}" CLEARGATE_ADVISORY=1 \
|
|
258
|
+
node "${INIT_SCRIPT}" SPRINT-99 --stories STORY-99-01,STORY-99-02 --force 2>&1 >/dev/null
|
|
259
|
+
)"
|
|
260
|
+
|
|
261
|
+
STATE4="${SCRATCH4}/.cleargate/sprint-runs/SPRINT-99/state.json"
|
|
262
|
+
if [[ ! -f "${STATE4}" ]]; then
|
|
263
|
+
fail "4-plan-lane: state.json not written" \
|
|
264
|
+
"init stderr: ${INIT_STDERR4}"
|
|
265
|
+
else
|
|
266
|
+
LANE4_01="$(node -e "const s=require('${STATE4}'); process.stdout.write(s.stories['STORY-99-01'].lane)" 2>/dev/null || echo 'ERROR')"
|
|
267
|
+
LANE_BY4_01="$(node -e "const s=require('${STATE4}'); process.stdout.write(s.stories['STORY-99-01'].lane_assigned_by)" 2>/dev/null || echo 'ERROR')"
|
|
268
|
+
LANE4_02="$(node -e "const s=require('${STATE4}'); process.stdout.write(s.stories['STORY-99-02'].lane)" 2>/dev/null || echo 'ERROR')"
|
|
269
|
+
|
|
270
|
+
if [[ "${LANE4_01}" = "fast" ]]; then
|
|
271
|
+
pass "4a-plan-lane: STORY-99-01 lane==fast (declared in §2.4 Lane Audit table)"
|
|
272
|
+
else
|
|
273
|
+
fail "4a-plan-lane: STORY-99-01 lane expected 'fast'" \
|
|
274
|
+
"got '${LANE4_01}'; stderr: ${INIT_STDERR4}"
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
if [[ "${LANE_BY4_01}" = "sdr-lane-audit" ]]; then
|
|
278
|
+
pass "4b-plan-lane: STORY-99-01 lane_assigned_by==sdr-lane-audit"
|
|
279
|
+
else
|
|
280
|
+
fail "4b-plan-lane: STORY-99-01 lane_assigned_by expected 'sdr-lane-audit'" \
|
|
281
|
+
"got '${LANE_BY4_01}'"
|
|
282
|
+
fi
|
|
283
|
+
|
|
284
|
+
if [[ "${LANE4_02}" = "standard" ]]; then
|
|
285
|
+
pass "4c-plan-lane: STORY-99-02 (undeclared) lane==standard"
|
|
286
|
+
else
|
|
287
|
+
fail "4c-plan-lane: STORY-99-02 lane expected 'standard'" \
|
|
288
|
+
"got '${LANE4_02}'"
|
|
289
|
+
fi
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
293
|
+
# SAFETY: Verify the real repo .active is still SPRINT-34
|
|
294
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
295
|
+
REAL_ACTIVE="$(cat "${REPO_ROOT}/.cleargate/sprint-runs/.active" | tr -d '\n')"
|
|
296
|
+
if [[ "${REAL_ACTIVE}" = "SPRINT-34" ]]; then
|
|
297
|
+
pass "safety: real repo .active still == SPRINT-34 (not clobbered)"
|
|
298
|
+
else
|
|
299
|
+
fail "SAFETY VIOLATION: real repo .active clobbered!" \
|
|
300
|
+
"expected SPRINT-34, got '${REAL_ACTIVE}'"
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
304
|
+
echo ""
|
|
305
|
+
echo "cr078_init.test.sh: ${PASS} passed, ${FAIL} failed"
|
|
306
|
+
if [[ "${FAIL}" -gt 0 ]]; then
|
|
307
|
+
exit 1
|
|
308
|
+
fi
|
|
309
|
+
exit 0
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cr079_provision.red.sh — CR-079 QA-Red provision test harness.
|
|
3
|
+
#
|
|
4
|
+
# RED: fails against clean baseline — provision_worktree_config.sh does not yet
|
|
5
|
+
# exist, so the .env is never provisioned into the test worktree, and the
|
|
6
|
+
# stray_env_files scan has no exemption for provisioned config.
|
|
7
|
+
# GREEN: passes after Developer implements CR-079 (provision script created +
|
|
8
|
+
# pre_gate_runner.sh exemption branch + config.yml worktree.provision_config).
|
|
9
|
+
#
|
|
10
|
+
# Assertions (per M1 §5 / CR §4):
|
|
11
|
+
# 1. Provision (symlink): provision script creates .env symlink in worktree
|
|
12
|
+
# pointing to absolute repo-root .env.
|
|
13
|
+
# 2. Scan PASS (exempted): with the provisioned .env present, stray_env_files
|
|
14
|
+
# scan records PASS (provisioned file is exempt, not stray).
|
|
15
|
+
# 3. Negative control: a non-provisioned .env.local in the worktree makes the
|
|
16
|
+
# scan record stray_env_files FAIL (exemption is scoped, not blanket).
|
|
17
|
+
# 4. Teardown: no dangling symlink at repo root; fixture .env cleaned up; no
|
|
18
|
+
# leftover worktree.
|
|
19
|
+
#
|
|
20
|
+
# The harness is self-cleaning even on assertion failure: trap EXIT removes the
|
|
21
|
+
# test worktree, any fixture .env created at repo root, and the test branch.
|
|
22
|
+
#
|
|
23
|
+
# Mirrors: cr077_eviction.red.sh / test_prep_qa_context.sh harness shape.
|
|
24
|
+
# macOS bash 3.2 portable.
|
|
25
|
+
# FLASHCARD #test-harness #bash 2026-06-03: never use `grep -c … || echo 0`
|
|
26
|
+
# (doubles on zero-match). Use grep -q or grep -c … | head -1.
|
|
27
|
+
#
|
|
28
|
+
# Exit 0 = PASS (all assertions pass); exit 1 = one or more FAIL.
|
|
29
|
+
set -uo pipefail
|
|
30
|
+
|
|
31
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
32
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
33
|
+
|
|
34
|
+
PASS=0
|
|
35
|
+
FAIL=0
|
|
36
|
+
|
|
37
|
+
pass() {
|
|
38
|
+
echo "PASS: $1"
|
|
39
|
+
PASS=$((PASS + 1))
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
fail() {
|
|
43
|
+
echo "FAIL: $1"
|
|
44
|
+
echo " detail: $2"
|
|
45
|
+
FAIL=$((FAIL + 1))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# ── Constants ────────────────────────────────────────────────────────────────
|
|
49
|
+
TEST_BRANCH="test/079"
|
|
50
|
+
TEST_WORKTREE="${REPO_ROOT}/.worktrees/TEST-079"
|
|
51
|
+
PROVISION_SCRIPT="${REPO_ROOT}/.cleargate/scripts/provision_worktree_config.sh"
|
|
52
|
+
PRE_GATE_SCRIPT="${REPO_ROOT}/.cleargate/scripts/pre_gate_runner.sh"
|
|
53
|
+
FIXTURE_ENV="${REPO_ROOT}/.env"
|
|
54
|
+
# Report path written by pre_gate_runner.sh arch mode
|
|
55
|
+
SCAN_REPORT="${TEST_WORKTREE}/.cleargate/reports/pre-arch-scan.txt"
|
|
56
|
+
|
|
57
|
+
# Track whether the harness created the fixture .env at repo root
|
|
58
|
+
HARNESS_CREATED_ENV=0
|
|
59
|
+
|
|
60
|
+
# ── Teardown / trap ───────────────────────────────────────────────────────────
|
|
61
|
+
cleanup() {
|
|
62
|
+
# Remove test worktree (force — even if dirty)
|
|
63
|
+
if git -C "${REPO_ROOT}" worktree list 2>/dev/null | grep -q "${TEST_WORKTREE}"; then
|
|
64
|
+
git -C "${REPO_ROOT}" worktree remove --force "${TEST_WORKTREE}" 2>/dev/null || true
|
|
65
|
+
git -C "${REPO_ROOT}" worktree prune 2>/dev/null || true
|
|
66
|
+
fi
|
|
67
|
+
# Remove worktree directory if still present
|
|
68
|
+
if [[ -d "${TEST_WORKTREE}" ]]; then
|
|
69
|
+
rm -rf "${TEST_WORKTREE}"
|
|
70
|
+
fi
|
|
71
|
+
# Remove test branch if it exists
|
|
72
|
+
if git -C "${REPO_ROOT}" branch --list "${TEST_BRANCH}" | grep -q "${TEST_BRANCH}"; then
|
|
73
|
+
git -C "${REPO_ROOT}" branch -D "${TEST_BRANCH}" 2>/dev/null || true
|
|
74
|
+
fi
|
|
75
|
+
# Remove fixture .env only if harness created it and it's still a real file
|
|
76
|
+
if [[ "${HARNESS_CREATED_ENV}" -eq 1 && -f "${FIXTURE_ENV}" && ! -L "${FIXTURE_ENV}" ]]; then
|
|
77
|
+
rm -f "${FIXTURE_ENV}"
|
|
78
|
+
fi
|
|
79
|
+
}
|
|
80
|
+
trap cleanup EXIT
|
|
81
|
+
|
|
82
|
+
# ── Pre-check: fixture .env at repo root ─────────────────────────────────────
|
|
83
|
+
# The repo has no .env (gitignored). Create a fixture so the provision script
|
|
84
|
+
# has a real source file to symlink from.
|
|
85
|
+
if [[ ! -e "${FIXTURE_ENV}" ]]; then
|
|
86
|
+
printf 'CR079_FIXTURE=1\n' > "${FIXTURE_ENV}"
|
|
87
|
+
HARNESS_CREATED_ENV=1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# ── Setup: create test worktree ───────────────────────────────────────────────
|
|
91
|
+
# Clean up any stale worktree/branch from a previous interrupted run.
|
|
92
|
+
if git -C "${REPO_ROOT}" worktree list 2>/dev/null | grep -q "TEST-079"; then
|
|
93
|
+
git -C "${REPO_ROOT}" worktree remove --force "${TEST_WORKTREE}" 2>/dev/null || true
|
|
94
|
+
git -C "${REPO_ROOT}" worktree prune 2>/dev/null || true
|
|
95
|
+
fi
|
|
96
|
+
if [[ -d "${TEST_WORKTREE}" ]]; then
|
|
97
|
+
rm -rf "${TEST_WORKTREE}"
|
|
98
|
+
fi
|
|
99
|
+
if git -C "${REPO_ROOT}" branch --list "${TEST_BRANCH}" | grep -q "${TEST_BRANCH}"; then
|
|
100
|
+
git -C "${REPO_ROOT}" branch -D "${TEST_BRANCH}" 2>/dev/null || true
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
git -C "${REPO_ROOT}" worktree add "${TEST_WORKTREE}" -b "${TEST_BRANCH}" HEAD \
|
|
104
|
+
> /dev/null 2>&1
|
|
105
|
+
if [[ ! -d "${TEST_WORKTREE}" ]]; then
|
|
106
|
+
fail "setup-worktree" "git worktree add failed — ${TEST_WORKTREE} does not exist"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "cr079_provision.red.sh: ${PASS} passed, ${FAIL} failed"
|
|
109
|
+
exit 1
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
113
|
+
# ASSERTION 1: Provision script creates .env symlink in worktree
|
|
114
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
115
|
+
# On the clean baseline: provision_worktree_config.sh does not exist → fails.
|
|
116
|
+
|
|
117
|
+
if [[ ! -f "${PROVISION_SCRIPT}" ]]; then
|
|
118
|
+
fail "provision-script-exists" \
|
|
119
|
+
"provision_worktree_config.sh does not exist at ${PROVISION_SCRIPT}"
|
|
120
|
+
else
|
|
121
|
+
pass "provision-script-exists"
|
|
122
|
+
# Script exists — run it and check the resulting symlink
|
|
123
|
+
bash "${PROVISION_SCRIPT}" "${TEST_WORKTREE}" > /dev/null 2>&1 || true
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if [[ -L "${TEST_WORKTREE}/.env" ]]; then
|
|
127
|
+
SYMLINK_TARGET="$(readlink "${TEST_WORKTREE}/.env")"
|
|
128
|
+
if [[ "${SYMLINK_TARGET}" = "${FIXTURE_ENV}" ]]; then
|
|
129
|
+
pass "provision-symlink-target — readlink resolves to absolute repo-root .env"
|
|
130
|
+
else
|
|
131
|
+
fail "provision-symlink-target" \
|
|
132
|
+
"readlink='${SYMLINK_TARGET}' — expected absolute path '${FIXTURE_ENV}'"
|
|
133
|
+
fi
|
|
134
|
+
else
|
|
135
|
+
# Expected on clean baseline: provision script never ran → no symlink
|
|
136
|
+
fail "provision-symlink-exists" \
|
|
137
|
+
"${TEST_WORKTREE}/.env does not exist (provision script never ran or failed)"
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
141
|
+
# ASSERTION 2: Scan records PASS for provisioned .env (exemption in place)
|
|
142
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
143
|
+
# Pre-condition: the .env must actually be present in the worktree for this
|
|
144
|
+
# assertion to be meaningful. On clean baseline, no .env was provisioned, so
|
|
145
|
+
# the scan trivially PASSes (nothing to flag). This means assertion 2 does NOT
|
|
146
|
+
# fail on the baseline solely due to the missing script — but we need it to
|
|
147
|
+
# FAIL to prove the exemption logic. We therefore MANUALLY place a .env symlink
|
|
148
|
+
# into the worktree here (mirroring what a real provision step would do), then
|
|
149
|
+
# run the scan. On clean baseline the scan will record FAIL because the
|
|
150
|
+
# exemption branch does not exist. After implementation the scan records PASS
|
|
151
|
+
# because the provisioned .env is exempt.
|
|
152
|
+
|
|
153
|
+
# Ensure a .env (symlink) is present in the worktree before running scan.
|
|
154
|
+
# If the provision step (assertion 1) already created it, this is a no-op.
|
|
155
|
+
if [[ ! -L "${TEST_WORKTREE}/.env" && ! -f "${TEST_WORKTREE}/.env" ]]; then
|
|
156
|
+
# Create the symlink manually for this assertion so we can test the scan
|
|
157
|
+
# exemption independently of the provision script.
|
|
158
|
+
ln -s "${FIXTURE_ENV}" "${TEST_WORKTREE}/.env"
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Remove any stale scan report so we get a fresh run.
|
|
162
|
+
rm -f "${SCAN_REPORT}" 2>/dev/null || true
|
|
163
|
+
|
|
164
|
+
# Run pre_gate_runner.sh arch mode with ABSOLUTE worktree path (FLASHCARD
|
|
165
|
+
# #pre-gate #cwd-leak #worktree 2026-06-03: pass absolute path to avoid leak).
|
|
166
|
+
bash "${PRE_GATE_SCRIPT}" arch "${TEST_WORKTREE}" HEAD > /dev/null 2>&1 || true
|
|
167
|
+
|
|
168
|
+
if [[ -f "${SCAN_REPORT}" ]]; then
|
|
169
|
+
if grep -q '^\[PASS\] stray_env_files' "${SCAN_REPORT}"; then
|
|
170
|
+
pass "scan-exemption — stray_env_files PASS for provisioned .env"
|
|
171
|
+
else
|
|
172
|
+
# Expected on clean baseline: no exemption branch → records FAIL on .env
|
|
173
|
+
STRAY_LINE="$(grep 'stray_env_files' "${SCAN_REPORT}" | head -1 || echo '(no stray_env_files line)')"
|
|
174
|
+
fail "scan-exemption — stray_env_files should record PASS for provisioned .env" \
|
|
175
|
+
"report line: ${STRAY_LINE}"
|
|
176
|
+
fi
|
|
177
|
+
else
|
|
178
|
+
fail "scan-report-exists" \
|
|
179
|
+
"pre-arch-scan.txt not written at ${SCAN_REPORT}"
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
183
|
+
# ASSERTION 3: Negative control — .env.local still triggers FAIL
|
|
184
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
185
|
+
# .env.local is in stray_env_files list but NOT in provision_config default.
|
|
186
|
+
# Drop it into the worktree, run a fresh scan, assert stray_env_files FAIL.
|
|
187
|
+
|
|
188
|
+
printf 'NOT_PROVISIONED=1\n' > "${TEST_WORKTREE}/.env.local"
|
|
189
|
+
|
|
190
|
+
# Remove the previous scan report so we get a completely fresh scan.
|
|
191
|
+
rm -f "${SCAN_REPORT}" 2>/dev/null || true
|
|
192
|
+
|
|
193
|
+
bash "${PRE_GATE_SCRIPT}" arch "${TEST_WORKTREE}" HEAD > /dev/null 2>&1 || true
|
|
194
|
+
|
|
195
|
+
if [[ -f "${SCAN_REPORT}" ]]; then
|
|
196
|
+
if grep -q '^\[FAIL\] stray_env_files' "${SCAN_REPORT}"; then
|
|
197
|
+
pass "negative-control — .env.local (non-provisioned) triggers stray_env_files FAIL"
|
|
198
|
+
else
|
|
199
|
+
NEG_LINE="$(grep 'stray_env_files' "${SCAN_REPORT}" | head -1 || echo '(no stray_env_files line)')"
|
|
200
|
+
fail "negative-control — .env.local should trigger stray_env_files FAIL (exemption must be scoped)" \
|
|
201
|
+
"report line: ${NEG_LINE}"
|
|
202
|
+
fi
|
|
203
|
+
else
|
|
204
|
+
fail "negative-control-report-exists" \
|
|
205
|
+
"pre-arch-scan.txt not written at ${SCAN_REPORT} for negative-control scan"
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# Remove the negative-control file so teardown sees a clean worktree
|
|
209
|
+
rm -f "${TEST_WORKTREE}/.env.local"
|
|
210
|
+
|
|
211
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
212
|
+
# ASSERTION 4: Teardown verification
|
|
213
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
214
|
+
# Remove the worktree and verify no dangling symlink at repo root and no
|
|
215
|
+
# leftover fixture .env. The EXIT trap is the safety net; here we verify
|
|
216
|
+
# explicitly so we can record PASS/FAIL before returning.
|
|
217
|
+
|
|
218
|
+
git -C "${REPO_ROOT}" worktree remove --force "${TEST_WORKTREE}" 2>/dev/null || true
|
|
219
|
+
git -C "${REPO_ROOT}" worktree prune 2>/dev/null || true
|
|
220
|
+
if [[ -d "${TEST_WORKTREE}" ]]; then
|
|
221
|
+
rm -rf "${TEST_WORKTREE}"
|
|
222
|
+
fi
|
|
223
|
+
if git -C "${REPO_ROOT}" branch --list "${TEST_BRANCH}" | grep -q "${TEST_BRANCH}"; then
|
|
224
|
+
git -C "${REPO_ROOT}" branch -D "${TEST_BRANCH}" 2>/dev/null || true
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# Assertion: no dangling symlink at repo root (.env symlink lives INSIDE the
|
|
228
|
+
# worktree pointing OUT; removing the worktree removes the symlink).
|
|
229
|
+
if [[ -L "${FIXTURE_ENV}" ]]; then
|
|
230
|
+
fail "teardown-no-dangling-symlink" \
|
|
231
|
+
".env at repo root is a symlink after worktree removal — dangling"
|
|
232
|
+
else
|
|
233
|
+
pass "teardown-no-dangling-symlink — no dangling symlink at repo root"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
# Assertion: worktree is no longer registered
|
|
237
|
+
if git -C "${REPO_ROOT}" worktree list 2>/dev/null | grep -q "TEST-079"; then
|
|
238
|
+
fail "teardown-worktree-removed" \
|
|
239
|
+
".worktrees/TEST-079 still registered in git worktree list"
|
|
240
|
+
else
|
|
241
|
+
pass "teardown-worktree-removed — .worktrees/TEST-079 removed"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# Assertion: fixture .env at repo root is cleaned up (if harness created it)
|
|
245
|
+
if [[ "${HARNESS_CREATED_ENV}" -eq 1 ]]; then
|
|
246
|
+
rm -f "${FIXTURE_ENV}"
|
|
247
|
+
HARNESS_CREATED_ENV=0 # prevent double-remove in trap
|
|
248
|
+
if [[ -e "${FIXTURE_ENV}" ]]; then
|
|
249
|
+
fail "teardown-fixture-env-removed" \
|
|
250
|
+
"fixture .env still present at ${FIXTURE_ENV} after cleanup"
|
|
251
|
+
else
|
|
252
|
+
pass "teardown-fixture-env-removed — fixture .env cleaned up"
|
|
253
|
+
fi
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
257
|
+
echo ""
|
|
258
|
+
echo "cr079_provision.red.sh: ${PASS} passed, ${FAIL} failed"
|
|
259
|
+
if [[ "${FAIL}" -gt 0 ]]; then
|
|
260
|
+
exit 1
|
|
261
|
+
fi
|
|
262
|
+
exit 0
|