benchbook
↑↓ navigate↵ openDocs · Wiki · Contract
GitHub
Contractagents-lint-checks.md

agents-lint-checks.md

LINT Checks — Detail

Loaded on-demand: read this file only when actually running the LINT operation. Not loaded at session start — see agents-core.md § 3 Operations § LINT for the cadence, posture, report format, and archival procedures, which stay in core.

Posture reminder: LINT is report-only for wiki content. It never edits page bodies or frontmatter. Its only write permissions are two file-moving operations that never delete — raw-file archival and log archival.

One exception, and it is narrow: the error-class mechanical checks gate commits. scripts/pre-commit.sh runs scripts/lint.py and blocks the commit on any error. Warnings never block, and the judgement checks below are not involved at all — they need a model, and a commit hook that needs a model is a commit hook people disable. Bypass deliberately with git commit --no-verify; install with ln -s ../../scripts/pre-commit.sh .git/hooks/pre-commit.

The distinction that makes this safe: reporting stays advisory because it involves judgement, while gating is restricted to checks with exactly one correct answer — a missing required field, a link that doesn’t resolve, a file in the wrong folder for its declared type. Nothing that gates a commit requires an opinion.


Mechanical checks

These are deterministic. They belong in scripts/lint.py, not in model judgement — cheaper, repeatable, and runnable on every commit.

CheckRule sourceNotes
Frontmatter — required fields, enums, tag vocabularyagents-page-conventions.md § YAML Frontmattertag vocabulary enforced on reference pages only
Domain ↔ folder consistencyagents-core.md § 4 Architecturewiki/sources/ and wiki/people/ are global — any domain allowed there; elsewhere a mismatch is an error
Source page sectionsagents-page-conventions.md § Source Page Conventionsmissing ## Summary / ## Sources = error; missing ## Content with a fetchable source_url = warning, unless content-exempt tagged
Project section templateagents-domain-projects.mdincluding the three extra sections required by deployed status
Skill roster vs diskagents-core.md § skillsa skill directory with no roster entry, or a roster entry with no directory = error; missing/invalid SKILL.md frontmatter, name: ≠ directory name, maturity: outside draft|tested|hardened = error. Disk is the source of truth; the roster page is a view over it
Predicate vocabularyagents-domain-knowledge.mdout-of-vocabulary predicate = warning; fix at next touch — most belong in ## Key Facts. Scans every page carrying a ## Relations table, not just knowledge entities, and matches the heading exactly## Relationship to X is prose, not a triplet table
Project relationsagents-page-conventions.md § Project Relations## Relations missing on an active/planned project, or not positioned directly after ## Summary = error. Closed projects are out of scope
Reference page auditagents-page-conventions.md § Reference Page Conventionsfewer than 4 compared entities = conversion candidate; no enforcement
Index coverage + orphansagents-core.md § 6 Indexpage missing from all index files = warning; dead index link = error; zero inbound links = warning, unless standalone-reference tagged
Page lengthagents-core.md Hard Rule 10measured excluding append-only sections; project and source exempt; entity threshold higher. Report the worst offenders and a total count, not every breach
Broken relative linksHard Rule 4any ](path.md) that doesn’t resolve = error
Raw path in page bodyHard Rule 14a body link to a raw/ path = error
Duplicate files* 2.md / *conflicted copy* under wiki/ = error (sync-tool artifact); delete manually after confirming the original
Scripts store — README + linksagents-core.md § scripts/subfolder missing README.md = warning; a wiki page linking a scripts/… path that doesn’t exist = error; subfolder with no inbound link from any wiki page = warning
Scripts store — secret scanagents-core.md § scripts/scripts/**/*.{yaml,yml,json} scanned for hardcoded password / api_key / secret / token literals not using env-var, vault, or placeholder syntax = error
Publish auditcounts per domain only, no enforcement
Channel triggeragents-domain-knowledge.mdan origin with ≥3 sources and no channel entity → note proposing one

Judgement checks

These need reading comprehension and are where a linting agent adds something a script can’t. All of them surface findings; none of them act.

CheckRule sourceNotes
Entity placement auditagents-core.md § Entity Placement Rulepeople/ is humans only; flag suspected misplacements between <domain>/entities/ and knowledge/entities/ — surface, never auto-move
Contradictionsspot-check recent pages against what they supersede. Two pages that quietly stopped agreeing is the single most valuable thing LINT finds
Stalenessdoes this page describe a state of the world that later pages have superseded?
Thin pagestriage the script’s orphan and thin-page warnings for genuine problems vs. pages that are simply short and fine
Inline-artifact triageagents-core.md § scripts/spot fenced code blocks in page bodies that are standalone artifacts (full configs or scripts) rather than illustrative snippets; flag as scripts/ migration candidates

A note on threshold design

When a check fires on more than a few percent of your content, the check is usually wrong, not the content.

In the original wiki, the page-length rule flagged 27% of all pages. A rule that flags a quarter of your content steers nothing — you stop reading its output within two runs. The fix was to make the measurement honest (exclude append-only sections, exempt page types whose length is inherent, raise the threshold for deliberately dense pages) and to report only the worst offenders plus a backlog count.

Before adding a check, estimate what fraction of pages it will fire on. If the answer is “lots”, fix the threshold first.

A note on check scope

A second failure mode, subtler than a bad threshold: a check that is right about the region it inspects is not the same thing as a check that is right.

The predicate-vocabulary check above was originally scoped to knowledge entity pages, because that is where ## Relations tables started. It reported clean for months. When the graph was finally measured end to end, 709 triples existed — 185 of them outside the check’s scope, carrying 124 off-vocabulary predicates. Inside the scope, 0 of 524 rows were bad. The check had a perfect record and a blind spot, and the perfect record is what stopped anyone looking.

So when you write a rule and a check for it, write down both scopes and compare them. If the rule says “every page that has this section” and the check says “pages in this one folder”, the gap between them is invisible by construction — the check cannot report on what it does not read.

Same class of bug, different shape: matching a heading by prefix rather than exactly. ## Relations and ## Relationship to the old system both start with ## Relation, and only one of them is a triplet table.