Round-3 review of PR #85 found the "enforcing" pre-commit hook enforced nothing. Vale's exit code keys on error-level alerts alone: five of the six rules were level: warning, so they exited 0, and pre-commit hides output from a passing hook — the alerts were invisible and blocked nothing. ADR-0013 rejected a report-only trial tier and then shipped one by accident. Flatten every rule to level: error. Vale's own exit code is then correct, so the hook entry drops to a bare vale-wrap.sh call and the graded error->FAIL / warning->SUGGESTION mapping disappears from both audit skills: every alert is a FAIL, in the gate and the audit alike. No ignorable tier, matching shellcheck, the test suite and conventional-pre-commit. Delete Kyberforge.VagueQualifier. Measured against the 41 skill/agent files as they stood before the rule ever ran: 2 hits. One marginal ("very different" -> "fundamentally different"), one an unfixable false positive — caveman/SKILL.md quotes "of course" as an example of filler, a mention not a use — which forced the only Vale suppression comments in the repo. Those four lines go with it; two of them were dead anyway, suppressing a frontmatter-scoped rule on a body line. Held-out prose (273 files) fired 15 times, 9 inside out-of-scope research examples and the rest one word in two idioms in a single doc. SentenceOpenerThereIs survives: 22 held-out hits, both in-corpus hits clean rewrites, zero suppressions. Widen .vale.ini's globs to [**/SKILL.md], [**/agents/*.md] and [**/*.agent.md]. The plugins/*/-prefixed globs scoped nothing — Vale's * crosses /, so they already matched docs/research/examples/**/agents/*.md and assets/templates/SKILL.md, the two paths CONTEXT.md claimed they excluded. Scoping is and was the hook's files: regex. The old globs also hid a silent false negative: a skill outside plugins/ matched no section, so Vale reported 0 files and exited 0, which both audits read as clean. They now treat a 0-file run as NOT RUN and fall back to full judgment. Also: - vale-wrap.sh resolves relative --config values and file arguments against the caller's cwd, as vale does, instead of the repo root, which hard-errored from a subdirectory and silently skipped flattening for file args that did not resolve from the root. Absolute paths inside the cwd are relativized so reports cite resolvable paths, not scratch ones. - vale-run's exit-code model was documented backwards ("exits non-zero whenever it finds an alert at or above MinAlertLevel") and would have led anyone following it to build a gate that passes everything. Its Markdown suppression syntax was MDX-only and does not suppress in .md; corrected in the skill and its troubleshooting reference, with backtick/fence exemption documented as the first resort. - skill-size-check.sh fails only above 500 lines, agreeing with skill-audit's validate.sh <= 500 pass. - ADR-0013 and CONTEXT.md amended to match, recording why graded severities cannot gate. Verified: 9 test scripts / 15 vale-wrap cases pass; vale-audit-prefilter, skill-size-check and shellcheck pass --all-files; check-manifests and claude plugin validate --strict clean. New tests fail against the old script (3 of them) and pass against the new one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MCQ648fLSFXPHGZdQ8gn58
49 lines
2.0 KiB
Bash
Executable File
49 lines
2.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Enforces agentskills.io's skill-authoring.md guidance: keep SKILL.md within
|
|
# 500 lines and roughly 5,000 tokens, so the full body doesn't crowd out
|
|
# conversation history and other active skills once loaded into context. Vale
|
|
# can't express a whole-file length ceiling (its checks operate on text
|
|
# patterns, not raw file size), so this is a plain script instead of a Vale
|
|
# rule.
|
|
#
|
|
# Both ceilings are inclusive: a file at exactly MAX_LINES or MAX_WORDS passes,
|
|
# and only one past it fails. That matches skill-audit/scripts/validate.sh,
|
|
# which has always used `line_count <= 500` as its pass condition — the two
|
|
# previously disagreed at exactly 500 lines, so a SKILL.md could pass its own
|
|
# audit and still be blocked by the commit hook.
|
|
#
|
|
# Token counts aren't computed exactly here — word count (`wc -w`) is used as
|
|
# a proxy. This repo's own SKILL.md corpus measures ~5.7-6.5 characters per
|
|
# word, which at the standard ~4-characters-per-token English approximation
|
|
# works out to roughly 1.6-1.7 tokens per word. MAX_WORDS below is calibrated
|
|
# from that measured ratio against the 5,000-token ceiling, with margin — it's
|
|
# still a proxy, not exact BPE tokenization, but now grounded in actual repo
|
|
# content rather than an unverified "conservative" assumption.
|
|
|
|
MAX_LINES=500
|
|
MAX_WORDS=2900
|
|
FAIL=0
|
|
|
|
for f in "$@"; do
|
|
[[ -f "$f" ]] || continue
|
|
|
|
# awk's NR counts the final line even without a trailing newline, matching
|
|
# Python's splitlines() semantics (used by skill-audit/scripts/validate.sh
|
|
# for its own line count) — `wc -l` undercounts by 1 in that case.
|
|
lines=$(awk 'END{print NR}' "$f")
|
|
if (( lines > MAX_LINES )); then
|
|
echo "ERROR: $f has $lines lines, exceeding the $MAX_LINES-line ceiling (agentskills.io skill-authoring.md)" >&2
|
|
FAIL=1
|
|
fi
|
|
|
|
words=$(wc -w < "$f")
|
|
if (( words > MAX_WORDS )); then
|
|
echo "ERROR: $f has $words words (proxy for tokens), exceeding the $MAX_WORDS-word ceiling (~5,000 tokens, agentskills.io skill-authoring.md)" >&2
|
|
FAIL=1
|
|
fi
|
|
done
|
|
|
|
exit $FAIL
|