Skip to content

Commit 4f7c918

Browse files
BenPerroclaude
andcommitted
test(pril): codify C4 gitignored-exemption in suite; fix shellcheck findings in ported TDD specs
merge-when-true gate findings on PR #95, closed instead of waived: - C4 behavior had only manual verification — now 7 suite assertions in test_runtime_integrity_layer.sh against a real dynamic git fixture: exempt+visible-NOTE, non-ignored file still blocks, violation names the real file, tracked-but-ignore-matching never exempted, --strict-gitignored re-blocks - shellcheck: SC2317/SC2329 directives on indirectly-invoked helpers (is_deny/hook_out, called via assert's eval), drop genuinely-unused out1/rc2 captures in test_reality_wired_in_prod.sh Full suite local (with shellcheck installed): ALL CHECKS PASSED. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent e51c1f5 commit 4f7c918

3 files changed

Lines changed: 40 additions & 2 deletions

File tree

config/claude/tests/test_pretool_wait_state_hook.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,15 @@ run_hook() { # run_hook <project> <stdin-json>
5555
}
5656
# A genuine deny: decision=="deny" OR a deliberate non-zero from an EXISTING hook
5757
# (1 or 2). 255 = "hook absent" sentinel, 127 = bash missing-file: NOT a deny.
58+
# shellcheck disable=SC2317,SC2329 # invoked indirectly via assert's eval'd condition string
5859
is_deny() { # is_deny "<decision>|<rc>"
5960
local d="${1%%|*}" rc="${1##*|}"
6061
[ "$d" = "deny" ] && return 0
6162
{ [ "$rc" = "1" ] || [ "$rc" = "2" ]; } && return 0
6263
return 1
6364
}
6465
# Capture the hook's stdout text for stop-code assertions (empty when absent).
66+
# shellcheck disable=SC2317,SC2329 # invoked indirectly via command substitution inside assert args
6567
hook_out() { # hook_out <project> <stdin-json>
6668
local project="$1" payload="$2"
6769
[ ! -f "$HOOK" ] && { printf ''; return; }

config/claude/tests/test_reality_wired_in_prod.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ assert_file "A0: reality-check binary present" "$REALITY"
4545
# A1 (positive control / gap exposure): plain mode currently PASSES a not-wired
4646
# record. This assertion PASSES today and documents the hole.
4747
set +e
48-
out1="$("$REALITY" --repo "$repo" --feature "$FEAT" --min-evidence integration 2>&1)"; rc1=$?
48+
"$REALITY" --repo "$repo" --feature "$FEAT" --min-evidence integration >/dev/null 2>&1; rc1=$?
4949
set -e
5050
assert_eq "A1 gap: plain reality-check currently PASSES the not-wired record (exit 0)" "0" "$rc1"
5151

@@ -54,7 +54,7 @@ assert_eq "A1 gap: plain reality-check currently PASSES the not-wired record (ex
5454
# name is a placeholder for the fix; the load-bearing assertions are the
5555
# STOP-WIRED-PROD behaviour and naming the culprit REQ, not the exact CLI).
5656
set +e
57-
out2="$("$REALITY" --repo "$repo" --feature "$FEAT" --min-evidence integration --require-wired 2>&1)"; rc2=$?
57+
out2="$("$REALITY" --repo "$repo" --feature "$FEAT" --min-evidence integration --require-wired 2>&1)"
5858
set -e
5959
assert_contains "A2 RED: wired-enforcing rejection carries stop-code STOP-WIRED-PROD" "$out2" "STOP-WIRED-PROD"
6060
assert_contains "A2 RED: rejection names the not-wired requirement (REQ-X1)" "$out2" "REQ-X1"

config/claude/tests/test_runtime_integrity_layer.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,42 @@ assert_output_contains "broad [a-z]* scope error names too-broad pattern" "too b
163163
assert_exit "literal-anchored glob-class scope still passes" 0 \
164164
"$SCOPE_BIN" --repo "$FIXTURES/scope-broad-literalclass" --feature demo --changed-files "$FIXTURES/scope-broad-literalclass/changed-files.txt"
165165

166+
# C4 (2026-07-08 retro): paths that are BOTH gitignored AND untracked are
167+
# session-tooling droppings (e.g. `.claude-flow/` daemon state), not feature
168+
# edits — they are exempted with a visible NOTE instead of false-positiving the
169+
# gate. Tracked files are never exempted; `--strict-gitignored` restores the old
170+
# behavior. Needs a REAL git repo (check-ignore), so this fixture is built
171+
# dynamically instead of living under fixtures/.
172+
C4_REPO="$(mktemp -d)"
173+
git -C "$C4_REPO" init -q -b main
174+
mkdir -p "$C4_REPO/docs/canvas" "$C4_REPO/src/demo" "$C4_REPO/.claude-flow"
175+
cp "$FIXTURES/scope-pass/docs/canvas/demo.canvas.md" "$C4_REPO/docs/canvas/demo.canvas.md"
176+
printf '.claude-flow/\n' > "$C4_REPO/.gitignore"
177+
printf 'runtime\n' > "$C4_REPO/.claude-flow/daemon.pid"
178+
printf 'ok\n' > "$C4_REPO/src/demo/app.py"
179+
printf '.claude-flow/daemon.pid\nsrc/demo/app.py\n' > "$C4_REPO/changed-dropping.txt"
180+
assert_exit "C4: gitignored+untracked dropping is exempted (pass)" 0 \
181+
"$SCOPE_BIN" --repo "$C4_REPO" --feature demo --changed-files "$C4_REPO/changed-dropping.txt"
182+
C4_NOTE_OUT="$("$SCOPE_BIN" --repo "$C4_REPO" --feature demo --changed-files "$C4_REPO/changed-dropping.txt" 2>&1)"
183+
assert_contains "C4: exemption is visible (NOTE names the dropping)" "$C4_NOTE_OUT" ".claude-flow/daemon.pid"
184+
assert_contains "C4: exemption is labeled as tool artifacts, not silent" "$C4_NOTE_OUT" "NOTE: ignoring gitignored+untracked tool artifacts"
185+
# A real out-of-scope file (untracked but NOT gitignored) must still block.
186+
printf 'nope\n' > "$C4_REPO/rogue.py"
187+
printf '.claude-flow/daemon.pid\nrogue.py\n' > "$C4_REPO/changed-rogue.txt"
188+
assert_nonzero "C4: non-ignored out-of-scope file still blocks" \
189+
"$SCOPE_BIN" --repo "$C4_REPO" --feature demo --changed-files "$C4_REPO/changed-rogue.txt"
190+
assert_output_contains "C4: violation names the real file, not the dropping" "rogue.py" \
191+
"$SCOPE_BIN" --repo "$C4_REPO" --feature demo --changed-files "$C4_REPO/changed-rogue.txt"
192+
# A TRACKED file matching a gitignore pattern is a real edit — never exempted.
193+
git -C "$C4_REPO" add -f .claude-flow/daemon.pid -- >/dev/null 2>&1
194+
assert_nonzero "C4: tracked-but-ignore-matching file is NOT exempted" \
195+
"$SCOPE_BIN" --repo "$C4_REPO" --feature demo --changed-files "$C4_REPO/changed-rogue.txt"
196+
git -C "$C4_REPO" rm -q --cached .claude-flow/daemon.pid >/dev/null 2>&1
197+
# --strict-gitignored restores the old fail-closed behavior for droppings.
198+
assert_nonzero "C4: --strict-gitignored re-blocks the dropping" \
199+
"$SCOPE_BIN" --repo "$C4_REPO" --feature demo --changed-files "$C4_REPO/changed-dropping.txt" --strict-gitignored
200+
rm -rf "$C4_REPO"
201+
166202
# G2-REQ-002: redaction rejects unsafe persistence and can produce a safe redacted stream.
167203
assert_exit "redaction safe JSONL check exits 0" 0 \
168204
"$REDACT_BIN" --mode check < "$FIXTURES/redaction/safe.jsonl"

0 commit comments

Comments
 (0)