Skip to content

bug(hooks): a hook emits permissionDecision "warn", which is not in the contract and does nothing (#15956 family) #16079

Open

Description

@mrveiss

Summary

.claude/hooks/block-dangerous-commands.sh:347 emits

{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"warn", ...}}

warn is not a value in the PreToolUse contract. The harness recognises
allow, deny and ask. An unrecognised value is not a weaker decision — it is
no decision, so this emission does nothing at all.

It is inert twice over:

the value warn is not in the contract, so nothing acts on it
the channel it is written to stderr, and stdout is what carries a decision; the script then falls through to exit 0 at :410, where stderr is not surfaced

So the advisory reaches neither the harness nor the operator.

Why it matters beyond one dead line

The advisory exists to warn when a commit is made outside a per-task workspace,
citing #6512 — a real coordination hazard, and the reason the advisory was
written. What shipped cannot deliver that warning, and nothing in the source
distinguishes it from one that does
: it is well-formed JSON, correctly shaped,
sitting beside three sibling emissions in the same file that are all real
decisions and all work.

This is the #15956 family exactly. There the defect was an ask whose exit code
discarded it; here it is a decision whose value is not in the contract. Both
produce a hook that looks correct at every site a reader would check.

Found by the guard, which could not see it

repo_tests/hook_decision_exit_codes_15956_test.py swept every hook and reported
green over this line, because DECISION_RE enumerated ask|allow|deny — the
valid values. A detector keyed on the valid set cannot see an invalid member
of it, which is the one thing it most needs to catch. PR #15996 widens the regex
to match any value and asserts membership, so this fails loudly.

That PR carries this instance as a ratchet entry pinned to this issue rather than
fixing it, because the remedy is a behaviour decision (below) and bundling it
would make that PR's review harder than it should be. The ratchet asserts the
line is still inert, so it fails the moment this is fixed and cannot be
forgotten.

The decision this needs

Restoring the intent is not a one-line change, because a PreToolUse hook has no
advisory channel that is both non-blocking and visible:

Acceptance criteria

Activity

  1. github-actions commented on Sep 8, 2026

    @github-actions
    Contributor

    👋 Auto-triage could not confidently classify this issue (no confident signal). Could a maintainer add the appropriate labels (frontend, backend, infrastructure, docs, testing and good-first-issue, intermediate, advanced)?

  2. modified the milestones: Backlog, v0.16.0 on Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions