fix(tests): the no-block guard reads the shell, not the comment explaining it (#3680)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 9s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / Python tests (push) Successful in 1m33s
CI & Build / Build & push image (push) Successful in 19s

The hook's header quotes `{"decision":"block"}` while explaining why this hook
must never emit one, and the instructions it prints use "decision" in a
sentence. Grepping the whole file caught both and failed the guard on the file
doing its job.

Strips comments and the heredoc first, and guards the stripper: `_code()`
returning nothing would make all three static checks pass against an empty
string, which is the circularity rule 167 is about.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
This commit is contained in:
2026-09-16 08:13:56 -04:00
co-authored by Claude Opus 5
parent 4b8d22e3ec
commit 47388eda36
+37 -4
View File
@@ -51,6 +51,39 @@ def _run(event: dict) -> subprocess.CompletedProcess:
capture_output=True, text=True, timeout=30)
def _code() -> str:
"""The script with its comments and its heredoc removed.
The static checks below are about what the shell DOES. Run over the whole
file they also read the header — which quotes `{"decision":"block"}` in the
course of explaining why this hook must never emit one — and the emitted
instructions, which use the word "decision" in a sentence. Both are the
file doing its job, and neither is code.
"""
lines, in_heredoc = [], False
for line in HOOK.read_text().splitlines():
if in_heredoc:
in_heredoc = line.strip() != "EOF"
continue
if line.lstrip().startswith("cat <<'EOF'"):
in_heredoc = True
continue
if not line.lstrip().startswith("#"):
lines.append(line)
return "\n".join(lines)
def test_the_comment_stripper_still_leaves_the_shell_behind():
"""Guard on the three checks below it. `_code()` returning nothing would
make every one of them pass while checking an empty string — the same
circularity the plugin version check has to defend against."""
code = _code()
assert "set -uo pipefail" in code and "exit 0" in code
# It really did strip: both of the words the checks look for are present
# in the file, and neither is in the code.
assert "decision" in HOOK.read_text()
@pytest.mark.parametrize("trigger", ["manual", "auto"])
def test_it_exits_zero_with_instructions_on_stdout(trigger):
"""Exit 0 plus non-empty stdout is the entire contract for reaching the
@@ -78,9 +111,9 @@ def test_it_emits_text_and_not_a_json_envelope():
def test_it_never_blocks_the_compaction():
"""A block skips compaction silently from the model's side. Nothing in the
script may produce one — not an exit code, not a decision."""
body = HOOK.read_text()
assert '"decision"' not in body and "'decision'" not in body
assert "exit 2" not in body
code = _code()
assert "decision" not in code, "a block decision would skip the compaction"
assert "exit 2" not in code
# A truncated or absent event must not turn into a non-zero exit either.
for event in ("", "not json", "{}"):
out = subprocess.run(["bash", str(HOOK)], input=event,
@@ -92,7 +125,7 @@ def test_additional_context_is_not_how_this_event_works():
"""SessionStart's channel, which does not exist on PreCompact. A rewrite
that reaches for it would read as consistent with the other hooks and
inject nothing at all."""
assert "additionalContext" not in HOOK.read_text().split("set -uo pipefail")[-1]
assert "additionalContext" not in _code()
def test_the_plugin_registers_it_on_precompact():