"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
79 lines
6.5 KiB
Markdown
79 lines
6.5 KiB
Markdown
# 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 page
|
||
- `CONVENTIONS.md` — marketplace-wide conventions inherited by every plugin repo
|
||
- `GOVERNANCE.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` (external `source: "url"` with
|
||
a pinned `ref`) 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 catalog `ref`. Forgetting the second
|
||
step strands users on the old version (the exact drift this helper exists to prevent). Run
|
||
`node scripts/release-plugin.mjs <plugin> [--version X.Y.Z]` — dry-run by default; it REFUSES unless
|
||
`plugin.json` == README badge == the target version AND the `vX.Y.Z` tag exists, then prints the
|
||
planned bump. Apply with `--write [--commit] [--push]`; `--create-tag` mints+pushes a missing plugin
|
||
tag first. On `--write` it bumps the catalog `ref` AND the catalog README's per-plugin `` `vX.Y.Z` ``
|
||
label together (and `git add`s both on `--commit`). Because it only moves both to a verified, tagged,
|
||
consistent version, `check-versions.mjs` is green by construction. Never hand-edit a `ref` or a
|
||
README label for a release — use this. Pure planner + label reconciler covered by
|
||
`scripts/release-plugin.test.mjs`.
|
||
- **Version-consistency gate:** run `node scripts/check-versions.mjs` before committing any `ref`
|
||
change. For each plugin it checks (against the sibling repo) that the catalog `ref` resolves to a
|
||
real git tag (ERROR if dangling — breaks install), that `plugin.json` version == README
|
||
version-badge (ERROR), that the catalog README's per-plugin `` `vX.Y.Z` `` label == the catalog
|
||
`ref` (ERROR — the human-facing doc must not misstate the installed version), and that the catalog
|
||
`ref` matches `plugin.json` version (WARN — catalog lags or an unreleased bump). Exit 1 on any
|
||
ERROR; `--strict` also fails on WARN. Pure-function core covered by
|
||
`scripts/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 (`+2` gated, `-2` ungated) and
|
||
repo-standard entered the catalog (`+1` gated, `+2` ungated). 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-mailbox `6 CLI scripts` (true 8) / `251 selftest checks`, and voyage `500+ tests` against 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** diffing `extractCatalogStats` against the 08-02 README shows
|
||
the only ungated numbers the catalog has restated since are repo-standard's two (absent then).
|
||
**⚠️ The `251 selftest checks` correction 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.mjs` said 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, so `500+` 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, and `commands` is what matched the badge on all 6 badged
|
||
plugins), and **tests = `ℹ tests` from `node --test`**, not `ℹ pass` (config-audit's badge 1398 is
|
||
its `tests` count; `pass` was 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,
|
||
check `git show <ref>:README.md` in the plugin repo before believing the working tree.**
|