feat(config-audit): TOK flags skill description > 500 chars (v5 M2) [skip-docs]

- New Pattern F in TOK: low-severity finding when SKILL.md description > 500 chars
- Scoped to discovery.files (project-local) — activeConfig.skills walk would
  pull in user/plugin skills out of project scope
- New fixtures: skill-bloated (594-char desc) + skill-tight (46-char baseline)

574 → 576 tests, all green.
This commit is contained in:
Kjell Tore Guttormsen 2026-05-01 06:58:42 +02:00
commit 9a44df22ac
4 changed files with 71 additions and 1 deletions

View file

@ -0,0 +1,8 @@
---
name: bloated
description: Bloated skill description used to trip the v5 M2 check. Repeats verbose framing about when, how, and why this skill should be used; lists every conceivable trigger phrase, every adjacent skill it composes with, and every alias and synonym a user might type, then explains in detail what the skill produces, what it does not produce, and what the user should run instead in edge cases. By design this description is comfortably over 500 characters so the TOK scanner emits a low-severity finding flagging it for tightening, since description text loads on every turn even when the body does not.
---
# Bloated skill body
Minimal body.

View file

@ -0,0 +1,8 @@
---
name: tight
description: Tight skill description, well under 500 chars.
---
# Tight skill
Minimal body.

View file

@ -189,6 +189,22 @@ describe('TOK scanner — hotspots contract', () => {
});
});
describe('TOK scanner — M2 skill description > 500 chars (v5)', () => {
it('flags skill with bloated description (low severity)', async () => {
const result = await runScanner('skill-bloated');
const f = result.findings.find(x => /skill description/i.test(x.title || ''));
assert.ok(f, `expected skill-description finding; got: ${result.findings.map(x => x.title).join(' | ')}`);
assert.equal(f.severity, 'low', `expected low, got ${f.severity}`);
assert.match(f.evidence || '', /bloated/);
});
it('does NOT flag tight description (under 500 chars)', async () => {
const result = await runScanner('skill-tight');
const f = result.findings.find(x => /skill description/i.test(x.title || ''));
assert.equal(f, undefined, `expected no skill-description finding; got: ${f?.title}`);
});
});
describe('TOK scanner — M4 cascade > 10k tokens (v5)', () => {
it('flags CLAUDE.md cascade > 10k tokens with medium severity', async () => {
const result = await runScanner('large-cascade');