Source: ce-code-review run 20260830-212446-4b8b0529 (adversarial P1/75, precedence-verified pre-existing).
What
When a PostToolUse host pipes no payload or an undecodable one, crates/comment-checker/src/check.rs (decode failure and file_path.is_empty) returns Outcome::Pass -> exit 0. The hook gate goes green while checking nothing.
Why it matters
The gate's failure mode is silent pass. Any payload-shape drift or a host that launches the hook without a pipe silently deactivates the enforcement for every write, with no stderr, no exit-2, and no committed test able to see it.
Decision needed
Keep fail-open (documented intent: 'a hook must never block the user on bad input', hook.rs:29) vs fail-closed on empty non-TTY stdin (exit non-zero with a diagnostic). Changes the binary contract; user decision.
Also pins the plumbing gap: no committed test pipes a real payload through hooks/run.ts (adversarial testing_gap).
Carried by PR #92: #92
Source: ce-code-review run 20260830-212446-4b8b0529 (adversarial P1/75, precedence-verified pre-existing).
What
When a PostToolUse host pipes no payload or an undecodable one,
crates/comment-checker/src/check.rs(decodefailure andfile_path.is_empty) returnsOutcome::Pass-> exit 0. The hook gate goes green while checking nothing.Why it matters
The gate's failure mode is silent pass. Any payload-shape drift or a host that launches the hook without a pipe silently deactivates the enforcement for every write, with no stderr, no exit-2, and no committed test able to see it.
Decision needed
Keep fail-open (documented intent: 'a hook must never block the user on bad input', hook.rs:29) vs fail-closed on empty non-TTY stdin (exit non-zero with a diagnostic). Changes the binary contract; user decision.
Also pins the plumbing gap: no committed test pipes a real payload through hooks/run.ts (adversarial testing_gap).
Carried by PR #92: #92