feat(gate): install truth, honest badges anywhere, and two stripCode bugs

Install truth is the brief's first control and the gate only checked
syntax. Now: the marketplace URL must be the real one (offline, from the
register), and the plugin must actually be pinned in the catalog (one
call, SKIP if unreachable). A well-formed `claude plugin install x@mkt`
fails silently when x was never pinned.

This makes the gate block ITSELF until publication finishes - the run
against this repo now has exactly one ERROR, and it is true: repo-standard
is not in the catalog yet. That is the post-publish acceptance test,
enforced mechanically instead of remembered.

Badge honesty no longer keys on img.shields.io. A self-hosted SVG asserts
the same unverified thing, and the README claimed the general rule while
the code checked one host.

Two stripCode bugs, both silent false passes:
- 4-space indent treated as code unconditionally made links inside nested
  list items invisible. Fixed by requiring a blank line to OPEN a block.
- That fix alone ended the block after line 1, so multi-line indented
  templates leaked back into scanning. Caught by the gate on this repo's
  own SKILL.md, which shows a README template containing a CHANGELOG link.
A block now opens on a blank line and continues while the indent holds.

Also corrected two claims in this README: it said "one network call"
when there are two, and it still argued against a CONTRIBUTING using
reasoning the solo-maintainer section had already replaced.

77 tests. llm-security regression: still zero link and boilerplate noise.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYJ3FHLtVgzFXMZ6UF598h
This commit is contained in:
Kjell Tore Guttormsen 2026-07-27 16:13:17 +02:00
commit 6b1db0096e
5 changed files with 187 additions and 16 deletions

View file

@ -24,6 +24,7 @@ import {
checkLicenseClaim,
checkInternalLinks,
resolveRelative,
checkInstallTruth,
classifyRepo,
levelOf,
} from './repo-standard-check.mjs';
@ -408,6 +409,7 @@ test('a fully compliant plugin repo classifies OK', () => {
readmeBadge: '0.7.0',
changelogTop: '0.7.0',
tags: ['v0.7.0'],
catalogNames: ['repo-mailbox'],
},
REGISTER,
);
@ -694,3 +696,84 @@ test('a nested link to a genuinely absent sibling is still an ERROR', () => {
});
assert.equal(f.some((x) => x.code === 'LINK-INTERNAL-MISSING'), true);
});
// ------------------------------- stripCode must not swallow nested list items
test('a link inside a nested list item is still scanned', () => {
// An indented line is only a code block when a blank line precedes it.
// Treating every 4-space indent as code made nested bullets invisible to both
// the link and boilerplate checks — a silent false pass, which is worse than
// the noise it was meant to remove.
const text = ['- top level', ' - nested with [a link](gone.md)'].join('\n');
const f = checkInternalLinks({ files: { 'README.md': text }, present: ['README.md'] });
assert.equal(f.some((x) => x.code === 'LINK-INTERNAL-MISSING'), true);
});
test('a genuine indented code block is still skipped', () => {
const text = ['Example:', '', ' curl [x](not-real.md)'].join('\n');
const f = checkInternalLinks({ files: { 'README.md': text }, present: ['README.md'] });
assert.equal(f.filter((x) => x.level === 'ERROR').length, 0);
});
// ------------------------------------------ badge honesty beyond shields.io
test('a self-hosted badge asserting a run is caught too', () => {
const f = checkBadges({ readme: '![Tests](https://example.com/static/tests-34-green.svg)' });
assert.equal(f.some((x) => x.code === 'BADGE-STATIC-CLAIM'), true);
});
// ------------------------------------------------------------ install truth
test('the marketplace URL in the install block must be the real one', () => {
const readme = [
'## Install',
'claude plugin marketplace add https://git.fromaitochitta.com/open/WRONG.git',
`claude plugin install repo-standard@${MKT.name}`,
].join('\n');
const f = checkInstallBlock({ readme, name: 'repo-standard', klass: 'plugin' }, REGISTER);
assert.equal(f.some((x) => x.code === 'INSTALL-URL-MISMATCH' && x.bucket === 'broken'), true);
});
test('a plugin absent from the catalog has an install line that cannot work', () => {
// Syntax is not truth. The brief's first control asks whether the command
// works for a stranger, not whether it is well-formed.
const f = checkInstallTruth({ name: 'ghost', klass: 'plugin', catalogNames: ['repo-mailbox', 'llm-security'] });
assert.equal(f.some((x) => x.code === 'INSTALL-NOT-IN-CATALOG' && x.bucket === 'broken'), true);
});
test('a plugin present in the catalog passes install truth', () => {
const f = checkInstallTruth({ name: 'repo-mailbox', klass: 'plugin', catalogNames: ['repo-mailbox'] });
assert.equal(f.filter((x) => x.level === 'ERROR').length, 0);
});
test('an unreachable catalog is SKIP, never a pass', () => {
const f = checkInstallTruth({ name: 'repo-mailbox', klass: 'plugin', catalogNames: null });
assert.equal(f[0].level, 'SKIP');
});
test('non-plugin classes are not measured against the catalog', () => {
const f = checkInstallTruth({ name: 'portfolio-optimiser', klass: 'standalone', catalogNames: null });
assert.equal(f.filter((x) => x.level !== 'OK').length, 0);
});
test('an indented code block stays code past its first line', () => {
// The blank-line rule fixed nested lists but broke multi-line indented blocks:
// only line 1 followed a blank line, so lines 2+ leaked back into scanning.
// Caught by the gate on this plugin's own SKILL.md, which shows a README
// template containing a link that does not exist relative to that file.
const text = [
'Template:',
'',
' # <name>',
' ## Changelog',
' See [CHANGELOG.md](CHANGELOG.md).',
].join('\n');
const f = checkInternalLinks({ files: { 'skills/x/SKILL.md': text }, present: ['skills/x/SKILL.md'] });
assert.equal(f.filter((x) => x.level === 'ERROR').length, 0);
});
test('an indented block ends at the first unindented line', () => {
const text = ['Template:', '', ' code here', '', 'Back to prose with [a link](gone.md).'].join('\n');
const f = checkInternalLinks({ files: { 'README.md': text }, present: ['README.md'] });
assert.equal(f.some((x) => x.code === 'LINK-INTERNAL-MISSING'), true);
});