Files
zernie__vigiles/docs/rules/duplicate-rules.md
zernie 85c54e7e78 fix(lint)!: make the lint report complete, tierable and machine-readable (#187)
Closes #181, closes #182, closes #183, closes #184, closes #185, and the
residual half of #173.

#185 — every per-surface check read ONE root, so a monorepo with `skills/` plus
`plugins/*/skills/` scored only the first: 4 skills over budget, 2 reported,
exit 0. The default now NAMES the bundles it did not score; `--bundles=all`
scores them in one pass with one exit code. Root-only stays the default so a
vendored third-party corpus is not scored as if it were yours.

#181 — `orphan-docs` had a documented severity nothing read, and the
duplicate-rules check had no id at all, so neither could be tiered. Both are
real rules now and the exit code respects their severity.

#183 — the log and `--json` disagreed (21 lines against 88 findings) because
some checks print per finding and others per group. One computed total, printed
and carried in `--json`.

#182 — `--json-out=<file>` writes the JSON while stdout stays human-readable,
so a CI job stops scanning twice.

#184 — `vigiles test` resolves a harness's bare `vigiles` import from the CLI's
own install, so `npx vigiles@<version> test` needs nothing in the project.
NODE_PATH was measured, not assumed: Node ignores it for ESM.

#173 residual — `lint` verified the integrity HASH, which says nothing about
whether the things a file NAMES still exist, so an artifact committed while its
refs were live stayed green after the target was deleted. The new `spec-refs`
rule re-derives them. It immediately found four dead references in this repo's
own `examples/CLAUDE.md.spec.ts`, left behind by the hexagonal refactor.

BREAKING CHANGE: `orphan-docs` and `duplicate-rules` now default to "warn" — a
repo relying on either to fail CI must set "error" explicitly. Registering them
surfaced that both are heuristic proxies, and this repo's calibration rule is
that a heuristic never defaults to error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 19:51:21 +05:00

2.1 KiB

duplicate-rules

Near-duplicate rules within one spec — two rules that say the same thing in different words. Detected by NCD (gzip-based) similarity, so it is deterministic and needs no model.

{ "rules": { "duplicate-rules": "warn" } }
Default warn
Surface instruction-file specs (*.spec.ts)
Bucket heuristic-behavioral
Detector findDuplicateRules

What it checks

Every pair of rules inside a spec is compared by normalized compression distance. A pair below the similarity threshold is reported as spec bloat: duplicated guidance is guidance the reader has to reconcile, and the model has to weigh twice.

Severity

  • "warn" (default) — reported, exit code untouched.
  • "error" — a duplicate pair fails the build.
  • false / "off" — the check does not run.

Why it defaults to warn

It is a proxy, not a fact: NCD says two strings compress well together, which is evidence that they overlap and not proof that they are redundant. Two rules can legitimately share vocabulary and mean different things.

This repo's calibration rule is that a heuristic never defaults to error, because a rule that fails a correct build gets switched off rather than fixed.

History

Until 2026-09 this check had no rule id at all — the finding fed the exit code directly, so vigiles lint could exit 1 over it with no name a config could even mention, and no way to tier it (#181). Registering it surfaced a second problem: it was behaving as error while being a heuristic, which is exactly the combination the calibration rule exists to prevent. Set it back to "error" explicitly if the old blocking behaviour is what you want.

See also