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,177 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cr080_wrapper.test.sh — CR-080 verification harness.
|
|
3
|
+
#
|
|
4
|
+
# Verifies F5 (pre_gate_runner.sh realpath-at-entry) and F8 (run_script.sh
|
|
5
|
+
# env pass-through) are correctly implemented.
|
|
6
|
+
#
|
|
7
|
+
# Assertions:
|
|
8
|
+
# F5-1: Relative worktree path — report written to correct location, no ENOENT.
|
|
9
|
+
# F5-2: Absolute worktree path — identical report location, no path doubling.
|
|
10
|
+
# F8-3: CLEARGATE_STATE_FILE exported before wrapper — reaches the child process.
|
|
11
|
+
# F8-4 (optional allowlist): RUN_SCRIPT_ENV_ALLOWLIST=FOO prevents non-listed
|
|
12
|
+
# var from being actively required (documents opt-in behavior).
|
|
13
|
+
#
|
|
14
|
+
# Exit 0 = PASS (all assertions pass); exit 1 = one or more FAIL.
|
|
15
|
+
#
|
|
16
|
+
# Self-cleaning: trap EXIT removes the stub worktree and any tmp files.
|
|
17
|
+
# Mirrors the cr077/cr079 harness shape.
|
|
18
|
+
# macOS bash 3.2 portable.
|
|
19
|
+
# FLASHCARD #test-harness #bash 2026-06-03: use grep -q not grep -c || echo.
|
|
20
|
+
set -uo pipefail
|
|
21
|
+
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
24
|
+
|
|
25
|
+
PASS=0
|
|
26
|
+
FAIL=0
|
|
27
|
+
|
|
28
|
+
pass() {
|
|
29
|
+
echo "PASS: $1"
|
|
30
|
+
PASS=$((PASS + 1))
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
fail() {
|
|
34
|
+
echo "FAIL: $1"
|
|
35
|
+
echo " detail: $2"
|
|
36
|
+
FAIL=$((FAIL + 1))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# ── Constants ────────────────────────────────────────────────────────────────
|
|
40
|
+
TEST_STUB_DIR="${REPO_ROOT}/.worktrees/CR-080-smoke"
|
|
41
|
+
PRE_GATE_SCRIPT="${REPO_ROOT}/.cleargate/scripts/pre_gate_runner.sh"
|
|
42
|
+
RUN_SCRIPT="${REPO_ROOT}/.cleargate/scripts/run_script.sh"
|
|
43
|
+
|
|
44
|
+
# Temp file for F8 env probe
|
|
45
|
+
TMP_STATE_FILE="/tmp/cr080-probe-$$.json"
|
|
46
|
+
|
|
47
|
+
# ── Teardown / trap ───────────────────────────────────────────────────────────
|
|
48
|
+
cleanup() {
|
|
49
|
+
# Remove stub worktree directory
|
|
50
|
+
if [[ -d "${TEST_STUB_DIR}" ]]; then
|
|
51
|
+
rm -rf "${TEST_STUB_DIR}"
|
|
52
|
+
fi
|
|
53
|
+
# Remove tmp files
|
|
54
|
+
rm -f "${TMP_STATE_FILE}" 2>/dev/null || true
|
|
55
|
+
}
|
|
56
|
+
trap cleanup EXIT
|
|
57
|
+
|
|
58
|
+
# ── Pre-checks ───────────────────────────────────────────────────────────────
|
|
59
|
+
if [[ ! -f "${PRE_GATE_SCRIPT}" ]]; then
|
|
60
|
+
fail "pre-check" "pre_gate_runner.sh not found at ${PRE_GATE_SCRIPT}"
|
|
61
|
+
echo ""
|
|
62
|
+
echo "cr080_wrapper.test.sh: ${PASS} passed, ${FAIL} failed"
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
if [[ ! -f "${RUN_SCRIPT}" ]]; then
|
|
67
|
+
fail "pre-check" "run_script.sh not found at ${RUN_SCRIPT}"
|
|
68
|
+
echo ""
|
|
69
|
+
echo "cr080_wrapper.test.sh: ${PASS} passed, ${FAIL} failed"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# ── Setup: create a stub worktree dir with the expected .cleargate structure ──
|
|
74
|
+
# We use a simple stub directory rather than a real git worktree because the
|
|
75
|
+
# pre_gate_runner.sh only requires the directory to exist for path normalization;
|
|
76
|
+
# the typecheck/test/stray checks are skipped when no package.json is present.
|
|
77
|
+
rm -rf "${TEST_STUB_DIR}" 2>/dev/null || true
|
|
78
|
+
mkdir -p "${TEST_STUB_DIR}/.cleargate/reports"
|
|
79
|
+
|
|
80
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
81
|
+
# ASSERTION F5-1: Relative worktree path writes report to correct location
|
|
82
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
# Run from REPO_ROOT with a relative path (.worktrees/CR-080-smoke).
|
|
84
|
+
# The report should land at <absolute-stub-dir>/.cleargate/reports/pre-qa-scan.txt.
|
|
85
|
+
|
|
86
|
+
RELATIVE_PATH=".worktrees/CR-080-smoke"
|
|
87
|
+
# Use qa mode (matches CR §4 verification command); report file = pre-qa-scan.txt.
|
|
88
|
+
# qa mode skips typecheck + test when no package.json is present in the worktree.
|
|
89
|
+
EXPECTED_REPORT="${TEST_STUB_DIR}/.cleargate/reports/pre-qa-scan.txt"
|
|
90
|
+
|
|
91
|
+
# Remove any stale report from a previous run
|
|
92
|
+
rm -f "${EXPECTED_REPORT}" 2>/dev/null || true
|
|
93
|
+
|
|
94
|
+
# Run from repo root with the RELATIVE path (the bug scenario).
|
|
95
|
+
# We use a non-existent branch (sprint/S-99) — pre_gate_runner.sh tolerates it
|
|
96
|
+
# (qa mode skips package.json checks when no package.json exists).
|
|
97
|
+
cd "${REPO_ROOT}"
|
|
98
|
+
bash "${PRE_GATE_SCRIPT}" qa "${RELATIVE_PATH}" "sprint/S-99" > /dev/null 2>&1 || true
|
|
99
|
+
|
|
100
|
+
if [[ -f "${EXPECTED_REPORT}" ]]; then
|
|
101
|
+
pass "F5-1: relative-worktree-path — report written at correct absolute location"
|
|
102
|
+
else
|
|
103
|
+
fail "F5-1: relative-worktree-path — report not found at ${EXPECTED_REPORT}" \
|
|
104
|
+
"expected report at ${EXPECTED_REPORT} after running with relative path ${RELATIVE_PATH}"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
108
|
+
# ASSERTION F5-2: Absolute worktree path writes report to the same location
|
|
109
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
110
|
+
# Run from repo root with ABSOLUTE path — identical report location expected.
|
|
111
|
+
|
|
112
|
+
rm -f "${EXPECTED_REPORT}" 2>/dev/null || true
|
|
113
|
+
|
|
114
|
+
cd "${REPO_ROOT}"
|
|
115
|
+
bash "${PRE_GATE_SCRIPT}" qa "${TEST_STUB_DIR}" "sprint/S-99" > /dev/null 2>&1 || true
|
|
116
|
+
|
|
117
|
+
if [[ -f "${EXPECTED_REPORT}" ]]; then
|
|
118
|
+
pass "F5-2: absolute-worktree-path — report written at correct location"
|
|
119
|
+
else
|
|
120
|
+
fail "F5-2: absolute-worktree-path — report not found at ${EXPECTED_REPORT}" \
|
|
121
|
+
"expected report at ${EXPECTED_REPORT} after running with absolute path ${TEST_STUB_DIR}"
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# Regression: verify no path-doubling (the ENOENT symptom was a doubled path like
|
|
125
|
+
# <worktree>/<worktree>/.cleargate/... — which can't exist). The report is at the
|
|
126
|
+
# expected location = no doubling occurred. Verified implicitly by F5-1 passing
|
|
127
|
+
# from a relative-path invocation (the bug only triggered on relative paths).
|
|
128
|
+
|
|
129
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
130
|
+
# ASSERTION F8-3: CLEARGATE_STATE_FILE exported before wrapper reaches child
|
|
131
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
132
|
+
# Export the var, then run run_script.sh wrapping a node -e that reads it.
|
|
133
|
+
# The child should print the value, not "MISSING".
|
|
134
|
+
|
|
135
|
+
PROBE_RESULT="$(
|
|
136
|
+
export CLEARGATE_STATE_FILE="${TMP_STATE_FILE}"
|
|
137
|
+
bash "${RUN_SCRIPT}" node -e 'process.stdout.write(process.env.CLEARGATE_STATE_FILE || "MISSING")' 2>/dev/null
|
|
138
|
+
)"
|
|
139
|
+
|
|
140
|
+
if [[ "${PROBE_RESULT}" = "${TMP_STATE_FILE}" ]]; then
|
|
141
|
+
pass "F8-3: CLEARGATE_STATE_FILE forwarded to child — got '${PROBE_RESULT}'"
|
|
142
|
+
else
|
|
143
|
+
fail "F8-3: CLEARGATE_STATE_FILE not forwarded to child" \
|
|
144
|
+
"expected '${TMP_STATE_FILE}', got '${PROBE_RESULT}'"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
148
|
+
# ASSERTION F8-4 (optional allowlist): RUN_SCRIPT_ENV_ALLOWLIST is opt-in only
|
|
149
|
+
# ────────────────────────────────────────────────────────────────────────────
|
|
150
|
+
# When RUN_SCRIPT_ENV_ALLOWLIST is set to "FOO", a var NOT in the allowlist
|
|
151
|
+
# (e.g. CLEARGATE_STATE_FILE) should still reach the child because the
|
|
152
|
+
# allowlist is advisory/documentation-only — the current implementation does
|
|
153
|
+
# NOT strip the env (it only populates _allowed_env for future use).
|
|
154
|
+
# This assertion documents that the default pass-through is preserved even
|
|
155
|
+
# when the allowlist var is set: the child still sees CLEARGATE_STATE_FILE.
|
|
156
|
+
|
|
157
|
+
PROBE_ALLOWLIST_RESULT="$(
|
|
158
|
+
export CLEARGATE_STATE_FILE="${TMP_STATE_FILE}"
|
|
159
|
+
export RUN_SCRIPT_ENV_ALLOWLIST="FOO"
|
|
160
|
+
bash "${RUN_SCRIPT}" node -e 'process.stdout.write(process.env.CLEARGATE_STATE_FILE || "MISSING")' 2>/dev/null
|
|
161
|
+
)"
|
|
162
|
+
|
|
163
|
+
if [[ "${PROBE_ALLOWLIST_RESULT}" = "${TMP_STATE_FILE}" ]]; then
|
|
164
|
+
pass "F8-4: allowlist opt-in — full pass-through preserved when RUN_SCRIPT_ENV_ALLOWLIST set"
|
|
165
|
+
else
|
|
166
|
+
fail "F8-4: allowlist opt-in — CLEARGATE_STATE_FILE unexpectedly dropped" \
|
|
167
|
+
"expected '${TMP_STATE_FILE}', got '${PROBE_ALLOWLIST_RESULT}'"
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
171
|
+
echo ""
|
|
172
|
+
echo "cr080_wrapper.test.sh: ${PASS} passed, ${FAIL} failed"
|
|
173
|
+
|
|
174
|
+
if [[ $FAIL -gt 0 ]]; then
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
exit 0
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cr081_qa_red_lint.red.sh — CR-081 QA-Red semantic-fixture lint harness.
|
|
3
|
+
#
|
|
4
|
+
# RED: fails against clean baseline — qa_red_lint.mjs does not yet exist,
|
|
5
|
+
# pre_gate_runner.sh has no qa_red_lint invocation, and qa.md has no
|
|
6
|
+
# red-now-green clause. All six scenarios therefore FAIL.
|
|
7
|
+
# GREEN: passes after Developer implements CR-081 (qa_red_lint.mjs created,
|
|
8
|
+
# pre_gate_runner.sh wired, qa.md red-now-green clause added).
|
|
9
|
+
#
|
|
10
|
+
# Scenarios (per M3 plan CR-081 §test / dispatch §Scenarios):
|
|
11
|
+
# 1. R-enum positive: fixture with out-of-set literal → exit non-zero + R-enum message
|
|
12
|
+
# 2. R-query positive: fixture with duplicate-text queryByText → exit non-zero + R-query message
|
|
13
|
+
# 3. Negative — clean: valid literal + unique query → exit 0 (no false positive)
|
|
14
|
+
# 4. Negative — NON-APPLICABLE (CRITICAL): plain node:test (assert-based, no Pydantic
|
|
15
|
+
# Literal, no queryByText) shaped like CR-082's own close-gate test → exit 0.
|
|
16
|
+
# Proves qa_red_lint won't phantom-flag CR-082's own *.red.node.test.ts when it goes live.
|
|
17
|
+
# 5. Wiring grep: grep -q "qa_red_lint" .cleargate/scripts/pre_gate_runner.sh
|
|
18
|
+
# 6. qa.md red-now-green clause grep
|
|
19
|
+
#
|
|
20
|
+
# Self-cleaning: trap EXIT removes any mktemp fixture dirs.
|
|
21
|
+
# macOS bash 3.2 portable.
|
|
22
|
+
# FLASHCARD #test-harness #bash 2026-06-03: use grep -q (not grep -c || echo 0).
|
|
23
|
+
# FLASHCARD #pre-gate #live-on-merge #qa-red-lint 2026-06-04: Class-3 pre-gate
|
|
24
|
+
# checks MUST exit 0 on non-applicable files (plain node:test, no Pydantic/RTL).
|
|
25
|
+
#
|
|
26
|
+
# Exit 0 = PASS (all scenarios pass); exit non-zero = one or more FAIL.
|
|
27
|
+
set -uo pipefail
|
|
28
|
+
|
|
29
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
30
|
+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
31
|
+
|
|
32
|
+
PASS=0
|
|
33
|
+
FAIL=0
|
|
34
|
+
|
|
35
|
+
pass() {
|
|
36
|
+
echo "PASS: $1"
|
|
37
|
+
PASS=$((PASS + 1))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fail() {
|
|
41
|
+
echo "FAIL: $1"
|
|
42
|
+
echo " detail: $2"
|
|
43
|
+
FAIL=$((FAIL + 1))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# ── Constants ─────────────────────────────────────────────────────────────────
|
|
47
|
+
LINT_SCRIPT="${REPO_ROOT}/.cleargate/scripts/qa_red_lint.mjs"
|
|
48
|
+
PRE_GATE_SCRIPT="${REPO_ROOT}/.cleargate/scripts/pre_gate_runner.sh"
|
|
49
|
+
QA_MD="${REPO_ROOT}/cleargate-planning/.claude/agents/qa.md"
|
|
50
|
+
|
|
51
|
+
# ── Fixture temp dirs — tracked for cleanup ───────────────────────────────────
|
|
52
|
+
FIXTURE_DIR_ENUM=""
|
|
53
|
+
FIXTURE_DIR_QUERY=""
|
|
54
|
+
FIXTURE_DIR_CLEAN=""
|
|
55
|
+
FIXTURE_DIR_NONAPPLICABLE=""
|
|
56
|
+
|
|
57
|
+
cleanup() {
|
|
58
|
+
[[ -n "${FIXTURE_DIR_ENUM}" ]] && rm -rf "${FIXTURE_DIR_ENUM}"
|
|
59
|
+
[[ -n "${FIXTURE_DIR_QUERY}" ]] && rm -rf "${FIXTURE_DIR_QUERY}"
|
|
60
|
+
[[ -n "${FIXTURE_DIR_CLEAN}" ]] && rm -rf "${FIXTURE_DIR_CLEAN}"
|
|
61
|
+
[[ -n "${FIXTURE_DIR_NONAPPLICABLE}" ]] && rm -rf "${FIXTURE_DIR_NONAPPLICABLE}"
|
|
62
|
+
}
|
|
63
|
+
trap cleanup EXIT
|
|
64
|
+
|
|
65
|
+
# ── Pre-check: qa_red_lint.mjs must exist for scenarios 1-4 ──────────────────
|
|
66
|
+
# On clean baseline it does NOT exist → scenarios 1-4 fail with "script absent".
|
|
67
|
+
LINT_PRESENT=0
|
|
68
|
+
if [[ -f "${LINT_SCRIPT}" ]]; then
|
|
69
|
+
LINT_PRESENT=1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
73
|
+
# SCENARIO 1: R-enum positive
|
|
74
|
+
# A fixture with an out-of-set Literal — mirrors DeckSpec(theme="dark") against
|
|
75
|
+
# Literal["technical-dark","business-warm","minimal-light"].
|
|
76
|
+
# We write a .py file with BOTH the Literal declaration AND the bad constructor
|
|
77
|
+
# call statically visible, plus a .ts mirror with a TS string-union + bad prop.
|
|
78
|
+
# Expected: qa_red_lint.mjs exits NON-ZERO and stderr mentions "dark" + R-enum.
|
|
79
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
80
|
+
echo "--- Scenario 1: R-enum positive ---"
|
|
81
|
+
|
|
82
|
+
FIXTURE_DIR_ENUM="$(mktemp -d)"
|
|
83
|
+
|
|
84
|
+
# Python fixture: Literal declaration + out-of-set constructor call
|
|
85
|
+
cat > "${FIXTURE_DIR_ENUM}/deck_spec_fixture.red.node.test.ts" << 'PYEOF'
|
|
86
|
+
# fixture: deck_spec with invalid enum literal
|
|
87
|
+
# Simulates a QA-Red test that constructs a typed model with a bad literal.
|
|
88
|
+
#
|
|
89
|
+
# Pydantic-style Literal declaration (statically visible in this file):
|
|
90
|
+
# theme: Literal["technical-dark", "business-warm", "minimal-light"]
|
|
91
|
+
#
|
|
92
|
+
# Constructor call with out-of-set value (R-enum violation):
|
|
93
|
+
# DeckSpec(theme="dark") # "dark" is NOT in ["technical-dark","business-warm","minimal-light"]
|
|
94
|
+
|
|
95
|
+
from typing import Literal
|
|
96
|
+
from pydantic import BaseModel
|
|
97
|
+
|
|
98
|
+
class DeckSpec(BaseModel):
|
|
99
|
+
theme: Literal["technical-dark", "business-warm", "minimal-light"]
|
|
100
|
+
|
|
101
|
+
# This is the bad fixture line — "dark" is NOT a valid member of the Literal set.
|
|
102
|
+
spec = DeckSpec(theme="dark") # R-enum: "dark" not in Literal set
|
|
103
|
+
PYEOF
|
|
104
|
+
|
|
105
|
+
if [[ "${LINT_PRESENT}" -eq 0 ]]; then
|
|
106
|
+
fail "scenario-1-r-enum-positive" \
|
|
107
|
+
"qa_red_lint.mjs absent at ${LINT_SCRIPT} — cannot run; baseline FAIL as expected (RED)"
|
|
108
|
+
else
|
|
109
|
+
LINT_OUT="$(node "${LINT_SCRIPT}" "${FIXTURE_DIR_ENUM}" 2>&1)" || LINT_EXIT=$?
|
|
110
|
+
LINT_EXIT="${LINT_EXIT:-0}"
|
|
111
|
+
if [[ "${LINT_EXIT}" -ne 0 ]] && echo "${LINT_OUT}" | grep -qi "dark"; then
|
|
112
|
+
pass "scenario-1-r-enum-positive — exit non-zero + R-enum message names 'dark'"
|
|
113
|
+
elif [[ "${LINT_EXIT}" -eq 0 ]]; then
|
|
114
|
+
fail "scenario-1-r-enum-positive" \
|
|
115
|
+
"qa_red_lint.mjs exited 0 (expected non-zero) — R-enum rule not triggered for out-of-set 'dark'"
|
|
116
|
+
else
|
|
117
|
+
fail "scenario-1-r-enum-positive" \
|
|
118
|
+
"qa_red_lint.mjs exited non-zero but stderr did not mention 'dark' — R-enum message missing or wrong. Output: ${LINT_OUT}"
|
|
119
|
+
fi
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
123
|
+
# SCENARIO 2: R-query positive
|
|
124
|
+
# A fixture (.tsx) where 'Connected' appears on TWO render-input rows AND a
|
|
125
|
+
# queryByText('Connected') call targets it.
|
|
126
|
+
# Expected: exit NON-ZERO + R-query message recommends queryAllByText/getByTestId.
|
|
127
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
128
|
+
echo "--- Scenario 2: R-query positive ---"
|
|
129
|
+
|
|
130
|
+
FIXTURE_DIR_QUERY="$(mktemp -d)"
|
|
131
|
+
|
|
132
|
+
cat > "${FIXTURE_DIR_QUERY}/status_table_fixture.red.node.test.ts" << 'QEOF'
|
|
133
|
+
// fixture: status table with duplicate text — R-query violation
|
|
134
|
+
// Both postgres and redis rows have detail: 'Connected', so queryByText('Connected')
|
|
135
|
+
// will throw "Found multiple elements" at runtime.
|
|
136
|
+
|
|
137
|
+
import { render } from '@testing-library/react';
|
|
138
|
+
import StatusTable from '../StatusTable';
|
|
139
|
+
|
|
140
|
+
const rows = [
|
|
141
|
+
{ service: 'postgres', status: 'ok', detail: 'Connected' },
|
|
142
|
+
{ service: 'redis', status: 'ok', detail: 'Connected' }, // duplicate detail text
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
test('shows connected status', () => {
|
|
146
|
+
render(<StatusTable rows={rows} />);
|
|
147
|
+
// R-query violation: 'Connected' appears on >=2 rows in the render input above.
|
|
148
|
+
// queryByText will throw "Found multiple elements with text 'Connected'".
|
|
149
|
+
const el = queryByText('Connected'); // bad — duplicate text, use queryAllByText('Connected')[0]
|
|
150
|
+
expect(el).toBeTruthy();
|
|
151
|
+
});
|
|
152
|
+
QEOF
|
|
153
|
+
|
|
154
|
+
if [[ "${LINT_PRESENT}" -eq 0 ]]; then
|
|
155
|
+
fail "scenario-2-r-query-positive" \
|
|
156
|
+
"qa_red_lint.mjs absent at ${LINT_SCRIPT} — cannot run; baseline FAIL as expected (RED)"
|
|
157
|
+
else
|
|
158
|
+
LINT_OUT2="$(node "${LINT_SCRIPT}" "${FIXTURE_DIR_QUERY}" 2>&1)" || LINT_EXIT2=$?
|
|
159
|
+
LINT_EXIT2="${LINT_EXIT2:-0}"
|
|
160
|
+
if [[ "${LINT_EXIT2}" -ne 0 ]] && \
|
|
161
|
+
(echo "${LINT_OUT2}" | grep -qiE "queryAllByText|getByTestId|R-query"); then
|
|
162
|
+
pass "scenario-2-r-query-positive — exit non-zero + R-query recommendation present"
|
|
163
|
+
elif [[ "${LINT_EXIT2}" -eq 0 ]]; then
|
|
164
|
+
fail "scenario-2-r-query-positive" \
|
|
165
|
+
"qa_red_lint.mjs exited 0 (expected non-zero) — R-query rule not triggered for duplicate 'Connected' + queryByText"
|
|
166
|
+
else
|
|
167
|
+
fail "scenario-2-r-query-positive" \
|
|
168
|
+
"qa_red_lint.mjs exited non-zero but R-query recommendation (queryAllByText/getByTestId) not in output. Output: ${LINT_OUT2}"
|
|
169
|
+
fi
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
173
|
+
# SCENARIO 3: Negative — clean (no false positive)
|
|
174
|
+
# A fixture with a valid in-set literal + a uniquely-matched queryByText.
|
|
175
|
+
# Expected: exit 0 (no flags).
|
|
176
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
177
|
+
echo "--- Scenario 3: Negative — clean (no false positive) ---"
|
|
178
|
+
|
|
179
|
+
FIXTURE_DIR_CLEAN="$(mktemp -d)"
|
|
180
|
+
|
|
181
|
+
cat > "${FIXTURE_DIR_CLEAN}/clean_fixture.red.node.test.ts" << 'CEOF'
|
|
182
|
+
// fixture: clean — valid literal + unique query text
|
|
183
|
+
// theme="technical-dark" IS in Literal["technical-dark","business-warm","minimal-light"].
|
|
184
|
+
// 'Postgres' appears exactly once in the render input, so getByText('Postgres') is safe.
|
|
185
|
+
|
|
186
|
+
from typing import Literal
|
|
187
|
+
from pydantic import BaseModel
|
|
188
|
+
|
|
189
|
+
class DeckSpec(BaseModel):
|
|
190
|
+
theme: Literal["technical-dark", "business-warm", "minimal-light"]
|
|
191
|
+
|
|
192
|
+
# Valid in-set value — no R-enum violation
|
|
193
|
+
spec = DeckSpec(theme="technical-dark")
|
|
194
|
+
|
|
195
|
+
const rows = [
|
|
196
|
+
{ service: 'postgres', status: 'ok', detail: 'Postgres' }, // unique detail
|
|
197
|
+
{ service: 'redis', status: 'ok', detail: 'Redis' }, // different text
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
test('shows postgres row', () => {
|
|
201
|
+
render(<StatusTable rows={rows} />);
|
|
202
|
+
// Safe: 'Postgres' appears exactly once in the render input above.
|
|
203
|
+
const el = getByText('Postgres');
|
|
204
|
+
expect(el).toBeTruthy();
|
|
205
|
+
});
|
|
206
|
+
CEOF
|
|
207
|
+
|
|
208
|
+
if [[ "${LINT_PRESENT}" -eq 0 ]]; then
|
|
209
|
+
fail "scenario-3-negative-clean" \
|
|
210
|
+
"qa_red_lint.mjs absent at ${LINT_SCRIPT} — cannot run; baseline FAIL as expected (RED)"
|
|
211
|
+
else
|
|
212
|
+
node "${LINT_SCRIPT}" "${FIXTURE_DIR_CLEAN}" > /dev/null 2>&1
|
|
213
|
+
CLEAN_EXIT=$?
|
|
214
|
+
if [[ "${CLEAN_EXIT}" -eq 0 ]]; then
|
|
215
|
+
pass "scenario-3-negative-clean — exit 0 (no false positive on valid literal + unique query)"
|
|
216
|
+
else
|
|
217
|
+
fail "scenario-3-negative-clean" \
|
|
218
|
+
"qa_red_lint.mjs exited ${CLEAN_EXIT} (expected 0) — false positive on clean fixture"
|
|
219
|
+
fi
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
223
|
+
# SCENARIO 4: Negative — NON-APPLICABLE file (CRITICAL live-on-merge safety)
|
|
224
|
+
# A plain node:test file using only assert, no Pydantic Literal, no queryByText/
|
|
225
|
+
# getByText — shaped exactly like CR-082's own close_sprint.deferred-verify.red.node.test.ts.
|
|
226
|
+
# Expected: exit 0. Proves qa_red_lint won't phantom-flag CR-082's red test on merge.
|
|
227
|
+
# THIS SCENARIO IS MANDATORY.
|
|
228
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
229
|
+
echo "--- Scenario 4: Negative — NON-APPLICABLE file (CRITICAL) ---"
|
|
230
|
+
|
|
231
|
+
FIXTURE_DIR_NONAPPLICABLE="$(mktemp -d)"
|
|
232
|
+
|
|
233
|
+
# Write a file that is intentionally shaped like CR-082's own node:test:
|
|
234
|
+
# - uses node:test + assert only
|
|
235
|
+
# - no import from pydantic, no Literal[...], no string-union type
|
|
236
|
+
# - no queryByText, getByText, queryAllByText
|
|
237
|
+
# - no RTL imports
|
|
238
|
+
cat > "${FIXTURE_DIR_NONAPPLICABLE}/close_sprint.deferred-verify.red.node.test.ts" << 'NAEOF'
|
|
239
|
+
// close_sprint.deferred-verify.red.node.test.ts
|
|
240
|
+
// CR-082 QA-Red node:test — shaped as a plain node:test + assert file.
|
|
241
|
+
// No Pydantic Literal, no queryByText/getByText, no RTL — NOT a QA-Red lint target.
|
|
242
|
+
|
|
243
|
+
import { describe, it } from 'node:test';
|
|
244
|
+
import assert from 'node:assert/strict';
|
|
245
|
+
import { execSync } from 'node:child_process';
|
|
246
|
+
import path from 'node:path';
|
|
247
|
+
|
|
248
|
+
const SCRIPT = path.resolve(import.meta.dirname, '../../close_sprint.mjs');
|
|
249
|
+
|
|
250
|
+
describe('close_sprint deferred-verification gate (Step 2.9)', () => {
|
|
251
|
+
it('declared + NO result file → exits non-zero', () => {
|
|
252
|
+
// Env-seam: CLEARGATE_FORCE_DEFERRED_VERIFY drives the test without real files
|
|
253
|
+
const env = {
|
|
254
|
+
...process.env,
|
|
255
|
+
CLEARGATE_FORCE_DEFERRED_VERIFY: JSON.stringify({
|
|
256
|
+
'STORY-099-01': { declared: [{ command: 'docker build .', blocks: 'close' }], result: null }
|
|
257
|
+
}),
|
|
258
|
+
CLEARGATE_SKIP_WORKTREE_CHECK: '1',
|
|
259
|
+
CLEARGATE_SKIP_MERGE_CHECK: '1',
|
|
260
|
+
};
|
|
261
|
+
let threw = false;
|
|
262
|
+
try {
|
|
263
|
+
execSync(`node ${SCRIPT} SPRINT-00`, { env, stdio: 'pipe' });
|
|
264
|
+
} catch {
|
|
265
|
+
threw = true;
|
|
266
|
+
}
|
|
267
|
+
assert.ok(threw, 'Expected close_sprint.mjs to exit non-zero when deferred result is absent');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('declared + green result → gate passes', () => {
|
|
271
|
+
const env = {
|
|
272
|
+
...process.env,
|
|
273
|
+
CLEARGATE_FORCE_DEFERRED_VERIFY: JSON.stringify({
|
|
274
|
+
'STORY-099-01': { declared: [{ command: 'docker build .', blocks: 'close' }], result: 'green' }
|
|
275
|
+
}),
|
|
276
|
+
CLEARGATE_SKIP_WORKTREE_CHECK: '1',
|
|
277
|
+
CLEARGATE_SKIP_MERGE_CHECK: '1',
|
|
278
|
+
};
|
|
279
|
+
// Should NOT throw — gate passes on green
|
|
280
|
+
assert.doesNotThrow(() => {
|
|
281
|
+
execSync(`node ${SCRIPT} SPRINT-00`, { env, stdio: 'pipe' });
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('none declared → silent no-op, continues', () => {
|
|
286
|
+
const env = {
|
|
287
|
+
...process.env,
|
|
288
|
+
CLEARGATE_FORCE_DEFERRED_VERIFY: JSON.stringify({}),
|
|
289
|
+
CLEARGATE_SKIP_WORKTREE_CHECK: '1',
|
|
290
|
+
CLEARGATE_SKIP_MERGE_CHECK: '1',
|
|
291
|
+
};
|
|
292
|
+
// No deferred entries declared → gate is a no-op → should not throw
|
|
293
|
+
assert.doesNotThrow(() => {
|
|
294
|
+
execSync(`node ${SCRIPT} SPRINT-00`, { env, stdio: 'pipe' });
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
NAEOF
|
|
299
|
+
|
|
300
|
+
if [[ "${LINT_PRESENT}" -eq 0 ]]; then
|
|
301
|
+
fail "scenario-4-nonapplicable" \
|
|
302
|
+
"qa_red_lint.mjs absent at ${LINT_SCRIPT} — cannot run; baseline FAIL as expected (RED)"
|
|
303
|
+
else
|
|
304
|
+
node "${LINT_SCRIPT}" "${FIXTURE_DIR_NONAPPLICABLE}" > /dev/null 2>&1
|
|
305
|
+
NA_EXIT=$?
|
|
306
|
+
if [[ "${NA_EXIT}" -eq 0 ]]; then
|
|
307
|
+
pass "scenario-4-nonapplicable — exit 0 on plain node:test file (no phantom R-enum/R-query flag)"
|
|
308
|
+
else
|
|
309
|
+
fail "scenario-4-nonapplicable" \
|
|
310
|
+
"qa_red_lint.mjs exited ${NA_EXIT} (expected 0) — CRITICAL: false-flagged CR-082's own node:test shape; live-on-merge self-block risk"
|
|
311
|
+
fi
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
315
|
+
# SCENARIO 5: Wiring grep — qa_red_lint invoked in pre_gate_runner.sh run_arch()
|
|
316
|
+
# Expected: grep -q "qa_red_lint" .cleargate/scripts/pre_gate_runner.sh → 0
|
|
317
|
+
# FAILS on clean baseline (not yet wired).
|
|
318
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
319
|
+
echo "--- Scenario 5: Wiring grep ---"
|
|
320
|
+
|
|
321
|
+
if grep -q "qa_red_lint" "${PRE_GATE_SCRIPT}" 2>/dev/null; then
|
|
322
|
+
pass "scenario-5-wiring-grep — 'qa_red_lint' found in pre_gate_runner.sh"
|
|
323
|
+
else
|
|
324
|
+
fail "scenario-5-wiring-grep" \
|
|
325
|
+
"'qa_red_lint' not found in ${PRE_GATE_SCRIPT} — CR-081 wiring not yet applied (expected RED)"
|
|
326
|
+
fi
|
|
327
|
+
|
|
328
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
329
|
+
# SCENARIO 6: qa.md red-now-green clause grep
|
|
330
|
+
# Expected: grep -qiE "red-now-green|now PASSES|failing at baseline" in qa.md → 0
|
|
331
|
+
# FAILS on clean baseline (clause not yet added).
|
|
332
|
+
# ═════════════════════════════════════════════════════════════════════════════
|
|
333
|
+
echo "--- Scenario 6: qa.md red-now-green clause ---"
|
|
334
|
+
|
|
335
|
+
if grep -qiE "red-now-green|now PASSES|failing at baseline" "${QA_MD}" 2>/dev/null; then
|
|
336
|
+
pass "scenario-6-qa-md-clause — red-now-green clause found in qa.md"
|
|
337
|
+
else
|
|
338
|
+
fail "scenario-6-qa-md-clause" \
|
|
339
|
+
"red-now-green clause not found in ${QA_MD} — CR-081 qa.md edit not yet applied (expected RED)"
|
|
340
|
+
fi
|
|
341
|
+
|
|
342
|
+
# ── Summary ───────────────────────────────────────────────────────────────────
|
|
343
|
+
echo ""
|
|
344
|
+
echo "cr081_qa_red_lint.red.sh: ${PASS} passed, ${FAIL} failed"
|
|
345
|
+
if [[ "${FAIL}" -gt 0 ]]; then
|
|
346
|
+
exit 1
|
|
347
|
+
fi
|
|
348
|
+
exit 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"d7d1579f-97a4-4ed2-953e-1364ce697de7":{"input":166100,"output":1238677,"cache_creation":4905569,"cache_read":90028882,"last_ts":"2026-06-04T08:59:03Z","last_turn_index":0},"cd330896-e59e-4b46-b2ab-f420cbfa89d2":{"input":35856,"output":273596,"cache_creation":532880,"cache_read":12920963,"last_ts":"2026-06-04T09:22:15Z","last_turn_index":0},"a7ff198a-7354-4390-ba21-ec7df60ef4a1":{"input":71371,"output":934473,"cache_creation":4350709,"cache_read":91569515,"last_ts":"2026-06-04T14:17:56Z","last_turn_index":0},"00c82e3f-17dc-49cc-ab08-981ba1d9c6e2":{"input":155691,"output":1522802,"cache_creation":7137389,"cache_read":113485679,"last_ts":"2026-06-05T20:15:13Z","last_turn_index":0},"80279738-6cfd-4774-a2d3-50547d214129":{"input":34535,"output":50008,"cache_creation":993677,"cache_read":1958700,"last_ts":"2026-06-06T19:14:48Z","last_turn_index":0}}
|