Skip to content

feat(hooks): 4 new hooks for Opus 4.7 friction mitigation (v4.4.0)#2

Merged
LEEI1337 merged 5 commits into
mainfrom
feat/4-new-hooks
May 1, 2026
Merged

feat(hooks): 4 new hooks for Opus 4.7 friction mitigation (v4.4.0)#2
LEEI1337 merged 5 commits into
mainfrom
feat/4-new-hooks

Conversation

@LEEI1337

@LEEI1337 LEEI1337 commented May 1, 2026

Copy link
Copy Markdown
Member

Summary

  • 4 new hooks addressing Opus 4.7 audit-2 friction trends (+21% Wrong-Approach, +28% Buggy-Code, +22% Misunderstood-Request after 4.6→4.7 swap)
  • 120 new tests, ruff-clean, hook-safety verified
  • 12 → 16 hooks (+4), 13 → 18 hook commands in hooks.json
  • Plugin v4.3.0 → v4.4.0
  • 5 atomic commits in TDD-loop pattern

Hooks Added

Hook Event Friction-Class Tests
false-positive-guard.py UserPromptSubmit + PreToolUse Edit False-Positive-Bug-Invention (NEU 4.7) 47
org-naming-pre-push.py PreToolUse Bash (git push) Wrong-Folder/Repo 40
ahead-of-remote-warning.py SessionStart Ahead-of-Remote unentdeckt (nomos-97 pattern) 13
working-set-watch.py SessionStart Source-Files unversioned in Downloads/ 20

Test Plan

  • All 4 hooks: pytest tests/test_<hook>.py → 120/120 pass
  • Local CI dry-run: 7/7 jobs green (syntax, json, hook-safety, skills, format-tests, hardening-evidence, harden-scan)
  • ruff format --check clean
  • ruff check clean (own code; pre-existing RUF100 in session-start.py and statusline_lib.py untouched)
  • hooks.json valid + matchers correct
  • Plugin manifest version-bumped 4.3.0 → 4.4.0
  • CHANGELOG.md + CLAUDE.md + README.md updated (12→16 hooks)
  • CI green on this PR (await GitHub Actions)
  • Self-review (Joe Fuchs)

Code Reviewers (Pre-Commit Pattern)

2 blind judges via Agent-Team for H1:

  • Judge A (Pattern-Compliance): 7/9 → CONDITIONAL YES, blocker fixed
  • Judge B (Security/Performance): 3 critical findings:
    • Path-Traversal in lib/state.py (session_id not validated) — lib-wide, separately filed
    • Race-Condition in state.save()lib-wide, separately filed
    • DoS via large prompt — fixed in H1 (100KB input cap)

Out-of-Scope (Filed for Follow-up)

  • lib/state.py: session_id validation (path-traversal mitigation) — affects all 16 hooks, not introduced by this PR
  • lib/state.py: file-locking or atomic-write for concurrent save() — affects all 16 hooks

References

  • Audit reports: Documents/audit-2026-05-01/ (CODEBASE-ANALYSIS, ZUGANGSWEG-DEEP-DIVE, META-ANALYSIS, MASTER-FIX-EXECUTION)
  • Audit summary: Documents/COMPREHENSIVE-AUDIT-2026-05-01.md
  • Plan: ~/.claude/plans/jaundder-plan-hashed-tiger.md
  • Methodology: TDD-Red-Green-Refactor + 2 parallel blind judges + 6 quality-gates per hook (Joe-defined)

🤖 Generated with Claude Code

ai-engineering.at and others added 5 commits May 1, 2026 17:23
…itigation

H1 of 4 new hooks addressing 4.7 friction patterns (META-ANALYSIS audit-2).

Two-event hook:
- UserPromptSubmit: scan prompt for bug-evidence keywords (DE+EN), update
  state with timestamp + source. No output.
- PreToolUse (Edit): if no recent bug-evidence in state (default: <10 min),
  emit advisory; else silent pass. Never blocks.

Mitigates "false-positive bug invention" pattern observed in 4.7 audit
(+21% Wrong-Approach trend post-swap). Hook is structural — Code-enforced
verification gate before edits, not prompt-level guidance which 4.7's
higher confidence overrides.

Implementation:
- BUG_PATTERNS: 20 regex (DE+EN bug/error keywords, word-bounded)
- FAILURE_PATTERNS: 6 regex (test-failure markers in tool output)
- DoS-guard: truncate prompt to 100KB before regex (Judge B finding)
- Clock-skew defense: future timestamps not counted as recent (Judge A)
- State namespace: false_positive_guard.{last_evidence_seen_at,
  last_evidence_source, evidence_total, advisories_emitted, last_advisory_at}

Tests: 47 passed (parametrized DE/EN keywords, time-window logic,
DoS-guard, subprocess integration, state persistence, edge cases).
Coverage: hook fully exercised; lib/state.py shared paths unchanged.

Code-Reviewers (judgment-day pattern): 2 blind judges
- Judge A (Pattern-Compliance): 7/9 → CONDITIONAL YES → fixed Issue 1
- Judge B (Security/Performance): NO → 3 critical issues identified
  (path-traversal, race-condition, DoS). DoS fixed in-scope (input-cap).
  Path-traversal + race-condition are lib/state.py-wide concerns;
  filed as separate ERPNext follow-up tasks (out-of-scope for H1).

hooks.json: registered for UserPromptSubmit (matcher "") and
PreToolUse (matcher "Edit"). Total hook-commands: 13 → 15.

Refs: audit-2026-05-01/META-ANALYSIS.md (4.7-friction analysis)
Plan: ~/.claude/plans/jaundder-plan-hashed-tiger.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
H2 of 4 new hooks. PreToolUse Bash matcher; only fires on `git push` commands.

Reads cwd's .git/config, parses origin URL, classifies org:
- allow: AI-Engineering-at, LEEI1337, FoxLabs-ai → silent pass
- typo: AI-Engineerings-at → advisory with set-url remediation
- unknown: any other org → advisory (intentional fork? re-check)
- none: no origin / non-GitHub → silent pass

Default mode: advisory only (never blocks). Push works via redirect
for typo-org. Future config flag could enable strict block-mode after
a soak window.

Implementation:
- is_git_push_command: regex word-boundary, allows `git -C path push`
- parse_org_from_url: handles https:// and git@ URLs
- _read_origin_url: pure file-read (no subprocess), tolerates missing config
- State namespace: org_naming_pre_push.{push_count, violations_warned,
  last_org, last_classification}

Tests: 40 passed (parametrized URL/org/command parsing, fake-repo
fixtures, edge cases).

hooks.json: registered alongside approach-guard in PreToolUse Bash matcher.
Total hook-commands: 15 → 16.

Refs: audit-2026-05-01/MASTER-FIX-EXECUTION.md (#7 Org-Naming-Drift)
Plan: ~/.claude/plans/jaundder-plan-hashed-tiger.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
H3 of 4 new hooks. SessionStart event.

Iterates a configurable watch-list of repos and runs `git rev-list --count
origin/<branch>..HEAD` (NO fetch — pure local) for each. Emits an advisory
on Session-Start if any repo is ≥ warn threshold (5), critical (20).

Watch-list resolution:
  1. Env AHEAD_WARN_WATCH (comma-separated paths) — for testing/override
  2. Default: phantom-ai, nomos, zeroth, Playbook01, wiki under ~/Documents

Pure-local: no `git fetch`, no network. count_ahead() returns None when
repo is invalid, has no origin, or git times out (5s per call). Multiple
repo checks are sequential; total bound by 30s hook timeout in hooks.json.

Implementation:
- classify_severity: count → ok|warn|critical|unknown
- count_ahead: subprocess git rev-list, defensive
- _current_branch: subprocess git symbolic-ref
- _resolve_watch_list: env-or-defaults
- _build_advisory: formatted multi-repo output with severity icons

Tests: 13 passed (severity classification, real-git fixture with
clone+commits, env-override watch-list, edge cases).

hooks.json: registered alongside session-start in SessionStart.
Total hook-commands: 16 → 17.

Refs: audit-2026-05-01/COMPREHENSIVE-AUDIT (nomos 97 unpushed pattern)
Plan: ~/.claude/plans/jaundder-plan-hashed-tiger.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…igation

H4 of 4 new hooks. SessionStart event.

Scans configurable inboxes (default: ~/Downloads, ~/Documents/Downloads)
for strategy/concept/decision files older than threshold. Emits advisory
listing stale files with migration suggestion.

Threshold: warn ≥7 days, critical ≥30 days. Capped at 20 files reported.

Strategy-file patterns (filename, .md/.py/.yaml/.yml/.json only):
  Action_Plan*  Compliance_*  Lineage_*
  DEC-*         M0*           *_Concept_*

Implementation:
- is_strategy_file: pattern + extension whitelist
- classify_age_days: ok/warn/critical
- scan_inbox: per-inbox file walk + filter, returns list of findings
- _resolve_inboxes: env WORKING_SET_INBOXES or defaults
- _build_advisory: formatted output with severity icons + migration CTA

Tests: 20 passed (filename patterns, age classification, real-fs
fixtures with os.utime mtime control, edge cases).

hooks.json: registered alongside ahead-of-remote-warning in SessionStart.
Total hook-commands: 17 → 18.

Refs: audit-2026-05-01/MASTER-FIX-EXECUTION (Action Plan v1.0 lived
unversioned in Downloads/, migrated in Session A2)
Plan: ~/.claude/plans/jaundder-plan-hashed-tiger.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ation

- plugin.json: 4.3.0 → 4.4.0, description updated to reflect 16 hooks
- CHANGELOG.md: full v4.4.0 entry with hook details + judge findings
  + lib/state.py follow-ups (path-traversal, race-condition)
- CLAUDE.md: hook-count 12 → 16, list of 4 new hooks
- README.md: hook-count 12 → 16

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09f428ab8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

for line in content.splitlines():
stripped = line.strip()
if stripped.startswith("[") and stripped.endswith("]"):
in_origin = stripped == '[remote "origin"]'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve the pushed remote instead of hardcoding origin

The hook always parses [remote "origin"] from .git/config, so git push upstream main (or any push to a non-origin remote) is classified against the wrong target. This can suppress warnings when the actual destination org is typo/unknown, or emit misleading warnings when origin differs from the pushed remote. Since git push accepts an explicit <repository> argument, the hook should derive and validate that destination instead of assuming origin.

Useful? React with 👍 / 👎.

Comment on lines +141 to +142
cwd = data.get("cwd", "")
origin_url = _read_origin_url(cwd)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use git -C target repo when reading remote config

is_git_push_command explicitly matches commands like git -C /some/path push, but main() always reads .git/config from data["cwd"]. In that case the hook inspects the wrong repository (or none), so org checks can be skipped or reported for the wrong repo. Parse and prefer the -C path from the command before falling back to cwd.

Useful? React with 👍 / 👎.

@LEEI1337 LEEI1337 merged commit 9237ed4 into main May 1, 2026
7 checks passed
@LEEI1337 LEEI1337 deleted the feat/4-new-hooks branch May 1, 2026 16:26
LEEI1337 pushed a commit that referenced this pull request May 2, 2026
…eview #2)

Codex re-review on PR #3 (commit eafebc1) APPROVED the file-lock + RMW
fix but flagged one minor blind spot: get() returns the live reference,
not a copy. Callers who mutate via reference (e.g. `qg = s.get("ns");
qg["k"] = v`) without a follow-up s.set(ns, qg) won't trigger dirty-
namespace tracking, so the mutation is silently lost on save().

In practice this is mitigated because all existing hooks follow the
established `set()-after-mutation` pattern (visible throughout test
fixtures and hook code). But the contract was implicit. This commit
makes it explicit in the docstring so future hook authors won't be
surprised.

No code change. Lint clean. 49 state tests still green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant