Adversarial deep research (25 sources, 124 claims extracted, 25 verified: 11 confirmed / 14 refuted) plus direct measurement of all 18 cloned open/ repos. The useful half of the result is what it REFUSED to support, so the research is recorded in docs/presentation-research-2026-08-03.md rather than being spent and forgotten. - BADGE-COUNT (WARN) — past five badges. Trockman et al., ICSE 2018 (n=294,941 npm packages) measured a non-linear relationship with popularity inflecting at five, motivated by surveyed maintainers calling over-badged READMEs cluttered and "trying too hard". WARN and never ERROR: the coefficient sits in an appendix with no CI or p-value. Counting deliberately uses a NARROWER rule than the existing claim check, so a screenshot or an architecture diagram is never counted as clutter. Fires on 8 of 18. - README-LANGUAGE (WARN) — prose not in the language this repo's readers were declared to speak, via a new `locales` axis in the register. Class is structural, a trait is what the code DOES, a locale is who it is FOR — the standard's own "who the reader is decides what is required". English is the default; ms-ai-architect and okr are declared nb, named by the operator as Norway-only in audience. Stopword-frequency comparison over prose with code stripped: a Norwegian flag name in a shell example cannot decide the document. Fires on exactly those two, silent on all sixteen English repos. One design correction found mid-implementation: the first version returned SKIP when a README had too little prose to judge, which broke a passing fixture and would have stopped any terse repo from ever reaching OK. SKIP is for a check that could not RUN; this one ran, saw everything and found no prose to be in the wrong language — the same shape as "no licence claim to back". Insufficient prose is now OK, and evenly bilingual prose is the SKIP, because there the question is live and unanswered. Deliberately NOT built, because the evidence does not reach: any rule about images, diagrams or terminal recordings (every such claim refuted 0-3); a README length bound (no evidence-based target exists); a section count (would fire on 9 of 18 — textbook "suspect the CHECK"); Mermaid source length and #gh-dark-mode-only (zero occurrences, and the instance limit is not readable via the API, so any threshold would be a guess). Verified live against the operator's own forge (15.0.6+gitea-1.22.0): Mermaid DOES render in README.md — two div.mermaid-block iframes carrying real SVG — while #gh-dark-mode-only landed only in Gitea 1.26.0 and is unavailable here. 103 tests green, up from 92. No version bump: the catalog ref still trails at v0.1.1 against 0.1.3, and starting a second release chain over that is the operator's call. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TCAGKZT8h9F46ygzSkhEee
179 lines
8.8 KiB
Markdown
179 lines
8.8 KiB
Markdown
# repo-standard
|
|
Per-repo gate for the open/ presentation standard: README first screen, install block, files required by the repo's class, and dead repo references.
|
|
|
|
A repository can be substantially good and still read as abandoned. The gap is
|
|
almost never the code — it is the first screen, an install path that stops
|
|
halfway, and references to a name that was retired two renames ago. This plugin
|
|
checks that surface in one repository and reports what it finds.
|
|
|
|
> **Solo-maintained, fork-and-own.** This plugin is a starting point, not a vendor product. Issues are welcome as signals; pull requests are not accepted. See the [marketplace governance](https://git.fromaitochitta.com/open/ktg-plugin-marketplace/src/branch/main/GOVERNANCE.md) for the full model.
|
|
|
|
*AI-generated: all code produced by Claude Code through dialog-driven development.*
|
|
|
|

|
|

|
|

|
|

|
|
|
|
**Status:** maintained, solo. The public API is the gate's finding codes and the
|
|
register schema; both can still change before 1.0. There is no CI — the forge
|
|
has no Actions runner — so the test claim is one you run yourself, in one
|
|
command, from a clean clone: `npm test`. A badge asserting it would be a claim
|
|
dressed as evidence.
|
|
|
|
## Install
|
|
|
|
Use the `https://` form. The forge UI's clone button hands out an `ssh://` URL,
|
|
and `marketplace add` answers it with `Invalid git URL` — a message that never
|
|
mentions the protocol.
|
|
|
|
```bash
|
|
claude plugin marketplace add https://git.fromaitochitta.com/open/ktg-plugin-marketplace.git
|
|
claude plugin install repo-standard@ktg-plugin-marketplace
|
|
```
|
|
|
|
Or enable it directly in `~/.claude/settings.json` — a working second path, not
|
|
a replacement for the two commands above:
|
|
|
|
```json
|
|
{ "enabledPlugins": { "repo-standard@ktg-plugin-marketplace": true } }
|
|
```
|
|
|
|
## Requirements
|
|
|
|
Node 18 or newer. No dependencies. Two network calls: the org listing (for a
|
|
repo's published description) and the catalog manifest (to confirm the install
|
|
command resolves). Both read anonymously, so no token is needed, and `--offline`
|
|
skips both — the checks that depended on them then report `SKIP`, not `OK`.
|
|
|
|
## What it does
|
|
|
|
Run it inside a repository:
|
|
|
|
```bash
|
|
node scripts/repo-standard-check.mjs --dir "$PWD"
|
|
```
|
|
|
|
The repository's **class** decides what each check means:
|
|
|
|
| Check | What fails it |
|
|
| --- | --- |
|
|
| First screen | no H1 on line 1, or the line under it is not the published description. An H1 that merely differs from the repo name is a `WARN` — that is a naming choice, not a defect |
|
|
| Install block | the form for this class is missing, incomplete, shown over `ssh://`, or points at the wrong marketplace |
|
|
| Install truth | the plugin is not pinned in the catalog, so the documented command cannot succeed for anyone |
|
|
| Required headings | `## Install`, `## Non-goals`, `## Changelog` — per class. Present at the wrong depth is its own finding |
|
|
| Required files | a file this class (or trait) needs is absent |
|
|
| Repo references | an `open/<name>` in URL position resolves to nothing |
|
|
| Relative links | a link points at a file that is not tracked |
|
|
| Licence claim | the README cites a licence the repo has no file for |
|
|
| Badges | a static image badge — any host — asserts a test, build or coverage run that nothing verifies |
|
|
| Badge count | more than five badges, the inflection measured by Trockman et al. (ICSE 2018) past which a badge row reads as clutter rather than as evidence. `WARN` only — the source cannot carry a hard limit |
|
|
| README language | the prose is not in the language this repo's readers were declared to speak |
|
|
| Boilerplate | template text nobody filled in |
|
|
| Version consistency | manifest, README badge, newest CHANGELOG entry and the git tag disagree |
|
|
| Description | empty, or past the length bound |
|
|
|
|
Findings carry two independent things: a **level** (`ERROR`, `WARN`, `SKIP`,
|
|
`OK`) and a **bucket**, which is what you actually triage on:
|
|
|
|
- **broken now** — a stranger is blocked or misled
|
|
- **missing** — an expected artefact is absent
|
|
- **weakening** — present and working, but it reads as amateur
|
|
|
|
The process exits 1 on any `ERROR`. A `SKIP` means the check could not run — an
|
|
unreachable forge, an untagged repo, a link that leaves the repository. It is
|
|
not a pass, and the output prints those separately under a heading that says so.
|
|
|
|
### Traits — a second axis
|
|
|
|
Class is structural. A **trait** is about what the code does, which no remote can
|
|
tell you. `security` attaches the obligations a tool takes on by handling
|
|
untrusted input: a `SECURITY.md` with a real disclosure channel, and a
|
|
`## Known limitations` section. Traits live in the register and are the
|
|
maintainer's judgement, not a reading.
|
|
|
|
### Locales — a third axis
|
|
|
|
Class is structural, a trait is what the code *does*, and a locale is who the
|
|
code is *for*. English is the default and is not listed. A repo aimed only at a
|
|
Norwegian readership is declared `nb` in the register, and is then wrong in
|
|
English rather than right — the standard's own principle is that who the reader
|
|
is decides what is required, and language is the first thing that decides.
|
|
|
|
Detection is a stopword-frequency comparison over prose with code stripped, so a
|
|
Norwegian flag name in a shell example cannot decide what the document is. It
|
|
answers which language dominates and nothing else: a README can pass this and
|
|
still be badly written. Where the prose is too evenly bilingual to call, the
|
|
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.
|
|
|
|
### What is deliberately not required
|
|
|
|
`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` and `MAINTAINERS.md` are required by no
|
|
class. This project is solo-maintained and says so publicly; contributor-facing
|
|
documentation for something that accepts no contributors is theatre, and a code
|
|
of conduct with an unattended placeholder address is worse than none — it is a
|
|
visible unfinished template. Consumer-facing documents are untouched by that.
|
|
Being solo is not a reason to skip a `SECURITY.md`; someone finding a hole still
|
|
needs somewhere to send it.
|
|
|
|
### The class decides what is required
|
|
|
|
The class is read off the catalog and the remotes; it is structural, not a
|
|
judgement. It lives in `register/repos.json`.
|
|
|
|
| Class | Install form | Requires |
|
|
| --- | --- | --- |
|
|
| plugin | `marketplace add` **and** a CLI install command | README, LICENSE, CHANGELOG, plugin manifest |
|
|
| catalog | `marketplace add` only — it *is* the marketplace | + GOVERNANCE, CONVENTIONS |
|
|
| shared-asset | how to vendor it; never a plugin install line | README, LICENSE |
|
|
| standalone | pip/uv | README, LICENSE |
|
|
| org-profile | none | README |
|
|
|
|
A flat standard across every class would demand a roadmap from a five-line
|
|
profile. That is how a gate teaches people to switch it off.
|
|
|
|
### Three outcomes on references, not two
|
|
|
|
"Matches no repository" and "matches something that is deliberately not a
|
|
repository" are different findings. The second class is real and it is common:
|
|
a retired name kept alive on purpose in prose, a reserved namespace occupying a
|
|
repo-shaped path, a published package name that was never a repo. If those share
|
|
an outcome with genuine dead links, the genuine ones hide inside a pile of
|
|
correct text.
|
|
|
|
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.
|
|
|
|
## Non-goals
|
|
|
|
- **Anything requiring a view across every repository at once.** This gate sees
|
|
one repo. A README can look correct from the inside and only turn out wrong
|
|
when a dozen are compared. Org-wide divergence is measured where the org is
|
|
enumerated, not here.
|
|
- **Fixing while measuring.** It records findings; you fix them afterwards.
|
|
Patching under measurement is how inconsistency accumulates unnoticed.
|
|
- **Deciding whether to rename a repo, or whether a roadmap is real.** Those are
|
|
operator calls. The gate brings evidence to them.
|
|
- **Blocking commits.** There is no hook. A gate that fails a correct repository
|
|
is the mechanism that gets gates switched off, so this one earns that role
|
|
before it takes it.
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
npm test
|
|
```
|
|
|
|
103 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
|
|
a naive scanner, `file:` URLs, and relative links resolved against the wrong
|
|
directory.
|
|
|
|
## Changelog
|
|
|
|
See [CHANGELOG.md](CHANGELOG.md).
|