"No ungated ref has moved since its audit" only proves the badge source is
unchanged. Catalog prose is itself ungated, so an ungated stat value could have
been restated by any commit with nothing catching it — which would have made
the no-re-measurement justification false.
Checked by diffing extractCatalogStats against README.md at db1e80b (08-02):
the only ungated numbers the catalog has restated since are repo-standard's two,
absent then and measured 08-04. The claim holds; it is now stated as a two-sided
verification rather than a one-sided inference.
Sharpens the 251-selftest-checks flag with what that diff also showed: the
catalog's own 08-02 stat line already said 370, so two independent records agree
on 370 and check-versions.mjs's 374 reads as a transcription slip.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PtnSwCLpUR3Hk8SHkPoxX4
6.5 KiB
6.5 KiB
ktg-plugin-marketplace (catalog)
Catalog repository for the ktg-plugin-marketplace. After the polyrepo migration this repo hosts only
the marketplace manifest and the catalog-level docs; every plugin and the shared design-system live in
their own Forgejo repositories under https://git.fromaitochitta.com/open/.
What lives here
.claude-plugin/marketplace.json— the marketplace manifest (plugin entries point at external repos)README.md— the landing/catalog pageCONVENTIONS.md— marketplace-wide conventions inherited by every plugin repoGOVERNANCE.md— governance + fork-and-own model.mailmap,.gitleaks.toml,.gitleaksignore— shared git-hygiene baselines
Catalog maintenance
- Marketplace conventions: see CONVENTIONS.md.
- Adding/updating a plugin entry: edit
.claude-plugin/marketplace.json(externalsource: "url"with a pinnedref) and re-state the plugin in README.md with its verified version. - Plugin source, issues, and releases live in each plugin's own repository — not here.
- Releasing a plugin (canonical path —
scripts/release-plugin.mjs): since the polyrepo split, a release is a TWO-repo act — tag the plugin repo AND bump the catalogref. Forgetting the second step strands users on the old version (the exact drift this helper exists to prevent). Runnode scripts/release-plugin.mjs <plugin> [--version X.Y.Z]— dry-run by default; it REFUSES unlessplugin.json== README badge == the target version AND thevX.Y.Ztag exists, then prints the planned bump. Apply with--write [--commit] [--push];--create-tagmints+pushes a missing plugin tag first. On--writeit bumps the catalogrefAND the catalog README's per-plugin`vX.Y.Z`label together (andgit adds both on--commit). Because it only moves both to a verified, tagged, consistent version,check-versions.mjsis green by construction. Never hand-edit arefor a README label for a release — use this. Pure planner + label reconciler covered byscripts/release-plugin.test.mjs. - Version-consistency gate: run
node scripts/check-versions.mjsbefore committing anyrefchange. For each plugin it checks (against the sibling repo) that the catalogrefresolves to a real git tag (ERROR if dangling — breaks install), thatplugin.jsonversion == README version-badge (ERROR), that the catalog README's per-plugin`vX.Y.Z`label == the catalogref(ERROR — the human-facing doc must not misstate the installed version), and that the catalogrefmatchesplugin.jsonversion (WARN — catalog lags or an unreleased bump). Exit 1 on any ERROR;--strictalso fails on WARN. Pure-function core covered byscripts/check-versions.test.mjs(node --test scripts/check-versions.test.mjs). - Stat-badge mirroring (part of the same gate): each plugin block in the catalog README ends in a
stat line (
7 agents · 16 scanners · 21 commands · 1398 tests · [Full documentation →]). The gate compares every number on that line against the plugin's own shields badge for the same axis, and ERRORs when they disagree — the catalog must not overstate a plugin. The rule is per-AXIS, not per-plugin: an axis the plugin does not badge is skipped silently, so there is no exception list to maintain. Re-measured 2026-08-04 at the pinned refs, all 12 plugins: 42 catalog axis-claims — 27 badge-covered · 15 badge-less across 7 of the 12 plugins and therefore ungated. That supersedes the 2026-08-02 reading (24 · 15 across 7 of 11); only two entries moved in between and both reconcile exactly — repo-mailbox now badges the two axes it did not (+2gated,-2ungated) and repo-standard entered the catalog (+1gated,+2ungated). The 15 ungated axes were hand-audited at their pinned tags — 13 on 2026-08-02 (14 of that pass's 15 were exact; the defects were repo-mailbox6 CLI scripts(true 8) /251 selftest checks, and voyage500+ testsagainst a measured 832), and repo-standard's two on 2026-08-04. Every ungated value currently stands measured at the ref it is pinned to — verified on both sides 2026-08-04, because a ref that has not moved only proves the badge source is unchanged and catalog prose is itself ungated: no ungated plugin's ref has moved since its audit, and diffingextractCatalogStatsagainst the 08-02 README shows the only ungated numbers the catalog has restated since are repo-standard's two (absent then). ⚠️ The251 selftest checkscorrection is not fully settled, though the weight is on 370: this file and the catalog's own 08-02 stat line both record the axis as corrected to 370,check-versions.mjssaid 374 (most likely a transcription slip), and repo-mailbox's README at v0.19.0 implies 390 (183 + 134 + 73) — its own prose being ungated too. Moot for the gate (they badge the axis now, 398 at v0.20.2, green) and not re-measured. It stands as the proof of the cost: an ungated number rots, and so does the record of having fixed it.N+in the catalog is read as a lower bound, not an equality, so500+was never gate-visible — ungated axes rot in silence and need a re-run of this pass whenever a ref moves. Never hand-edit a stat line to silence the gate — the plugin's badge is the source for every stat number; fix the catalog to match it. - Counting rules for a badge-less axis (calibrated against the badged plugins, 2026-08-02). When
the catalog must count an axis itself, count it the way the badges do, or the numbers stop being
comparable across plugin blocks: hooks = hook COMMAND entries in
hooks/hooks.json(not events, not matchers — the three diverge, andcommandsis what matched the badge on all 6 badged plugins), and tests =ℹ testsfromnode --test, notℹ pass(config-audit's badge 1398 is itstestscount;passwas 1375). Measure in an extraction of the tag (git archive <ref> | tar -x -C <tmp>), never the sibling working tree. - The stat mirror reads the plugin README AT THE PINNED
ref, never the sibling working tree. The catalog documents what installs, and that is the tag. A plugin that commits past its tag without bumping its version — measured 2026-08-02 on both llm-security (scanners 23→22, tests 2013→2034) and config-audit (tests 1398→1441) — would otherwise make the gate demand that the catalog restate unreleased numbers, which is exactly backwards. When the gate flags a stat, checkgit show <ref>:README.mdin the plugin repo before believing the working tree.