repo-standard/CHANGELOG.md
Kjell Tore Guttormsen f4017bcfe1 feat(engine)!: a skip says which of the two things it is
`notChecked` merged "deliberately not judged" with "could not run". 0.7.0 took
SKIP out of the severity lattice, which fixed "clean repos look skipped"; this
fixes the same defect one level down, where it was saying so more quietly.
Measured across 19 clones, 35 of 39 skips are deliberate — so
`portfolio-optimiser — OK · 11 not checked` announced eleven unread checks when
all eleven were fixture and out-of-repo links.

Every SKIP finding now carries `skip: 'byDesign' | 'notRun'`, set at the
emission site rather than looked up from its code: VERSION-TAG is emitted at
SKIP with no tags and at ERROR with the wrong one, so a code→kind map has to
re-derive a reason the emitter already had. Untagged falls to `notRun`, the
loud side. Results carry `skips: { byDesign, notRun }`; `notChecked` stays a
number and stays the total, because a consumer doing `notChecked > 0` against
an object gets a silent false.

The summary line names only `notRun` — the deliberate ones keep their own
`NOT JUDGED` heading in the detail output. Landing the split in `--json` alone
would have left the symptom exactly where it was.

VERSION-UNAVAILABLE stays `notRun` by decision, not by default: it is arguably
"no subject to judge", the shape checkReadmeLanguage answers with OK, but
re-levelling it moves a repo's status and is a second behaviour change.

Verified: 169 tests. 19 clones swept with both engines offline — 220 judged
findings, every status, notChecked and buckets identical, no finding differing
beyond the new tag. The exhaustiveness test scans the engine SOURCE, not a
finding set: a corpus test only sees the sites it triggers, and the next
emission site added would take the reader's default invisibly.

BREAKING CHANGE: the summary line's coverage qualifier reads `· N not run` and
counts only un-runnable skips, where it read `· N not checked` over all of
them. `--json` gains `skips`; `notChecked` is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHaQTcaD3w2C6PqVsAmrcv
2026-08-09 21:52:00 +02:00

490 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog
All notable changes to this project are documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
versioning is [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.8.0] — 2026-08-09
### Added
- **Skips split into the two facts they always were.** Every `SKIP` finding now
carries `skip: 'byDesign' | 'notRun'` beside its level, and results carry
`skips: { byDesign, notRun }` beside `status`. `byDesign` is a check that saw
the thing and declined — a link leaving the repository, a dead link in a
fixture path; it can never become a verdict and nobody has an action.
`notRun` is one a re-run or an operator action resolves — an unreachable
catalog, an unregistered repo, a repo with no tags.
0.7.0 took `SKIP` out of the severity lattice, which fixed "clean repos look
skipped". It left both kinds inside one number, which said the same thing
more quietly: measured across 19 clones, 35 of 39 skips were deliberate, so
`portfolio-optimiser — OK · 11 not checked` announced eleven unread checks
when all eleven were fixture and out-of-repo links. org-ops named the split
in its census-05 report without a name for it.
The kind is set where the finding is emitted, never looked up from its code:
`VERSION-TAG` is emitted at `SKIP` with no tags and at `ERROR` with the wrong
one, so a code→kind map would have to re-derive a reason the emission site
already had. An untagged skip counts as `notRun` — the loud side, because a
skip of unknown kind must not inherit "deliberate, nothing to see".
### Changed
- **The summary line names only what someone has an action on.** A repo whose
every skip was deliberate prints an unqualified verdict; `· N not run`
appears only when N > 0. The deliberate ones are not silenced — the detail
output gained a `NOT JUDGED — deliberately outside what this gate decides`
heading beside `NOT CHECKED`. Landing the split in `--json` alone would have
left the human-facing symptom exactly where it was.
- `notChecked` is untouched: still present, still a **number**, still the total
of both kinds. A consumer doing `notChecked > 0` against an object would get
a silent false — the same class of quiet wrong answer this axis exists to
remove. Absent `skips` means an engine older than 0.8.0; absent `notChecked`
one older than 0.7.0. Neither absence is zero.
- `VERSION-UNAVAILABLE` stays `notRun` by decision, not by default. "No package
version to compare against" is arguably a third thing — no *subject* to
judge, the shape `checkReadmeLanguage` answers with `OK` rather than `SKIP`
but re-levelling it moves a repo's `status`, and that is a second behaviour
change. Recorded in the engine so the next reader knows it was decided.
- README example output cites `@<sha>` instead of a commit hash. Three releases
running, those examples went stale against the behaviour they demonstrate; a
placeholder cannot.
Verified before release: 169 tests; 19 clones swept with both engines offline,
220 judged findings and every `status`, `notChecked` and `buckets` identical,
with no finding differing beyond the new tag. The exhaustiveness test scans the
engine source rather than the finding set — a corpus test only sees the sites it
manages to trigger, and the next emission site added would inherit the reader's
default invisibly.
## [0.7.1] — 2026-08-09
### Fixed
- The skill told a reader what a `SKIP` finding means and stopped there, which
was complete before 0.7.0 and is not now: a repo can headline `OK · 3 not
checked`, and a session reporting only the status word would report a green
pass over three unjudged findings. `SKILL.md` now requires the status and the
count to be reported together. Shipping 0.7.0 without this made the plugin
whose purpose is catching stale published documents ship one.
- README's example output carried commits older than the behaviour they
demonstrate — one from 0.6.0 beside a `notChecked` that did not exist in it,
one two releases back. This repo's own invariant is that the version names a
file and only the sha names the code; the examples now cite `10ad125`, the
commit the feature actually shipped in.
### Added
- README states the unit of `notChecked`: it counts un-judged **findings**, not
checks. A repo with many links leaving it scores a high count without a single
check having failed to run, so the bare number reads worse than the repo is.
Named as a known limitation rather than corrected in the string — the fix is
splitting *deliberately not judged* from *could not run*, which is its own
release.
## [0.7.0] — 2026-08-09
### Changed
- **A repo's `status` is the worst *judged* finding, and `SKIP` only when
nothing was judged.** `SKIP` used to rank between `OK` and `WARN`, so one
un-runnable check spoke for every check that ran: a repo with 0 ERROR, 0 WARN
and a dozen `OK` headlined as "skipped". Reported by org-ops against five
repos in census 05 — `ktg-plugin-marketplace`, `okr`,
`playground-design-system`, `portfolio-optimiser`, `commons` — with `okr`
holding the most `OK` in the org and reading as unread. A skip is not a
severity; it is the absence of a verdict, and it cannot be the worst of a set
that contains real ones. "`SKIP` is never a pass" survives intact in the half
of the rule that keeps it: an unregistered repo, or an empty finding set,
still says `SKIP`, because there is nothing else to be worst of.
Measured across all 21 local clones from one saved sweep, so before and after
are computed from the *same* findings rather than from two sweeps of a moving
org: 343 findings before, 343 after, none added or removed. 8 repos moved,
every one `SKIP``OK`. The counts that decide whether a repo needs work did
not move at all — 1 `ERROR` before and after, 3 `WARN` before and after.
Consumers reading `.status` see a changed value domain: a repo that reported
`SKIP` in censuses 0307 may report `OK` from 08 on with an identical finding
set. Raw census files already carry `engineVersion` and `engineCommit`, which
is what distinguishes the two readings.
### Added
- `notChecked` beside `status`, in `--json` and as a `· N not checked` qualifier
on the summary line. Fixing the status alone would have traded "clean repos
look skipped" for "skipped checks look clean", which is the worse direction —
so coverage gets its own axis rather than being folded into the verdict, the
same split the engine already makes between a finding's level and its bucket.
The count is the number of `SKIP` findings, which is what the existing
`NOT CHECKED — these are not passes` section has always listed. An **absent**
`notChecked` means an older engine and prints the pre-0.7.0 line; it is not
zero.
## [0.6.0] — 2026-08-09
### Added
- `titles` in the register: an optional per-repo README title. Set, the H1 is
compared against it and a match is `OK`; unset, the `WARN` stands exactly as
before. A human title was already a valid choice — `docs/rds-v1.md` prescribes
`1. # Title` for every class, not `# repo-name` — but a decided YES had
nowhere to live, so the same 6 `README-H1` WARNs were reported in census 05,
06 and 07 and would have been reported forever. "We decided this is correct"
and "nobody has looked at it" now produce different outcomes. Five titles
registered, each H1 read from the repo rather than copied from the census;
`ai-psychosis` is deliberately left unregistered, so the one repo where a
reader cannot connect title to name stands alone. Measured across all 21
local clones: 6 WARN before, 1 after, no other finding moved.
- `engineCommit` alongside `engineVersion`, in the header line (short) and the
`--json` output (full). The version names a FILE; only the sha names the CODE.
A sweep stamped 18 raw files `0.4.0` while four carried findings from a check
that only exists in 0.5.0 — the feature and the version bump are two commits,
so the worktree held new code under an old number for a window, and the stamp
lied without being broken. Derived from this checkout, no network call. The
field is present-and-`null` when underivable, never absent: an absent key
means an older engine, an explicit `null` means this engine ran and had no
HEAD to read, and a consumer sorting raw files by stamp needs those to differ.
### Changed
- `README-DESC` no longer demands byte equality for the `org-profile` class,
via `readme_desc_match: false` on the class — data in the register, not a
hardcoded name. For an ordinary repo the README opening and the forge
description describe the same subject and equality is right; for this one
class they do not — the README is the organisation's landing page, the forge
text describes the repo. Both are correct about their own subject, so it is
the equality that does not apply. A landing page's opening line also carries a
markdown link while the description field renders as plain text, so passing
the old check would have meant putting raw markdown on a real surface. The
class has one member, so coverage is lost nowhere else, and the exemption is
still RECORDED as an `OK` finding naming the reason rather than dropped.
Measured: `.profile` went from `ERROR` to 0 ERROR / 0 WARN, and the same
README under a `plugin` class is still an `ERROR`.
## [0.5.0] — 2026-08-09
### Added
- `LINK-INTERNAL-FIXTURE`: a dead link inside a `test/`, `tests/`,
`fixtures/`, or `*golden*` path now reports as `SKIP` instead of `WARN`.
These paths are presumed to break their own links on purpose —
`nav-golden-escape/bundle/index.md`'s deliberate `../../../../etc/passwd`
escape pops the whole base path instead of resolving outside the repo, so
it read as a genuine dead link against three repos in the org. The finding
still fires with file and line; only the judgement changes. Measured
before shipping: 16 `LINK-INTERNAL-*` findings before, 16 after, across
all 20 local clones — every one converted 1:1, none disappeared.
## [0.4.0] — 2026-08-09
### Added
- `LINKS-OPEN-REFS`: the `open/` reference check now reports its own result
instead of only its failures. Emitting nothing on success made "no dead
references" and "the check never ran" identical in the output — a sweep
across the org could not tell 19 clean repos from 19 unread ones (measured:
org-ops census 03b). The OK line carries the count it resolved, because an
OK that cannot say how many it checked is the same silence in a different
colour. Zero enumerated files is now `LINKS-OPEN-REFS-UNAVAILABLE` (SKIP),
which is the honest name for the case that used to look like a pass.
- `portfolio-optimiser-commons` registered as `shared-asset`, the org's 20th
repo. Class verified structurally rather than accepted: absent from the
catalog's `marketplace.json`, no `.claude-plugin/`, `README.md` + `LICENSE`
present, consumed by both reference implementations as a `git subtree`
so `vendor` is the right install form and `## Install` would be wrong to
require. Its absence was producing three false `LINK-DEAD` ERRORs in
`portfolio-optimiser` against a repo that exists, and leaving repo #20 with
zero coverage. Verified after the fact: `portfolio-optimiser` now has no
ERROR, and the commons repo measures as WARN with 9 checks passed.
### Fixed
- `LINK-DEAD`/`LINK-NON-REPO` false negative on a schemaless host. `URL_REF`
required `://` or `@host:`, so `git.fromaitochitta.com/open/<name>` — the
form a subtree instruction routinely uses — resolved to nothing at all
(measured: llm-security/V3-UPGRADE.md:343). What makes a name resolvable is
its position after a host, not the scheme in front of it. Two guards keep
the widening from becoming noise: the host must end in a TLD-shaped label,
and a candidate preceded by `/` is a path segment that merely contains a
dot, not a host — so `docs/v1.2/open/` and `test/nav.golden/open/` stay
silent, and the API-endpoint rule from 0.3.0 is untouched. Measured before
shipping across 1501 tracked Markdown files in 20 local clones: 14 lines
changed verdict, 13 of them references that were previously invisible.
- The 14th was a defect the widening introduced, caught by that same
measurement and fixed here: a markdown link whose display text repeats its
own URL matched on both halves, which prints one dead reference twice and
inflates the count the new OK line offers as evidence. References are now
deduplicated per name-and-line — two different names on one line, or the
same name on two lines, still count as two.
## [0.3.0] — 2026-08-04
### Added
- `BADGE-DEAD-LINK`: a linked badge making a run claim ("tests", "build",
"CI", "passing") is now resolved against the repo's tracked files when the
link target is relative. Being wrapped in a link previously ended all
scrutiny — the link-target capture group was missing from the regex
outright, so a badge linked to a dead relative path passed silently.
External targets (the ordinary case — a CI provider) still need the
network and stay out of scope, same precedent as `checkInternalLinks`.
### Fixed
- `LINK-DEAD` false positive on API endpoint paths: `URL_REF` matched
`open/<name>` anywhere in a URL, so a Forgejo API call like
`.../api/v1/orgs/open/repos` read as a dead reference to a repo named
"repos". `open` must now be the first path segment after the host,
matching how every real repo URL is shaped. Measured twice against the
catalog's own `RUNBOOK.md`.
- 429 backoff was tuned for a hard IP ban that does not exist. Measured
directly against the live forge: nginx never sends `Retry-After` (the
branch handling it is dead code in practice), the limit is a leaky bucket
that can take up to ~15s to drain, and it is IP-based rather than
token-quota-based — a valid token made no difference. `fetchWithRetry` now
defaults to a 23s worst-case budget (`retries: 5`, `maxDelayMs: 8000`), up
from 7s. `CLAUDE.md`'s "13 calls in a loop" explanation corrected to match.
- Two tests asserted facts about their own local test fixture instead of the
real `register/repos.json` — a typo in the real register would have
drifted past them silently. Both now read the live register via
`loadRegister()`.
## [0.2.2] — 2026-08-04
### Fixed
- The engine never printed its own version, which is how a stale plugin cache
went unnoticed: two repos independently proved the `/repo-standard` skill
had resolved `${CLAUDE_PLUGIN_ROOT}` to a cached `0.1.1` while `0.2.0` was
installed and the catalog pinned it — same instruction, wrong engine, and
`0.1.1` has neither `BADGE-COUNT` nor `README-LANGUAGE`, so the run looked
clean instead of incomplete. The header line and `--json` output now both
carry `repo-standard v<version>`; `SKILL.md` tells the reader to confirm it
against the catalog pin before trusting a green result. The cache
resolution itself is the harness's, not this repo's, and is not fixed here.
## [0.2.1] — 2026-08-04
### Fixed
- The gate makes two anonymous forge calls per invocation (org listing +
catalog `marketplace.json`), not one — this repo's own `CLAUDE.md` said
"one" from before `INSTALL-TRUTH` added the second, and stayed wrong long
enough that a 13-repo shell loop trusted the count and tripped an HTTP 429
at 26 requests. Both calls now go through `fetchWithRetry`, which honors
`Retry-After` and retries instead of silently reporting `SKIP` on a
transient rate limit. `CLAUDE.md` corrected to match.
## [0.2.0] — 2026-08-04
### Added
Two presentation checks, both from adversarially-verified research rather than
taste — `docs/presentation-research-2026-08-03.md` records what the evidence
supports and, more usefully, what it refuses to support.
- `BADGE-COUNT` (`WARN`) — more than 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 without CI or p-value, so it carries "more is
not better" and cannot carry a hard limit. Counting uses a narrower rule than
the existing claim check — a screenshot or architecture diagram must not be
counted as clutter. Measured: 8 of 18 `open/` repos are past it.
- `README-LANGUAGE` (`WARN`) — the prose is not in the language this repo's
readers were declared to speak, via a new `locales` axis in the register.
English is the default; `ms-ai-architect` and `okr` are declared `nb` as
Norway-only in audience. Detection is a stopword-frequency comparison over
prose with code stripped, so a Norwegian flag name in a shell example cannot
decide the document. Evenly bilingual prose is a `SKIP` — the question is
live and unanswered. No running prose is an `OK`: nothing claims a language,
and a thin README is `checkFirstScreen`'s business. Measured: fires on
exactly the two declared repos, silent on all sixteen English ones.
Deliberately **not** built, because the evidence does not reach: any rule about
images, diagrams, screenshots or terminal recordings (every such claim was
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's actual
limit is not readable via the API, so any threshold would be a guess).
### Changed
- The skill now carries diagram guidance, deliberately as judgement and not as a
check. Mermaid is verified to render on this forge; that is capability, not
justification, and every claim that visuals improve a README was refuted. What
the guidance covers is a diagram that already exists — height, node labels,
the silent degradation past `MERMAID_MAX_SOURCE_CHARACTERS`, and the fact that
`#gh-dark-mode-only` is unavailable below Gitea 1.26.0. The org's own measured
example renders at 1,459 px and wraps node text mid-word while its neighbour
sits at 191 px: rendering and rendering well are separate questions.
## [0.1.3] — 2026-08-03
### Fixed
Three more measured false positives, all reported via coord the same day
0.1.2 shipped, from repos running the gate for the first time.
- `extractChangelogTop` truncated a PEP 440 pre-release (`0.5.0a2`) to `0.5.0`,
so `VERSION-CHANGELOG` disagreed with `VERSION-TAG` — which compares the
untruncated tag and does not have this problem — over a version the manifest
and the tag already agreed on. Reported by `llm-ingestion-okf` with a
repro. An affected repo could reach 0 ERROR only by lying about its version;
now the pre-release suffix is kept.
- `BADGE-STATIC-CLAIM` treated a bare `status` badge (`status-alpha`,
`status-experimental`) as a run claim, the same as `tests-34-passing`.
A self-declared maturity label asserts no run — the same class as version,
licence and platform, already exempt. Reported by
`llm-ingestion-pipeline-security`. `build`/`ci`/`passing` still catch the
run-asserting compounds ("build status", "CI status"); only the bare word
is dropped.
- `BOILERPLATE` flagged a bare `FIXME` even when it named the *convention*
rather than an instance of it — a scanner's own docs describing what it
detects ("Flag TODO/FIXME markers…", a table row listing "TODO/FIXME
comments" as a finding type) read the same as a forgotten marker. Reported
by `config-audit`, whose product literally is a marker scanner. "TODO/FIXME"
named together is now read as the convention; a lone `FIXME` is still
caught.
## [0.1.2] — 2026-08-03
### Fixed
- `checkInternalLinks` compared a link's resolved target only against
`present` — the set of tracked *files* — so a link to a directory
(`[x](dir/)`) was reported `LINK-INTERNAL-MISSING` even when every file
under that directory was tracked. A directory was never a member of that
set to begin with. Reported by `portfolio-optimiser-claude` (coord
20260803T194933Z) with a minimal repro; confirmed and traced to the same
defect in `voyage`, `linkedin-studio` and `portfolio-optimiser` — 12 of the
71 ERROR findings measured across the org on 2026-08-03 were this one check,
not twelve separate repo problems. Fixed by deriving the set of directories
that actually contain a tracked file from `present` itself, and letting a
link that resolves to one of them pass.
## [0.1.1] — 2026-08-03
Documentation only. No behaviour change: `scripts/` and `register/` are
unchanged from 0.1.0 — this release carries version strings and the correction
below.
### Fixed
- The 0.1.0 entry said the gate has **eleven** checks. It has twelve, which is
what both the code and the README table already said. The entry is corrected
in place, and this release exists so the catalog's pinned tag serves the
corrected text instead of the wrong count. The count is drift of exactly the
kind this plugin was built to catch, and it was sitting in the plugin's own
repository.
## [0.1.0] — 2026-07-27
First release. Covers the checks that a single repository can answer on its own.
### Added
- **The gate** (`scripts/repo-standard-check.mjs`) — pure classifiers with all
I/O resolved into their input, findings tagged `ERROR`/`WARN`/`SKIP`/`OK`,
exit 1 on `ERROR`. Twelve checks: README first screen, install block, install
truth, required headings, files required by the repo's class and traits,
`open/<name>` references, relative links, licence claim, badges, boilerplate,
version consistency and description length.
- **Taxonomy register** (`register/repos.json`) — one central file mapping each
repository to its class, plus the per-class file and install requirements.
`--refresh` compares it against the live org listing.
- **Three-outcome reference check** — "matches no repository" (`ERROR`) is a
separate finding from "matches something that is deliberately not a
repository" (`WARN`). Sharing an outcome would let real dead links hide among
correct text. Only names in URL position are treated as references; the `.git`
suffix is normalised first.
- **Two-axis findings** — every `ERROR`/`WARN` carries a **bucket** alongside its
level: `broken` (a stranger is blocked or misled), `missing` (an expected
artefact is absent), `weakening` (present, but it reads as amateur). Output is
grouped by bucket, because that is the order findings get acted on.
- **Traits, a second axis beside class** — class is structural and readable off
the catalog; a trait is about what the code does. `security` attaches a
`SECURITY.md` requirement and a `## Known limitations` section.
- **Required README headings per class** — `## Install`, `## Non-goals`,
`## Changelog`. A heading present at the wrong depth is its own finding, not
"missing".
- **In-repo version consistency** — manifest, README version badge, newest
CHANGELOG entry and the git tag must agree. An untagged repo `SKIP`s the tag
comparison rather than failing it.
- **Badge honesty** — a static badge asserting a test, build or coverage run is
a claim dressed as evidence. Version, licence and platform badges assert no
run and are fine.
- **Install truth, not just install syntax** — the marketplace URL in the install
block must be the real one (offline, against the register), and the plugin must
actually be pinned in the catalog (one call; `SKIP` if unreachable). A perfectly
formed `claude plugin install x@mkt` fails silently when `x` was never pinned,
and that is the single most disqualifying thing a repo can publish.
- **Boilerplate, licence-claim and relative-link checks.**
- **The skill** (`skills/repo-standard/`) — the judgement the script cannot
encode: what a description should say, why the summary card must never be used
to verify one, what not to retrofit, and where the per-repo boundary is.
- **Link level follows the reader.** A dead relative link in a root document —
README, CHANGELOG, SECURITY — is an `ERROR`: it is in the shop window. The same
link below the root is a `WARN`. Measured across seventeen repositories: 30 of
43 findings sat in `shared/`, `docs/plan/` and `.claude/` — session plans,
agent working files, and path-traversal test fixtures whose targets are invalid
on purpose. All 30 were `ERROR`s, which is how a gate gets switched off. Only
the level moves; every finding is still reported with its file and line.
- **The repo name comes from the remote, not the directory.** `catalog/` is the
working directory of the repo named `ktg-plugin-marketplace`. Reading the
basename left it `REPO-UNREGISTERED` with zero checks run — against the one
repo every catalog rule depends on. The scp form the forge's clone button hands
out is handled, and a bare host is not a repo name.
- 84 tests over the pure classifiers, using measured false positives as
reference fixtures.
### Notes
- Descriptions are measured in **codepoints** — not bytes, and not UTF-16 units.
The same string measures 248 / 249 / 253 across those three yardsticks when it
contains an astral character.
- `enabledPlugins` in `settings.json` is treated as a legitimate second install
form. The gate requires a CLI command *as well*, and never reports the JSON
form as the defect.
- Two network calls, both anonymous: the org listing and the catalog manifest.
Per-repo fetching trips the forge's rate limiter, so neither is ever done per
repository. `--offline` skips both, and the checks that needed them report
`SKIP` rather than passing.
- `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` and `MAINTAINERS.md` are required by
no class: the project is solo-maintained and publishes that stance. This is
not a rule against having them — files already present are a cleanup decision,
not a gate finding. `SECURITY.md` is unaffected; it exists for the outsider who
finds a hole.
- There is no CI badge because there is no CI: the forge has no Actions runner
registered. The substitute is one command from a clean clone, stated honestly.
A badge asserting the test count would be the very anti-pattern the gate flags,
and an earlier draft of this README carried exactly that.
- The link and boilerplate checks ignore fenced blocks and inline code spans.
Documentation about regexes and placeholders is full of text that is a markdown
link to a naive scanner — the first version produced about thirty findings
against a real repository and every one was noise.
- Relative links resolve against the file they appear in, not the repo root.
- Indented text counts as a code block only when a blank line opens it, and then
continues while the indent holds. The first rule alone made links inside nested
list items invisible; the second alone let everything after a block's first line
leak back in. Both were silent false passes, which is worse than noise — the
second was caught by the gate on this plugin's own SKILL.md.
- A README H1 that differs from the repo name is a `WARN`, not an `ERROR`. The
thread that has to hold is description == catalog == opening line, and the H1
is none of those three; a human title is a naming choice the operator owns.
A missing H1 is still an `ERROR`.
- No hook ships in this release. A blocking gate has to be precise enough not to
fail a correct repository first.
[0.2.0]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.2.0
[0.1.3]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.3
[0.1.2]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.2
[0.1.1]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.1
[0.1.0]: https://git.fromaitochitta.com/open/repo-standard/src/tag/v0.1.0