feat(register): a decided title, and an org-profile that stops lying

Three changes at the register/engine boundary, all agreed with org-ops
after census 05 and all about a check missing a place to record a
legitimate exception.

`titles`: an optional per-repo README title. Set, the H1 matches it and
is OK; unset, the WARN stands as before. A human title was already this
engine's stated position and rds-v1's prescription, but a decided YES had
nowhere to live, so the same 6 WARNs were reported three censuses running
and would have been reported forever. Five registered, each H1 read from
the repo rather than copied from the census; `ai-psychosis` deliberately
left out so the one repo where a reader cannot connect title to name
stands alone. Measured across 21 local clones: 6 WARN before, 1 after,
nothing else moved.

`readme_desc_match: false` on the org-profile class: for an ordinary repo
the README opening and the forge description describe the same subject
and equality is right; for this class they do not — the README is the
org's landing page, the forge text describes the repo. The equality is
what does not apply, not either text. Class data, not a hardcoded name,
and the exemption is RECORDED as an OK naming its reason, not dropped.
`.profile` went ERROR to 0 ERROR / 0 WARN; the same README under a plugin
class is still an ERROR.

`engineCommit`: the version names a file, only the sha names the code. A
sweep stamped 18 files 0.4.0 while four carried a 0.5.0-only finding —
feature and version bump are two commits, so the stamp lied without being
broken. Present-and-null when underivable, never absent: an absent key
means an older engine, null means this one ran without a HEAD to read.

135 to 147 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NELsvPY5gnJjN3esdhWYWC
This commit is contained in:
Kjell Tore Guttormsen 2026-08-09 21:14:43 +02:00
commit 5884a64e54
8 changed files with 358 additions and 27 deletions

View file

@ -10,7 +10,7 @@ checks that surface in one repository and reports what it finds.
*AI-generated: all code produced by Claude Code through dialog-driven development.*
![Version](https://img.shields.io/badge/version-0.5.0-blue)
![Version](https://img.shields.io/badge/version-0.6.0-blue)
![Platform](https://img.shields.io/badge/platform-Claude_Code_Plugin-purple)
![Skills](https://img.shields.io/badge/skills-1-orange)
![License](https://img.shields.io/badge/license-MIT-lightgrey)
@ -108,6 +108,39 @@ finding is a `SKIP` — the question is live and unanswered. Where there is no
running prose at all, it is an `OK`: nothing claims a language, and a thin README
is the first-screen check's business, not this one's.
### Registered titles — where a decision gets written down
A README H1 that is a human title rather than the repo name is a naming choice
the maintainer owns, and the standard prescribes `# Title` for every class. But
until a YES could be *recorded*, the gate reported the same six warnings every
round, and there was no way to tell "this was decided" from "nobody has looked".
An optional `titles` entry in the register is that record. Set it, and an H1
matching it is an `OK`. Leave it out, and the warning stands exactly as before.
The point is the asymmetry: once the deliberate titles are registered, the repos
nobody has ruled on are the only ones still warning.
An H1 that matches neither the repo name nor a registered title is still a
warning, and the message names both — that is drift in one of the two, not a
title.
### When equality is the wrong demand
`README-DESC` requires the README's opening line to be the forge description
verbatim, because for an ordinary repo the two describe the same subject and any
gap between them is drift on a published surface.
The `org-profile` class is the one place that premise fails. Its README is the
organisation's landing page; the forge description describes the repository.
Both are correct about their own subject, so it is the *equality* that does not
apply, not either text — and a landing page's opening line carries a link, while
the description field renders as plain text, so satisfying the old check would
have meant putting raw markdown on a real surface.
A class turns the demand off with `readme_desc_match: false` in the register.
The exemption is still reported as a finding that names the reason: an exception
nobody can see is indistinguishable from a check that silently stopped running.
### What is deliberately not required
`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` and `MAINTAINERS.md` are required by no
@ -147,6 +180,28 @@ Only names in **URL position** are treated as references, which excludes prose,
paths and directory names in one move. The `.git` suffix is normalised first —
without that, a raw scan turns three dead names into about twenty.
### Every run says which engine produced it
The header and the `--json` output carry the engine's version *and* the commit
it ran from:
```
✓ voyage [plugin] — OK (repo-standard v0.6.0 @a7276e6)
```
Both, because they answer different questions. A stale plugin cache once served
an old engine against a current repo and the output looked like a clean pass,
which is why the version is there. But the version names a *file*: a feature and
its version bump are two commits, so a worktree holds new behaviour under the
old number for a window, and a sweep once stamped eighteen files with a version
that predated the check that produced their findings. Only the commit names the
code.
The commit is read from the engine's own checkout, with no network call. When
there is none to read — a vendored copy, an unpacked tarball — the JSON field is
present and `null` rather than missing, so "this engine could not tell you" stays
distinct from "an older engine that never tried".
## Non-goals
- **Anything requiring a view across every repository at once.** This gate sees
@ -167,7 +222,7 @@ without that, a raw scan turns three dead names into about twenty.
npm test
```
135 tests over the pure classifiers. The reference fixtures are measured false
147 tests over the pure classifiers. The reference fixtures are measured false
positives, each with its expected verdict — the six that produced the
three-outcome reference rule, plus the noise sources found by running the gate
against a real repository: regexes inside code spans that are markdown links to