ktg-plugin-marketplace/CLAUDE.md
Kjell Tore Guttormsen 780f86ec9f fix(check-versions): mirror stats against the pinned ref, not the working tree [skip-docs]
Found live minutes after shipping fc95cbd: llm-security went ERROR on scanners
(23 vs 22) and tests (2013 vs 2034). The catalog was RIGHT and the gate was
wrong. llm-security had committed past its v7.8.3 tag without bumping the
version, and the gate was reading the sibling working tree — but the catalog
documents what INSTALLS, and `ref: v7.8.3` still installs 23/2013.

Stat badges are now read with `git show <ref>:README.md`, falling back to the
working tree only when the ref cannot be read (a ref resolving to nothing is
already its own ERROR, so the fallback cannot hide a dangling ref). The
version-badge check is unchanged and still reads the working tree: that one is
about the plugin's internal consistency, not about what the catalog promises.

This also corrects a stat I got wrong in fc95cbd. I had moved config-audit from
1410 to 1441 tests off the working tree; at the pinned v5.13.0 the badge says
1398. 1441 is unreleased. The catalog now says 1398 — what installs.

[skip-docs]: CLAUDE.md carries the rule and the "check `git show <ref>:README.md`
before believing the working tree" instruction; README.md changes by one number
because the gate was wrong about it.

Tests 117 -> 120 (+3, all regression). Gate green at 11 OK / 0 WARN / 0 ERROR.

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

55 lines
4.3 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 · 1441 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. Measured 2026-08-02: 21 axis-pairs are badge-covered, and **14 axes across 8 of the 11
plugins are badge-less** and therefore ungated — those numbers still rot and need a human pass
(repo-mailbox's read `6 CLI scripts` / `251 selftest checks` against a true 8 / 374). `N+` in the
catalog is read as a lower bound, not an equality. **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.
- **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.**