walk_hooks: stop counting hooks/README.md and hooks.json as script_loc
ci/woodpecker/push/test Pipeline is pending

kotkan/claude-plugin-inference-arbitrage#10 — a hook file is only counted
if it's referenced by .claude-plugin/hooks.json, executable, or has a
shebang. hooks/hooks.json itself is always excluded regardless, since it
is configuration rather than logic. mask-worktree-audit.py needed no
change: it derives script_loc from the already-filtered hooks[] output.

Bumps plugin.json to 0.6.2 (fix).
This commit is contained in:
Oleks
2026-07-30 05:31:01 +03:00
parent a218a31055
commit eb4b945599
5 changed files with 22 additions and 3 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "inference-arbitrage",
"version": "0.6.1",
"version": "0.6.2",
"description": "Audits a Claude Code plugin's definitions and usage transcripts to find steps that should be a deterministic script instead of raw LLM inference, and files the well-evidenced ones as issues on the target repo.",
"author": {
"name": "oleks"
+12 -1
View File
@@ -267,7 +267,13 @@ def walk_agents(plugin_path, catalog):
def walk_hooks(plugin_path):
"""Returns (hooks, texts) — texts maps hook filename -> file content, kept
out of the JSON output but needed by build_aggregate for drift detection."""
out of the JSON output but needed by build_aggregate for drift detection.
Only files that look like actual hook scripts are counted: referenced by
hooks.json, executable, or shebang'd. `hooks.json` itself is always
excluded — it is configuration, not logic — and anything else that fails
all three checks (READMEs, notes) is prose, not shipped executable
volume (kotkan/claude-plugin-inference-arbitrage#10)."""
hooks = []
texts = {}
hooks_dir = os.path.join(plugin_path, "hooks")
@@ -289,9 +295,14 @@ def walk_hooks(plugin_path):
except (json.JSONDecodeError, OSError):
pass
for fname in sorted(os.listdir(hooks_dir)):
if fname == "hooks.json":
continue
fpath = os.path.join(hooks_dir, fname)
if not os.path.isfile(fpath):
continue
if fname not in events_by_file and not os.access(fpath, os.X_OK) \
and detect_lang(fpath) == "unknown":
continue
with open(fpath, encoding="utf-8", errors="ignore") as f:
content = f.read()
texts[fname] = content
+4
View File
@@ -0,0 +1,4 @@
# hooks
Fixture doc, not a hook. Must never be counted in `script_loc` or appear in
`hooks[]` (kotkan/claude-plugin-inference-arbitrage#10).
+3
View File
@@ -0,0 +1,3 @@
{
"hooks": {}
}
+2 -1
View File
@@ -33,8 +33,9 @@ check "duplicated command block found across dupe-a and dupe-b" "
"
check "one agent found" "len(d['agents']) == 1"
check "fetcher mechanical_tool_share is 0.8 (4 of 5 tools)" "d['agents'][0]['mechanical_tool_share'] == 0.8"
check "one hook found" "len(d['hooks']) == 1 and d['hooks'][0]['file'] == 'guard.sh'"
check "one hook found (README.md/hooks.json excluded, kotkan/claude-plugin-inference-arbitrage#10)" "len(d['hooks']) == 1 and d['hooks'][0]['file'] == 'guard.sh'"
check "hook LOC matches file" "d['hooks'][0]['loc'] == 8"
check "README.md not counted toward script_loc" "d['aggregate']['script_loc'] == d['hooks'][0]['loc'] + d['scripts'][0]['loc']"
check "one bin script found, bash detected" "d['scripts'][0]['lang'] == 'bash' and d['scripts'][0]['loc'] == 3"
check "hook_prose_drift catches FIXTURE_ENV_VAR/fixture_check restated in dupe-a" "
any(p['hook'] == 'guard.sh' and p['skill'] == 'dupe-a'