Lint — semantic consistency of the canon
the press's health lane is mechanical: it catches dangling links, orphans, stale dates, and
typed contradicts: edges. It cannot read prose. Lint is the judgment layer — an LLM sweep
that reads the dossiers and finds the inconsistencies that survive a structural check.
Run it on a cadence or before a milestone, not on every edit — it costs tokens and time.
It is the right-hand column of the consistency table: judgment, not mechanism.
What it finds
- Contradiction — two dossiers assert claims that cannot both be true (e.g. page A
says auth tokens last 24h, page B says 1h).
- Superseded — a page's settled (
verified/canonical) claim is obsoleted by a newer
dossier on the same topic; the canon still states the old truth. (Lint reads the
cabinets, not the logbook — superseded evidence is cabinet-vs-cabinet.) This is a free-text
obsolescence detection, distinct from the engine's typed supersedes edge / projected superseded
state (ADR-0006): when the obsolescence is a genuine architecture decision replacing another,
the durable expression is a new ADR (bureau:adr --supersedes <ADR-N>), not just a stale flag.
- Gap — a concept referenced across pages but never defined on its own page.
- Drift — one concept named differently across pages (vocabulary drift: "cabinet" vs
"drawer" vs "page" for the same thing).
Rigor — verify before recording (the audit→fix→verify discipline)
A false contradiction is worse than a missed one — it erodes trust in the canon. So every
candidate finding is adversarially verified before it is recorded:
- Find. Read the corpus (chunk by drawer for a large workspace; fan out one reader per
drawer when subagents are available). Collect candidate findings of each type.
- Refute. For each candidate, try to disprove it — are the two claims actually about the
same scope/time/entity, or is the conflict only apparent (different context, superseded
already, profile-specific)? Default to discarding a candidate the refutation survives.
- Record only survivors. A finding is written only if the refutation fails.
This mirrors cc-suite:audit-fix: dimensions → find → adversarially verify → report.
Profile lenses
Load bureau.json.profiles and weight the sweep:
- software → decision reversals, API/behavior claims, version/config values.
- story → canon facts, timeline order, character traits and relationships.
Output
Lint writes one rendered findings page: <workspace>/lint/findings.md (title Lint
findings, the lint/ drawer renders as its own board section). It is overwritten each run —
it states the CURRENT findings, not history (history lives in the logbook). Each finding lists
its type, severity, the involved [[pages]] (body links, so they show as backlinks), and a
one-line suggested resolution.
With --apply, lint also writes conservative, reversible in-place markers so the press's
health lane surfaces the hard cases:
- a verified contradiction → set both pages
status: contested and add a reciprocal
single-line contradicts: [[Other page]] edge to each (2+ pages → one comma list
contradicts: [[A]], [[B]], deduped, preserving any existing edge — keep it single-line so the
edge reads as one diff). the press renders the contradiction;
- a verified superseded claim → set the page
status: stale.
Gaps and drift are report-only (creating pages or renaming a concept is a human/compile
decision, never an automatic edit).
Steps
- Locate the workspace (
bureau.json; default canon). If none, tell the user to run
bureau:init first and stop.
- Read the cabinets. Load every cabinet drawer, EXCLUDING
logbook/,
lint/ (lint's own findings — never lint the findings), crew/ (the crew source),
every _-prefixed file/dir (state ledgers, not canon), and — only in the contained layout
(a workspace named bureau) — the configured board dir (bureau.json.board, default
gazette), which there nests inside the workspace. In a default-layout workspace the board
renders outside, so a same-named child is ordinary content — do NOT exclude it. If there are
no dossiers yet, report "no cabinets to lint" and stop.
- Find + refute. Run the find→refute→record loop above for all four finding types,
weighted by the active profiles.
- Write the report. Write
lint/findings.md with the surviving findings; if none survive,
write a page stating the canon is consistent.
- Apply markers (only when
--apply): set contested/stale status and contradicts:
edges for verified contradictions and superseded claims. Never edit a page's prose claims —
only its status and the contradicts edge.
- Structural check. Run
node "${CLAUDE_PLUGIN_ROOT}/press/bin/gazette.mjs" health --dir <workspace> — the press's
deterministic dangling/orphan/contradiction/stale/schema check (also surfaced by bureau:inspect);
report the contradictions it now renders alongside the lint report.
- Report. Summarize counts by type and severity, name each
contested page, and point the
user at lint/findings.md.
Rules
- Read-mostly. Without
--apply, lint writes only the report page; it never edits the
canon's claims.
- No prose edits. Even with
--apply, lint changes only status: and contradicts: —
resolving a claim is a human act.
- Verified findings only. A recorded finding survived adversarial refutation.
- Idempotent report. Re-running overwrites
lint/findings.md with the current state.
Examples
Scope note
This skill covers ONLY the semantic-consistency sweep of dossiers. It does not capture
sessions (capture / bureau:file-session), does not distil the logbook into cabinets
(compile / bureau:compile), and does not render the gazette (bureau:inspect). It reads
the cabinets that compile produced and is invoked by the bureau:lint command.
1---2name: lint3description: Sweep the dossiers for semantic inconsistencies that the press's structural check cannot see — free-text contradictions, superseded claims, undocumented gaps, and vocabulary drift. Use when running bureau:lint, before a milestone, or when the user asks to check the canon for contradictions / consistency / drift.4---56# Lint — semantic consistency of the canon78the press's health lane is mechanical: it catches dangling links, orphans, stale dates, and9*typed* `contradicts:` edges. It cannot read prose. Lint is the judgment layer — an LLM sweep10that reads the dossiers and finds the inconsistencies that survive a structural check.1112Run it on a cadence or before a milestone, **not** on every edit — it costs tokens and time.13It is the right-hand column of the consistency table: judgment, not mechanism.1415## What it finds16171. **Contradiction** — two dossiers assert claims that cannot both be true (e.g. page A18 says auth tokens last 24h, page B says 1h).192. **Superseded** — a page's settled (`verified`/`canonical`) claim is obsoleted by a newer20 dossier on the same topic; the canon still states the old truth. (Lint reads the21 cabinets, not the logbook — superseded evidence is cabinet-vs-cabinet.) This is a **free-text**22 obsolescence detection, distinct from the engine's typed `supersedes` edge / projected `superseded`23 state (ADR-0006): when the obsolescence is a genuine *architecture decision* replacing another,24 the durable expression is a new **ADR** (`bureau:adr --supersedes <ADR-N>`), not just a `stale` flag.253. **Gap** — a concept referenced across pages but never defined on its own page.264. **Drift** — one concept named differently across pages (vocabulary drift: "cabinet" vs27 "drawer" vs "page" for the same thing).2829## Rigor — verify before recording (the audit→fix→verify discipline)3031A false contradiction is worse than a missed one — it erodes trust in the canon. So every32candidate finding is **adversarially verified before it is recorded**:33341. **Find.** Read the corpus (chunk by drawer for a large workspace; fan out one reader per35 drawer when subagents are available). Collect candidate findings of each type.362. **Refute.** For each candidate, try to disprove it — are the two claims actually about the37 same scope/time/entity, or is the conflict only apparent (different context, superseded38 already, profile-specific)? Default to discarding a candidate the refutation survives.393. **Record only survivors.** A finding is written only if the refutation fails.4041This mirrors `cc-suite:audit-fix`: dimensions → find → adversarially verify → report.4243## Profile lenses4445Load `bureau.json.profiles` and weight the sweep:46- **software** → decision reversals, API/behavior claims, version/config values.47- **story** → canon facts, timeline order, character traits and relationships.4849## Output5051Lint writes one rendered findings page: `<workspace>/lint/findings.md` (title **Lint52findings**, the `lint/` drawer renders as its own board section). It is overwritten each run —53it states the CURRENT findings, not history (history lives in the logbook). Each finding lists54its type, severity, the involved `[[pages]]` (body links, so they show as backlinks), and a55one-line suggested resolution.5657With `--apply`, lint also writes conservative, reversible in-place markers so the press's58health lane surfaces the hard cases:59- a verified **contradiction** → set both pages `status: contested` and add a reciprocal60 single-line `contradicts: [[Other page]]` edge to each (2+ pages → one comma list61 `contradicts: [[A]], [[B]]`, deduped, preserving any existing edge — keep it single-line so the62 edge reads as one diff). the press renders the contradiction;63- a verified **superseded** claim → set the page `status: stale`.64Gaps and drift are report-only (creating pages or renaming a concept is a human/`compile`65decision, never an automatic edit).6667## Steps68691. **Locate the workspace** (`bureau.json`; default `canon`). If none, tell the user to run70 `bureau:init` first and stop.712. **Read the cabinets.** Load every cabinet drawer, EXCLUDING `logbook/`,72 `lint/` (lint's own findings — never lint the findings), `crew/` (the crew source),73 every `_`-prefixed file/dir (state ledgers, not canon), and — **only in the contained layout**74 (a workspace named `bureau`) — the configured board dir (`bureau.json.board`, default75 `gazette`), which there nests inside the workspace. In a default-layout workspace the board76 renders outside, so a same-named child is ordinary content — do NOT exclude it. If there are77 no dossiers yet, report "no cabinets to lint" and stop.783. **Find + refute.** Run the find→refute→record loop above for all four finding types,79 weighted by the active profiles.804. **Write the report.** Write `lint/findings.md` with the surviving findings; if none survive,81 write a page stating the canon is consistent.825. **Apply markers** (only when `--apply`): set `contested`/`stale` status and `contradicts:`83 edges for verified contradictions and superseded claims. Never edit a page's prose claims —84 only its status and the contradicts edge.856. **Structural check.** Run86 `node "${CLAUDE_PLUGIN_ROOT}/press/bin/gazette.mjs" health --dir <workspace>` — the press's87 deterministic dangling/orphan/contradiction/stale/schema check (also surfaced by `bureau:inspect`);88 report the contradictions it now renders alongside the lint report.897. **Report.** Summarize counts by type and severity, name each `contested` page, and point the90 user at `lint/findings.md`.9192## Rules93941. **Read-mostly.** Without `--apply`, lint writes only the report page; it never edits the95 canon's claims.962. **No prose edits.** Even with `--apply`, lint changes only `status:` and `contradicts:` —97 resolving a claim is a human act.983. **Verified findings only.** A recorded finding survived adversarial refutation.994. **Idempotent report.** Re-running overwrites `lint/findings.md` with the current state.100101## Examples102103<example>104Context: Before a milestone, the user wants the canon checked for inconsistencies.105user: "bureau:lint"106assistant: "Swept the cabinets. One survivor after refutation: **Token TTL** says 24h, **Session TTL** says 1h — a real contradiction (same artifact, same scope). I wrote it to lint/findings.md with both pages linked. The 'cabinet' vs 'drawer' wording I considered drift was refuted — they name different things — so I did not record it."107<commentary>Only findings that survive adversarial refutation are recorded; a false finding would erode trust in the canon.</commentary>108</example>109110<example>111Context: The user wants lint to also mark the hard cases so the gazette surfaces them.112user: "bureau:lint --apply"113assistant: "Same findings, plus markers: I set both TTL pages to status: contested with reciprocal contradicts: edges, so the press's health lane now reports the contradiction. I changed only status and edges — never the prose claims; resolving which TTL is true is your call."114<commentary>--apply writes conservative, reversible markers only; prose claims are never edited.</commentary>115</example>116117## Scope note118119This skill covers ONLY the semantic-consistency sweep of dossiers. It does **not** capture120sessions (`capture` / `bureau:file-session`), does **not** distil the logbook into cabinets121(`compile` / `bureau:compile`), and does **not** render the gazette (`bureau:inspect`). It reads122the cabinets that `compile` produced and is invoked by the `bureau:lint` command.