feat(engine): VERIFY-COMMAND — the one command a stranger has instead of CI

The forge has no Actions runners, so this org publishes no CI badge; the
stated substitute is one command runnable from a clean clone. A repo with
something runnable and no such command in its README is a WARN — and the
finding names what the repo already has, so the remedy is one line.

The subject is MEASURED, never read off a class. Five of 21 clones have
nothing runnable at all and answer VERIFY-NONE at OK; they span plugin,
shared-asset AND standalone, so every class-level phrasing of this rule
would fail a correct repository somewhere. Measured: 10 document a
command, 6 do not, 5 have no subject.

Two things bound the rule. It adds no API call, so it has no SKIP at all
— copying the null-input guard from every check since PIN-DEAD would
print a false "not run". And it runs nothing, so its OK says documented,
never passing.

Not built, with distinct reasons recorded as invariants: RELEASE-ASSETS
is rejected permanently for having NO SUBJECT (0 of 21 READMEs mention an
asset download; the 18/18 fire rate is a proxy and must not be quoted as
the reason). TAG-SIGNED is BLOCKED ON AN OPERATOR DECISION, not rejected
— filing it with the rejections would read as settled when it is one
yes/no from acquiring its whole subject.

Also fixes this repo's own surface, which had drifted behind its engine:
four checks had shipped without a row in the README check table, and
Requirements still said "two network calls" after the third was added.

230 tests (from 213).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwZeAZ8cHmGZofM9dryuT9
This commit is contained in:
Kjell Tore Guttormsen 2026-08-12 23:21:34 +02:00
commit e00ed3340c
7 changed files with 449 additions and 14 deletions

View file

@ -271,13 +271,54 @@ would recreate, in data, exactly the drift this plugin exists to remove.
repo with a correct manifest is invisible to `VERSION-TAG`. Recorded
rather than deferred: a decision that is wrong is worse than no record, and
the next session should not re-derive this measurement.
- **`RELEASE-ASSETS` is rejected permanently, and the reason is NO SUBJECT — not
the fire rate.** All 18 releases in the org carry no assets, but that number is
the weaker half of the measurement. The other half: **0 of 21 READMEs mention
an asset download at all** — no `releases/download` link, no tarball, nothing.
Every install path in this org goes through `marketplace add`, `plugin
install`, `pip`/`uv`, or a clone. So there is no reader who is harmed and no
remedy anyone would perform. That is a stronger rejection than VERSION-DRIFT's,
which was "fires on repos following the other legitimate convention"; this one
has no convention on either side because it has no subject. Do not re-derive
it from "18/18" alone — the fire rate is a proxy, and reasoning from the proxy
is what would resurrect this check the first time one repo publishes an asset.
- **`TAG-SIGNED` is BLOCKED ON AN OPERATOR DECISION, not rejected — and filing it
with the rejections is the error to avoid.** 0 of 18 repos sign their tags
today, which looks like the same measurement that killed VERSION-DRIFT and is
not: if the operator decides this org signs tags, the check acquires its whole
subject the same day. A rejection is permanent; this is one yes/no away.
Recorded here so the next session reads a pending question instead of
re-measuring a settled one. The scope is also fixed in advance: `git cat-file
tag` reads the signature block from the clone, so the check can answer *is it
signed* and must never claim *the forge vouches for it* — the forge's
"Verified" badge needs a key registered there.
- **A gate whose subject varies per repo MEASURES the subject; it does not read
it off the class.** `VERIFY-COMMAND` fires only where something runnable
exists (`scripts.test`, or a tracked executable test file), and answers
`VERIFY-NONE` at `OK` where nothing does. The five subject-less repos —
human-friendly-style, llm-security-commons, playground-design-system,
portfolio-optimiser-commons, app-creator — span `plugin`, `shared-asset` AND
`standalone`, so every class-level phrasing of this rule fails a correct
repository somewhere. The rate is fine (6 of 21 `WARN`) for a reason that must
travel with the rule: the org publishes exactly ONE stance on verification
("no CI badge, so one command from a clean clone"), so an undocumented suite
is not a second convention the way bump-first vs bump-at-release was for
VERSION-DRIFT. And the check runs nothing, so its `OK` says *documented*,
never *passing* — a green line implying a passing suite would be a claim on
the surface that nobody verified.
- **The check table in the README is part of the surface it measures.** Four
checks shipped without a row (`PIN-DEAD`, `TAG-ANNOTATED`, `RELEASE-CURRENT`,
`REMOTE-SYNC`), and the Requirements section still said "two network calls"
after the third was added — the same stale-count defect the invariant above
warns about, one file over, on the README of the repo whose entire job is
presentation. A new check is not shipped until its row exists.
- **No hook until the rule is precise.** A blocking gate that fails a correct
repository is the mechanism that gets gates switched off.
## Commands
```bash
npm test # 213 tests
npm test # 230 tests
node scripts/repo-standard-check.mjs --dir "$PWD" # gate one repo
node scripts/repo-standard-check.mjs --offline # no network call
node scripts/repo-standard-check.mjs --json # machine output