{
  "_README": [
    "PreToolUse(Bash) hook snippet — TRACKED, so it arrives with a clone. Every .claude/settings*.json",
    "path in this repo is gitignored (confirm with `git check-ignore -v .claude/settings.json`), so a",
    "hook registration cannot itself be tracked. This is the tracked SOURCE that install-wizard merges",
    "into the user's local settings. Shipping the file is not the same proposition as wiring it — that",
    "gap is exactly what #204 found (the SessionStart hook existed from 07-05 and the wizard had never",
    "installed it, for every new user).",
    "",
    "WHAT IT GUARDS: reading a verdict from the wrong end of a pipe. `cmd | tail -5; echo $?` reports",
    "TAIL's status, so a FAILED gate reads as 0 — a degrade toward PASS, the direction that never",
    "announces itself. Measured 6x in this project 2026-07-29..07-31.",
    "",
    "WHY A HOOK AND NOT A FILE LINTER: the plan of record was an S6 class in degrade_direction_scan.sh.",
    "Hand-verifying every `pipe + $?` in this repo's scripts returned 7 hits, 7 of them CORRECT. True",
    "positives in shipped files: 0. All 6 recurrences were in interactively-composed commands, which no",
    "repo scanner reads. The guard belongs where the defect occurs — the Bash call itself.",
    "",
    "ADVISORY BY DESIGN: it warns and exits 0. It never blocks a Bash call, because a mis-read verdict",
    "is re-runnable, and a false block on a developer's own shell trains the --no-verify reflex on the",
    "hooks that DO guard irreversible surfaces (pre-push destructive-op, pre-commit confidentiality).",
    "Escalate deliberately with FH_PIPE_VERDICT_BLOCK=1 if a project wants it to bite.",
    "",
    "Carries no private path, so it belongs in .claude/settings.json (project-local), not settings.local.json.",
    "Merge, do not overwrite: preserve any PreToolUse entries the user already has; replace only the FH",
    "one, keyed by script name.",
    "",
    "Verify after wiring (known pair, both directions):",
    "  bash scripts/test_pipe_verdict_guard_lanes.sh          # expect: all known pairs hold (count is self-reported by the suite — do not pin it here, it rots)",
    "  printf '%s' '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"g.sh | tail; rc=$?\"}}' \\",
    "    | bash scripts/pipe_verdict_guard.sh                 # expect a PIPE-VERDICT R2 warning",
    "",
    "SECOND GUARD ON THE SAME SURFACE — destructive_pre_gate.sh (added 2026-08-01, field→meta",
    "reverse propagation from pmh-dev): advisory warning when a Bash call carries a destructive",
    "command (git reset --hard, clean -f, checkout ., force push, branch -D, stash drop/clear,",
    "rm -rf on root/home/cwd). Origin: a below-floor sidecar self-justified `git reset --hard",
    "origin/main` and ran it — the weaker the tier, the weaker the self-inhibition, so the",
    "counterweight is mechanical. Net-new coverage is the LOCAL destructive ops no git hook sees;",
    "the pre-push hook remains the hard floor for the push-time surface (role deconfliction in the",
    "script header). Advisory by design, same contract as pipe_verdict_guard (additionalContext +",
    "systemMessage, no permissionDecision); escalate with FH_DESTRUCTIVE_BLOCK=1. Opt out with",
    "`# noqa: destructive-op` — the opt-out exempts the ENTIRE Bash payload (whole-command match),",
    "not a single line: a multi-statement payload with a destructive line 1 and a noqa on line 2 is",
    "fully exempt (accepted advisory-surface residual — see the script header's PRECISION OVER RECALL list).",
    "  bash scripts/test_destructive_pre_gate_lanes.sh        # expect: all known pairs hold (count self-reported)",
    "",
    "THIRD GUARD, Write matcher — stale_clone_guard.sh (added 2026-08-01, fh_signal_2026-07-31):",
    "advisory when a NEW file is created inside a git clone that is behind its upstream (fetch +",
    "behind-count, once per repo per day, creation-only — overwrites never fire). Origin: a session",
    "built on a 46-PR-behind clone and manufactured a duplicate of an upstream lane. found→extend",
    "applies at repo level; this is its mechanical layer. Same advisory contract; fail-open on",
    "every uncertainty (non-repo, no upstream, fetch failure).",
    "  bash scripts/test_stale_clone_guard_lanes.sh           # expect: all known pairs hold (count self-reported)",
    "",
    "FOURTH GUARD, Bash matcher — backtick_guard.sh (added 2026-09-03, weekly_audit_2026-09-02 HIGH #1):",
    "advisory when a Bash call carries a backtick inside a shell DOUBLE-QUOTING context — an unquoted",
    "heredoc body (<<EOF) or a \"double-quoted string\". There a backtick is command substitution: the text",
    "between the backticks is REPLACED by the command's output — empty when it names no command, so the",
    "text is silently DELETED and the record commits with a hole (every record hook checks presence, not",
    "completeness). Measured 7x 2026-08-10..09-02 with a resident memory rule that failed each time because",
    "the actor's task had a different name than the rule's title. Quote-aware state machine, not a regex:",
    "single-quoted text, quoted heredocs (<<'EOF'), and escaped backticks are CLEAN. Same advisory contract;",
    "escalate with FH_BACKTICK_BLOCK=1; opt out with `# noqa: backtick` (whole payload).",
    "  bash scripts/test_backtick_guard_lanes.sh              # expect: all known pairs hold (count self-reported)",
    "",
    "FIFTH GUARD, Edit|Write|Bash matcher — proposal_hook.sh (added 2026-09-03, identity ⑤ r4):",
    "advisory when a verdict/guard line in scripts/**/*.sh or templates/*.sh is about to change: puts ONE",
    "instruction into the model context — offer the user a known-pair control + degrade_direction_scan.sh in",
    "one line. Measured: the same rule as a CLAUDE.md table row fired 1/15 at floor tier (r3); as this hook",
    "9/9 relay on editing reps and 0/5 on a usage-string edit (r4). Quote-aware: an edit confined to quoted",
    "strings does not fire. Bash path (sed -i / > / tee into a .sh) covered with a weaker rule (named",
    "residual in the script header). Evidence row in .claude/.proposal_hook_events.tsv. Relaying an",
    "injected instruction is not initiative — see the r4 RESULT for what this does and does not claim.",
    "  bash scripts/test_proposal_hook_lanes.sh                # expect: all known pairs hold (count self-reported)",
    "",
    "SIXTH GUARD, WebSearch|WebFetch matcher — outbound_query_hook.sh (added 2026-09-05):",
    "the FIRST hook here that can emit permissionDecision:\"deny\", so read its degrade direction before",
    "wiring it. WHAT IT GUARDS: a WebSearch/WebFetch query is an OUTBOUND, IRREVERSIBLE act — if the",
    "string names an internal asset, the query IS the leak (CLAUDE.md §Field-Harness Diagnostic: internal",
    "names never reach a log, a comment or a paste). scripts/outbound_query_guard.sh has owned that lint",
    "since 2026-08-21 with ZERO callers, and its own header says so; this is its wiring. A repo scanner",
    "cannot see an interactively-composed query, so the guard belongs on the call — same reasoning as",
    "pipe_verdict_guard's.",
    "",
    "TWO LAYERS, AND ONLY ONE OF THEM DENIES. The CLI guard fail-closes when the operator's gitignored",
    "override layer is absent. Correct for a CLI you type; wrong for a hook, because in a consumer",
    "install that layer is absent BY CONSTRUCTION — importing that contract would deny every consumer's",
    "WebSearch, and the bypass it would train is turning hooks off, disarming the destructive-op and",
    "confidentiality guards riding the same channel. So:",
    "    override-layer hit   -> deny      (the operator's own internal literals)",
    "    defaults-layer hit   -> advisory  (universal shapes; FP-prone, and all a consumer has)",
    "    no override present  -> advisory + a once-per-session UNCALIBRATED notice (a defaults-only scan",
    "                           cannot say \"no internal tokens\", only \"no universal shapes\")",
    "    instrument incomplete-> deny      (NOT SCANNED is not clean; irreversible surface fails CLOSED)",
    "    not an FH checkout   -> silent    (mechanical test: is the tracked defaults file here?)",
    "    hook command absent  -> the tool RUNS. A PreToolUse command that cannot be found is a non-blocking",
    "                           error, so on a consumer install where scripts/outbound_query_hook.sh is not at",
    "                           $CLAUDE_PROJECT_DIR/scripts/ the deny you think you wired is fail-OPEN (cross-family",
    "                           review, 2026-09-05). Same contract as the five guards above, but this one denies,",
    "                           so VERIFY after wiring:  echo '{}' | bash \"$CLAUDE_PROJECT_DIR/scripts/outbound_query_hook.sh\"; echo rc=$?",
    "                           rc=0 and no output = resolved and silent on an empty payload; 'No such file' = not wired.",
    "The layer is decided by comparing hit COUNTS across two scans (full set, then defaults-only). A",
    "boolean would collapse \"both layers hit\" into \"defaults hit\" and silently downgrade a real deny.",
    "",
    "🟥 THE OUTPUT NEVER CARRIES THE TOKEN VALUE — only the count and the severity label. A leak guard",
    "that echoes the token into its own deny reason or log is the leak channel. Lane H10 asserts the",
    "fixture token appears on no output surface (stdout, stderr, event log).",
    "",
    "Opt out on one call by putting `# noqa: outbound` in the query. That channel is gameable, which is",
    "exactly why it writes a log row — an invisible bypass is worse than a recorded one. Evidence rows in",
    ".claude/.outbound_hook_events.tsv: ts, tool, verdict(deny|advisory|clean|noqa|na), layer, and the",
    "tool_input KEY NAMES (schema, never content) — the official hooks reference does not document",
    "WebSearch/WebFetch tool_input keys, so the hook scans every string value rather than hardcoding a",
    "key name that would fail SILENTLY OPEN, and logs the observed shape so it becomes measured.",
    "",
    "🟥 ADD THESE TWO TO YOUR .gitignore WHEN YOU WIRE THIS — the hook writes them on every matched",
    "call and they are not tracked content:",
    "    .claude/.outbound_hook_events.tsv",
    "    .claude/.outbound_hook_uncalibrated_notice",
    "Missed on the first build; a clean-clone run flagged both as tree contamination, which is also",
    "what a consumer's `git status` would have shown after their first WebSearch.",
    "",
    "Verify after wiring (known pair, both directions):",
    "  bash scripts/test_outbound_query_hook_lanes.sh       # expect: all known pairs hold (count self-reported)",
    "  printf '%s' '{\"tool_name\":\"WebSearch\",\"tool_input\":{\"query\":\"bash printf portability\"}}' \\",
    "    | bash scripts/outbound_query_hook.sh              # expect: NO output (a clean query is silent)",
    "  bash scripts/test_outbound_query_lanes.sh            # the CLI twin, for outbound paths this hook",
    "                                                       # does NOT cover (curl / external CLIs via Bash)"
  ],
  "project_settings_json": {
    "hooks": {
      "PreToolUse": [
        {
          "matcher": "Bash",
          "hooks": [
            {
              "type": "command",
              "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/pipe_verdict_guard.sh\"",
              "timeout": 5
            },
            {
              "type": "command",
              "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/destructive_pre_gate.sh\"",
              "timeout": 5
            },
            {
              "type": "command",
              "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/backtick_guard.sh\"",
              "timeout": 5
            }
          ]
        },
        {
          "matcher": "Write",
          "hooks": [
            {
              "type": "command",
              "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/stale_clone_guard.sh\"",
              "timeout": 20
            }
          ]
        },
        {
          "matcher": "Edit|Write|Bash",
          "hooks": [
            {
              "type": "command",
              "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/proposal_hook.sh\"",
              "timeout": 5
            }
          ]
        },
        {
          "matcher": "WebSearch|WebFetch",
          "hooks": [
            {
              "type": "command",
              "command": "bash \"$CLAUDE_PROJECT_DIR/scripts/outbound_query_hook.sh\"",
              "timeout": 5
            }
          ]
        }
      ]
    }
  }
}
