The 2026-08-02 reading (24 gated / 15 ungated across 7 of 11 plugins) predated
repo-standard entering the catalog and repo-mailbox badging its two remaining
axes. Re-measured 2026-08-04 at every pinned ref with the gate's own parsers:
42 catalog axis-claims, 27 badge-covered, 15 badge-less across 7 of 12 plugins,
source=ref for 12/12. The two readings reconcile exactly (24+3, 15-2+2).
Two premisses corrected while measuring:
- graceful-handoff has NOT lost its tests/hooks badges. Both badge-removing
commits are unreleased (after v3.1.0), so at the pinned ref the catalog's
"30 tests" is gated. Recorded at pickStatSource as the opposite failure
direction to the llm-security case: reading the worktree misreports COVERAGE,
not just values, and neither example alone would have caught it.
- the "251 selftest checks" correction is not settled: CLAUDE.md said 370,
check-versions.mjs said 374, and repo-mailbox's own README at v0.19.0 implies
390. Moot for the gate (badged and green at v0.20.2) and not re-measured, so
the disagreement is flagged rather than laundered into one number.
Badge-less VALUES were not re-audited this session and do not need to be: only
two refs have moved since their audit, so all 15 stand measured at the ref they
are pinned to. Re-measurement is triggered by a ref moving, not by the calendar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PtnSwCLpUR3Hk8SHkPoxX4
The ref moved v0.2.0 -> v0.2.2 in f71d2ca; the stat line was still the v0.1.1
measurement. Both axes are badge-less, so the catalog counts them itself,
measured in a git-archive extraction of the tag per CLAUDE.md:
checks = 14 (rows in repo-standard's own check table, README.md:61-74;
v0.2.0 added Badge count + README language to the 12)
tests = 111 (npm test at v0.2.2 -> node --test scripts/*.test.mjs,
'i tests 111', 111 pass / 0 fail)
Their README prose says '103 tests over the pure classifiers' -- a deliberately
scoped subset, not the suite count. Every other catalog block's tests axis is
the full suite, so 111 keeps the blocks comparable. Reported to repo-standard.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HKBG8WVnkUxmTPffjTAdZ8
repo-standard v0.2.2 — release. Catalog ref now pins the v0.2.2 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-standard v0.2.0 — release. Catalog ref now pins the v0.2.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ran repo-standard v0.1.1 against this repo (class `catalog`): 5 ERROR, 4 WARN.
Three ERRORs were real and are fixed here:
- LICENSE was missing while README and GOVERNANCE both claim MIT — the claim a
reader relies on was unbacked. Adds the same MIT text the plugin repos carry.
- `## Installation` -> `## Install`. The contract wants the fixed heading
because that is what an agent pattern-matches on; the block itself was already
the catalog form (`marketplace add` only, https, no plugin install line).
- Adds `## Non-goals`, grounded in GOVERNANCE.md: source and issues live in each
plugin repo, no third-party submissions, no PRs, no support commitment.
README's opening line also carried a trailing period that neither the forge
description nor `marketplace.json:metadata.description` has. The README was the
odd one out of three, so it loses the period — description == catalog == README
is the only place a machine can check the three agree.
The two remaining ERRORs are a gate defect, not a repo defect, and are
deliberately NOT silenced. `RUNBOOK.md:39` and `:114` contain
`https://.../api/v1/orgs/open/repos` — the Forgejo endpoint for creating an org
repo. The checker's `URL_REF` regex reads the `repos` collection segment as a
repo name. Measured: `GET /api/v1/orgs/open/repos` -> HTTP 200 (live API),
`GET /open/repos` -> HTTP 404 (no such repo), and repo-standard-check.mjs:705
builds the identical URL, so the gate would flag itself. The runbook text is
correct and stays; the classifier fix belongs in the repo-standard repo and has
been routed there.
The 4 WARNs (LINK-INTERNAL-MISSING) all stand by design: they are inside
`test/nav-golden-corpus/`, where `bundle/index.md`'s escaping links ARE the
traversal test, and `expected-read-context.md` is expected OUTPUT text whose
links are data, not navigation. Repairing any of them would delete the test.
Gate after: 10 checks pass, 0 real ERROR. check-versions 12 OK/0 ERROR,
tests 120/120.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4zqeGKBfAA2r8buPVefNR
org-ops reported that 30-fix-references.mjs:3-5 promises a disclosure-link
rewrite that 10 published plugin repos do not have. Confirmed by measurement,
at each plugin's catalog-pinned tag rather than in the sibling working trees:
10 of 12 still carry ../../README.md#ai-generated-code-disclosure on README.md:7.
Only repo-mailbox and repo-standard — both created after the migration — are clean.
The rewriter is not broken. Its DISCLOSURE_LINK regex was re-verified against the
live text at okr@v1.8.2:README.md:7 and matches, so "fix the script" would have
been a no-op. What never happened is the application: the migration's push half
was operator-gated and ran 0 pushes (review.md:79), so this step's output never
reached the content that was published. The header was true about the code and
false about the outcome — which is exactly how it got read as a receipt.
The header now says so, with the measurement date and method. Remediation is not
the catalog's to make: each plugin repo owns its README, and all 10 were notified.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bmkz7r2zycwwG2kcCCf9H
repo-standard v0.1.1 — release. Catalog ref now pins the v0.1.1 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
§12 says "When Google bumps OKF, each plugin re-checks conformance." Google
bumped 2026-07-25; commons ruled the trigger catalog's to pull and the plugin
owners' to perform. This is the pull.
Held: upstream has NOT moved (git ls-remote answers 3fcbb9f, identical to the
mirror the 0.3 round read; SPEC last touched 2026-07-24 in 780fe9d). All seven
upstream anchors resolve exactly, quotes verbatim. The §3 floor is conformant
with upstream §11. No floor change -> the convention stays at 0.3.
Corrected:
1. §14 said "OKF SPEC v0.1" while linking blob/main/okf/SPEC.md, which has
served v0.2 since 2026-07-24 — a reader following our own reference got
v0.2 under a v0.1 label.
2. §3 attributed to upstream a rule upstream does not state: "upstream binds
the index.md requirement to the bundle root alone", cited to commons'
method-spec.md. Google requires index.md NOWHERE (SPEC :117 "Optional",
:504 "MAY appear in any directory", :759 consumers MUST NOT reject for
missing index files). Three rungs, not two; ours is highest either way, so
only the attribution was wrong.
3. §4 now names v0.2's second breaking change (# Citations -> sources).
Measured 2026-08-03: no marketplace emitter writes # Citations; the one
live exposure is a plan, not code — ms-ai-architect's brief still names an
upstream v0.1 example as the template to copy.
Suites 120/120, 0 fail. check-versions 12/12 OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THEvHPWM11RupX24wBGKLu
repo-standard was tagged and pushed in its own repo but never pinned here, so
its documented install command could not resolve for anyone (its own gate
reported ERROR INSTALL-NOT-IN-CATALOG against us).
Manifest entry added by hand (release-plugin.mjs rewrites an existing entry,
it cannot create one); the ref was written by release-plugin.mjs, not by hand.
README block written to catalog house style from the text repo-standard
proposed, with one correction: the gate composes TWELVE checks, not fourteen
(classifyRepo spreads 12 check* calls at v0.1.0, and their own README table
has 12 rows). Stats measured in an extraction of the v0.1.0 tag: 1 skill
(badge), 12 checks, 84 tests (node --test: tests 84 / pass 84).
check-versions.mjs: 12 plugins — 12 OK, 0 WARN, 0 ERROR, 0 SKIP.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THEvHPWM11RupX24wBGKLu
The v0.20.1 and v0.20.2 ref bumps moved the pinned tag without moving the
stat line. repo-mailbox now badges the axis (selftest_checks-398), so the
gate caught it: 183 coord + 142 board + 73 route = 398 at v0.20.2.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01THEvHPWM11RupX24wBGKLu
repo-mailbox v0.20.1 — release. Catalog ref now pins the v0.20.1 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.19.0 — release. Catalog ref now pins the v0.19.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The stat-badge gate skips any axis the plugin does not badge, so those
numbers are structurally unverifiable and rot in silence. Hand-audited
every remaining one against ground truth extracted from the pinned tag
(git archive <ref>, never the sibling working tree).
12 of 13 measured exact. The one defect: voyage's `500+ tests`, which is
832 at v5.9.1 — true as a lower bound, so the gate could never have seen
it, but a 40% understatement to a reader comparing plugin blocks.
Also corrects CLAUDE.md's own worked example: `1441 tests` was the number
the ref-defect produced by reading config-audit's working tree; 1398 is
what v5.13.0 installs. Records the two counting rules calibrated against
the badged plugins — hooks = hook command entries (events and matchers
both diverge from the badge), tests = `ℹ tests` and not `ℹ pass`.
Gate: 11 OK / 0 WARN / 0 ERROR. Tests 120/120.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D6Sy2bjLWXjh59g1WsAe4X
ai-psychosis v1.2.2 — release. Catalog ref now pins the v1.2.2 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Same defect as 780f86e, in a number I wrote myself in e9054f8: 374 came from
repo-mailbox's working tree, which has committed past v0.18.0 (board-selftest.sh
is +44 lines there, worth 4 extra checks). The catalog documents what installs.
Measured at the pinned tag, extracted read-only with `git archive v0.18.0` into a
scratch dir (never a checkout in another repo): coord 183 + route 73 + board 114
= 370. CLI scripts stays 8 — scripts/ holds the same 11 *.sh at the tag as at
HEAD, of which 3 are selftests.
Both axes are badge-less, so the gate cannot check either. That is the point:
this is the class that needs a human pass, and it just proved it twice.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDSiMcgLMpEETwtkc86Nym
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
029ffb8 (this session, hours ago) said one emitter remained. okr migrated the
same day, so that is already stale. Both emitters are gone:
- linkedin-studio at its bc47c18 (scaffold.ts)
- okr at its 1da9dd8 — okf-index.mjs now emits okf_version via writeFrontmatter
ahead of the `# heading`; only okf_layout stays in body text.
Verified read-only against okr e662196 rather than taken from their notice.
The fallback stays, but its justification changed with them: it now covers
bundles already written in the old form, not emitters still producing it. okr
made its own checker tolerant (049259d) BEFORE moving the emitter (1da9dd8), so
nothing forces a simultaneous migration and the parity signature does not split.
Re-measured after the change: check-okf-parity 9/9 green, okf-check 25/25.
Removal condition restated honestly: only once every bundle in the wild has been
rewritten — which nothing tracks today.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDSiMcgLMpEETwtkc86Nym
[skip-docs]: the user-facing doc here is CLAUDE.md, not README.md. This is a
maintainer-side consistency gate — the catalog landing page should not describe
it — and CLAUDE.md gains a full paragraph covering the rule, the measured
badge-less gap, and the never-hand-edit-a-stat-line instruction. README.md
changes by exactly one number because the gate found it wrong.
The catalog restates each plugin's counts in a per-plugin stat line, and those
numbers rot silently: nothing compared them to anything. Measured across all 11
plugin READMEs today, config-audit's line claimed 1410 tests while the plugin's
own badge said 1441.
Rule is PER-AXIS, not per-plugin. For each number on a catalog stat line, if the
plugin carries a shields badge for that axis, they must agree (ERROR otherwise);
if it carries no such badge, the axis is skipped. This was measured, not assumed:
21 axis-pairs are badge-covered, but 14 axes across 8 of the 11 plugins are
badge-less (voyage 4, ms-ai-architect 3, repo-mailbox 2, ai-psychosis 2,
linkedin-studio 1, claude-design 1, graceful-handoff 1). A per-plugin exception
list — the original sketch, scoped around voyage alone — would have had to name 8
of 11 repos and be hand-edited for every new axis.
Stated plainly rather than hidden: those 14 axes stay ungated. repo-mailbox's two
were 6 and 251 against a true 8 and 374 (fixed in e9054f8).
Parsing is measured against the real corpus: shields' `--` literal-hyphen escape,
`_`/`%20` spaces, zero as a real count, non-numeric badges (version/platform/
license) excluded, parenthetical asides read as their own axis ("5 skills (389
docs)"), doc/docs/references/reference_docs/knowledge_docs folded onto one axis,
and `N+` read as a lower bound.
Only the catalog's config-audit number changed; the plugin badge is the source.
Tests 106 -> 117 (+11). 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
Both numbers were measured at v0.12.x and never re-measured across six version
bumps. Neither axis carries a shields badge, so the badge-mirroring gate now
being designed would not have caught either — they are stated here as the
ungated class that still needs a human pass.
Measured today against repo-mailbox v0.18.0:
- CLI scripts 6 -> 8: scripts/ holds 11 *.sh, of which 3 are selftests
(board, coord, route), leaving 8 operator-facing entry points.
- selftest checks 251 -> 374: coord 183 + route 73 + board 118, from running
the three selftests (each sandboxes its mailbox via mktemp -d).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDSiMcgLMpEETwtkc86Nym
linkedin-studio migrated its bundle-root okf_version from body text into the
root index.md frontmatter block (their bc47c18, which is their HEAD). The
comment justifying the body-text fallback still claimed two live emitters.
Verified against ground truth rather than taken from the notice:
- linkedin-studio scaffold.ts now emits okf_version 0.1 inside the frontmatter
block (measured 2026-08-02 at bc47c18).
- okr scripts/okf-index.mjs:204 still pushes it as body text, after the
`# heading` line with no `---` delimiters (measured 2026-08-02 at d634385).
So the fallback stays — it is still load-bearing for okr, and check-okf-parity
still compares this value against okr's live checker. Only the count and the
removal condition change. Comment-only; 106/106 tests green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDSiMcgLMpEETwtkc86Nym
repo-mailbox v0.18.0 — release. Catalog ref now pins the v0.18.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.17.0 — release. Catalog ref now pins the v0.17.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.16.0 — release. Catalog ref now pins the v0.16.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.15.0 — release. Catalog ref now pins the v0.15.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.14.0 — release. Catalog ref now pins the v0.14.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frontmatter reader matched `^\s*<key>:` with the m flag — indentation-
agnostic, so a block-form nested entry satisfied a top-level lookup. Measured
against okf/SPEC.md at frozen 3fcbb9f, this is a field confusion, not a near
miss: :467-469 names `resource`, `sources[].resource`, `executor.resource` and
`attester.resource` as DISTINCT fields. Top-level `resource` is the URI of the
asset a concept describes (:196); `sources[].resource` is the material it
derives from (:302). `sources` entries carry their own `title` and `type` too.
The consequence was not confined to warnings. Measured before the fix, a
concept with NO top-level `type:` and a `sources[].type` reported "0 files
without type: / OK: valid OKF bundle" — a false negative on §4.1's only
always-required field. `untyped` IS in the parity signature
(check-okf-parity.mjs:73-76), but okr vendors the same regex, so both impls
were blind identically and the gate stayed green while both were wrong.
Anchoring the key at column 0 fixes it. Flow-form never had the bug: in
`sources: [{ id: s1, resource: fixture }]` the nested key is mid-line, so `^`
cannot match it — measured against llm-ingestion-okf's v0.2 golden bundle
(6e0a7c0, read-only), which warns about `resource` and `description` both
before and after.
The divergence from okr is deliberate and is NOT okr lagging. Their reader is
SHARED, and the nested match is documented as load-bearing for their injector
(lib/frontmatter.mjs:7-9 -> inject:69) — while the same module backs their
scripts/okf-check.mjs:101, which needs the opposite. Pinned as parity fixture
`red-nested-key` (catalog FAILs on the nested type, okr passes it), so the
split is a running red/green signal instead of a note. It flips to `agree`
only if okr scopes the checker's reader without touching inject.
Correcting two premises carried in from the previous session, both measured:
- The reader was NOT flat/top-level-only. It read nested keys, so the suspected
false POSITIVE on `resource` was actually a false NEGATIVE, opposite sign.
- "No v0.2 bundle exists" held for our own corpora and emitters only.
llm-ingestion-okf ships a v0.2 golden bundle, where the previous commit's
version-conditional list has real effect — and behaves correctly there.
docs/okf-second-brain/spec.md is untouched deliberately: it makes no claim
about key scope, so gate and convention do not disagree here.
Tests 103 -> 106 (okf-check 22 -> 25), parity 9/9 -> 10/10. All six suites
green; check-versions 11 OK / 0 WARN / 0 ERROR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RGZGiDPYcHUMSDCVJavRhp
route.sh now writes --advisor opus into the startup command it emits,
per row and on a need: always on the Sonnet rows (capability lift, which
is what makes the quota fallback safe to take), on the Opus rows only at
costly/one-way stakes, never on Fable (the CLI rejects it).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X8N8hQEJSWWtieWUx37txT
The gate carried a flat RECOMMENDED list ending in `timestamp`. Upstream retired
that field in v0.2: "`timestamp` is superseded by `generated.at`" (okf/SPEC.md
§13.1:802-803, read at frozen 3fcbb9f), one of the version's two breaking
changes — while :804 still lets a consumer "fall back to a legacy `timestamp`
when `generated` is absent".
A version-unconditional list cannot serve both readings. It either nags a
correct v0.2 bundle about a retired field, or goes silent about a field v0.1
still wants. So the list is now chosen by the bundle root's own okf_version:
< 0.2 (or absent/unshaped) keeps `timestamp`, >= 0.2 asks for `generated`.
Absence gets the legacy floor deliberately — §3 echoes a missing marker rather
than failing it, so it still needs a defined list.
Measured, not assumed:
- Every fixture in both corpora and both live emitters (okr, linkedin-studio)
still write `okf_version: 0.1`, so this changes NO verdict today. It is
written now because the upstream reading is fresh and pinned to a commit.
- The parity signature is conceptCount|untyped|okfVersion|okfVersionAccepted
(check-okf-parity.mjs:73-76) — warnings are not in it, so diverging from
okr's list here cannot red the parity gate. Confirmed: 9/9 fixtures pass.
- The compare is component-wise, NOT parseFloat: okf_version is version-SHAPED,
and parseFloat('0.10') is 0.1, which would sort 0.10 before 0.2 and hand a
newer bundle the retired field. Guarded by its own test.
spec §4 is updated in the same commit — a gate and the convention it enforces
must not disagree about which field they want.
Tests 98 -> 103 (okf-check 17 -> 22). All six suites green; check-versions
11 OK / 0 WARN / 0 ERROR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0135YZBcCDvH3BgG5yEtuHCA
Same defect class as 9992235, found by auditing the remaining ten blocks:
the version label v0.12.1 was correct while the prose sat three minor
bumps behind. The block promised "3 skills" in its stat line and then
described exactly one of them.
`board` (v0.10.0) and `route` (v0.10.0) were invisible in the catalog --
the cross-repo attention board and the model/effort rubric that is now
the single copy of the operator's global routing policy. `reply-expected`
/ `--fyi` (v0.11.0) was missing too: the format can finally tell a
question from a notice, and absence means expected.
Two numbers were measured wrong, not estimated wrong:
3 CLI scripts -> 6 operational (board, coord-count, coord-done,
coord-inbox, coord-send, route) + 3 selftests
70 selftest checks -> 251, by running them:
coord 159, route 56, board 36
The other nine blocks were audited on the same two axes and are correct.
Every "Key commands" line was checked against real command files -- no
phantom commands anywhere, so the flag half of the graceful-handoff
defect does not repeat. Two prose claims I suspected held up on close
reading: voyage's annotation HTML view (README:24, 509+) and
claude-design's "enforced by test" -- that test says "collision", not
"overlap", so the first grep was too narrow, not the catalog wrong.
voyage's "500+ tests" stays UNMEASURED (76 test files, assertions not
run). Not asserted either way.
The stat line was fixed in 950c7a9, but it sat above four bullets that
still sold the architecture the plugin removed in v3.0 (BREAKING). The
catalog advertised a Stop hook at ~70% context, model-aware context
detection, a statusLine hint with SessionStart auto-load, and a
"handoff artifact" -- none of which exist. The version label v3.1.0 was
correct all along; only the prose was a major version behind.
The flags were wrong too: the catalog documented
`[topic-slug] [--no-push]`, neither of which the skill accepts. Measured
contract is `argument-hint: "[--no-commit] [--dry-run]"`.
Rewritten from the plugin's own README and SKILL.md: one user-initiated
skill (`disable-model-invocation: true`), overwrites the nearest
STATE.md with a mandatory NESTE block, remote-aware commit that stages
only STATE.md, push left to the operator.
The removal reason is worth stating rather than hiding -- a hook has no
session context, so it could only ever write a poor snapshot, and would
overwrite a good model-written STATE.md. That is a design argument for
the plugin, not an omission to paper over.
check-versions 11 OK / 0 WARN / 0 ERROR; tests 28 pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JoD3K9WDXSZNACArc7zTwn
The catalog invented its own counts and drifted from every plugin it
describes. Ten of eleven plugin READMEs publish their numbers as badges;
the plugin owns its count, so the catalog now mirrors it instead of
counting independently. File counts in agents/, commands/, skills/ and
entries in hooks/hooks.json agree with those badges everywhere both
exist, which is what makes the mirror trustworthy.
Voyage publishes no stat badges, so its numbers come from measurement:
all files in agents/ (24, including three self-declared reference
documents) and registered entries in hooks.json (7).
Corrections, measured 2026-07-31:
- llm-security 26 -> 23 scanners, 1863 -> 2013 tests
- config-audit 6 -> 7 agents, 13 -> 16 scanners, 18 -> 21 commands,
954+ -> 1410 tests
- voyage 23 -> 24 agents, 5 -> 7 hooks
- ms-ai-architect 25 -> 29 commands, 387 -> 389 docs
- linkedin-studio 19 -> 20 agents, 29 -> 30 commands
- okr 10 -> 14 commands, 4 -> 3 hooks (an over-claim)
- repo-mailbox 1 -> 3 skills
- graceful-handoff drops "3 hooks": the plugin removed hooks in v3.0
and its README says "No hooks" with a hooks-0 badge.
Tests 57 -> 30.
ai-psychosis, human-friendly-style and claude-design were already
correct. Test counts without a badge (voyage 500+, claude-design 5,
repo-mailbox 70) are left untouched: unmeasured, not verified.
No gate catches this class of drift -- check-versions compares versions,
not counts. check-versions 11 OK / 0 WARN / 0 ERROR; tests 28 pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JoD3K9WDXSZNACArc7zTwn
repo-mailbox v0.12.1 — release. Catalog ref now pins the v0.12.1 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
README.md:15 asserted two things that were measurably false as of
2026-07-31, both introduced in b4648e1 (2026-05-30):
- "Works with the Claude Code CLI, desktop app, and IDE extensions on
macOS, Linux, and Windows" — omits the web surface, and the desktop
app ships only for macOS and Windows (x64/ARM64), not Linux.
- "No external dependencies" — okr declares 4 runtime deps (mammoth,
postal-mime, turndown, unpdf).
Replaced with the requirement itself, which does not rot: install
happens via /plugin inside Claude Code, and the marketplace-add command
above registers the marketplace without installing anything.
No gate catches catalog prose — check-versions does not read README body
text. Verified by hand: check-versions 11 OK / 0 WARN / 0 ERROR,
28 pass / 0 fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gHfoARehGggASpC29muRz
The voyage entry was 625 chars against a field where the second-longest is
linkedin-studio at 274 and the median is 163 (measured 2026-07-31, n=11).
Roughly half of it was annotation-HTML implementation detail — scripts/annotate.mjs,
"modelled on claude-code-100x", pencil-toggle mode, Fiks/Endre/Spørsmål, Copy Prompt.
That belongs in the plugin's own docs; README.md:66 already carries the one-sentence
catalog-level version of it. Kept: the six phases, agent swarms, external research
triangulation, the adversarial-vs-independent-review distinction, and multi-session
resumption — the parts that distinguish voyage from any other pipeline in the list.
No gate covers this: check-versions.mjs does not inspect description length, so a bad
rewrite would still go green. Three variants were measured (189/237/328) and the
operator picked 237.
Verification: JSON parses, 11 plugins intact; check-versions 11 OK / 0 WARN / 0 ERROR
(exit 0); check-versions + release-plugin tests 28 pass / 0 fail; diff is 1 line.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wsm9DJmoiL5g9M8JXjFTE1
okr v1.8.2 — release. Catalog ref now pins the v1.8.2 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Upstream (~/repos/_okf-upstream @ 3fcbb9f, okf/SPEC.md) is unambiguous: a bundle-root
index.md MAY carry okf_version in a FRONTMATTER block, "the only place frontmatter is
permitted in an index.md" (§8:509-510 + §12:773-775). Through 0.2 this convention said
the opposite — no frontmatter, marker in body text. The divergence was OURS against
upstream, so 0.3 removes it rather than documenting it. Operator ruling, 2026-07-31.
Measured before deciding (date pinned to every number):
- emitters: okr (body, okf-index.mjs:204) · linkedin-studio (body, scaffold.ts:38)
· commons (FRONTMATTER, examples/nav-golden-*/bundle/index.md)
- this repo already carried BOTH forms, both green: okf-parity-corpus (9, body) and
nav-golden-corpus (4, frontmatter, byte-exact from commons @ b641741). Invisible
because the marker regex was unanchored /m, i.e. placement-blind.
THE READER IS TRANSITIONAL BY DESIGN, NOT BY OMISSION. check-okf-parity.mjs:36-39 runs
okr's LIVE checker and compares conceptCount|untyped|okfVersion|okfVersionAccepted. A
frontmatter-only reader reports null here and 0.1 there, splitting the signature on all
9 body-text fixtures — a red gate produced by a doc change, with no bundle having become
less conformant. So both placements are read, one is canonical, and placement is
DECLARED, NOT ENFORCED — the same shape §3 presence has carried since 07-23.
QUOTING WAS UPSTREAM'S OWN FORM, NOT A CORNER CASE. §12:773 is the only place in the
upstream spec showing the key with a value, and it is quoted: okf_version: "0.2". The
0.2 gate ran the shape regex on the RAW string and failed upstream's canonical example.
Fixed by unquoting BEFORE the shape check. Implemented by reusing okf-frontmatter.mjs's
existing get(), which already unquoted (lines 22-26) — no new parsing code.
okf_layout STAYS IN BODY TEXT (§12). Upstream's exception is enumerated to one key, so
the block exists by upstream's leave and for upstream's key; our own extension marker
stays outside it. Asymmetric on purpose: it survives either construction of upstream's
parenthesis — a question okr has flagged as open and we do not own.
MEASURED CONSEQUENCE, REPORTED NOT HIDDEN: okr v1.8.2 fixed their PRODUCER, not their
checker (rootMarkers/pick returns the raw string). On a quoted fixture the two impls now
diverge on the VALUE — catalog 0.2 vs okr "0.2" — measured directly via evaluateBundle.
No existing gate is affected because the corpus carries no quoted fixture, which also
means the parity gate's green does NOT cover the quoting axis: "not run", not "as
expected". The shared unquote-before-compare decision has to reach okr's CHECKER too.
Verification: suite 90 -> 98/98 (8 new; written red first — 6 genuinely failed, 2 were
regression guards already correct). Parity 9/9, red-marker-layout still diverging per
its manifest. nav-golden 2/2. git status test/ clean: NO fixture migrated — the 9
body-text fixtures are now the coverage for the transitional path.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRhqgd8hws7SxT3mC4Lm4U
config-audit v5.13.0 — release. Catalog ref now pins the v5.13.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.12.0 — release. Catalog ref now pins the v0.12.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.11.0 — release. Catalog ref now pins the v0.11.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The catalog half of a shared gap that was previously PINNED rather than fixed.
This reader of ~/repos tested `.git` with a directory check, so a plain
`git worktree add ~/repos/feature-x` produced a depth-1 sibling that can carry
its own STATE.md and was dropped SILENTLY - no warning, no count,
indistinguishable from a repo with nothing to say. A submodule fails the same
way for the same reason.
It was pinned, not fixed, because diverging would break the very
same-name-from-both-readers invariant discoverRepos exists to hold. ~/repos
answered YES to the gated question and reported their half landed. Verified
here rather than taken on report: board.sh's Discovery block tests `-e`, and
has done since board.sh was introduced (repo-mailbox 61e224c, first released
v0.9.0) - so the released reader has no `-d` era at all, and only this side
was ever the outlier. The two move together from here - change one, change the
other.
THE ACCEPTANCE TRAP, MEASURED RATHER THAN ASSUMED. This changes NO number
against real ~/repos. Old and new builders were run back to back against the
live tree and diffed: stdout and stderr byte-identical, both exit 0. Directly
measured why: 0 directories at depth 1 or 2 currently carry .git as a file.
A number standing still is not ambiguous here, it is the ONLY possible outcome,
and it is why a fixture is not the best way to test this but the only way.
FIXTURE GATED BEFORE BEHAVIOUR. The worktree fixture uses a real `git worktree
add`, not a hand-written `.git` file - faking it would assert against our guess
at git's on-disk format instead of against git. A separate test asserts the
fixture itself: .git exists, is a file, is not a directory. Without it, the day
git stops writing worktree .git as a file the behaviour tests would go green
while measuring nothing, and a green run cannot distinguish that from success.
The gate says which one it was, and says the premise of the -e rule is gone
rather than inviting a test tweak.
Two behaviour tests: a worktree at depth 1, and one under a polyrepo container
at depth 2 - the same rule at both depths board.sh walks.
Suite 90/90 across the six files (rollup 31 -> 34). check-versions 11 OK,
0 WARN, 0 ERROR. Real run unchanged at 8 repos, 17 markers, Output B 0 lines,
1 V6 warning, exit 0.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KSX2v1m7Fz22BKrGJZuUpQ
repo-mailbox v0.10.0 — release. Catalog ref now pins the v0.10.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.9.0 — release. Catalog ref now pins the v0.9.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.8.0 — release. Catalog ref now pins the v0.8.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.7.0 — release. Catalog ref now pins the v0.7.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
linkedin-studio v0.8.0 — release. Catalog ref now pins the v0.8.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
repo-mailbox v0.6.0 — release. Catalog ref now pins the v0.6.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two measured defects in build-rollup-register.mjs, reported by ~/repos and
independently re-measured here with the producer's own parser as instrument.
D1 - discovery saw only depth 1, so 5 markers across 3 marketplace repos were
invisible (11 STATE.md files live at depth 2). discoverRepos now mirrors
board.sh:63-89 EXACTLY: a dir that is itself a git repo contributes itself and
is NOT descended into; a non-repo dir holding git repos is a polyrepo container
contributing its children. Identity stays the RAW BASENAME (board.sh:100) so
this builder, board.sh and the coord mailboxes name a repo alike.
Not descending into a git repo is what makes the known nested-name trap
(claude-code-100x/claude-code-100x, both git repos) structurally unreachable
rather than merely absent - blanket depth-2, as proposed, would have reached it.
A collision gate still fails HIGH on two STATE-bearing dirs resolving to one
name, gated on CONTRIBUTING repos so a same-named dir without STATE.md cannot
stop the build. Measured today: 0 collisions across 25 state-bearing dirs.
D2 - parseMarkerLine returns null for two DIFFERENT facts ("not a marker" /
"a marker that failed to parse"), so a malformed marker vanished with exit 0.
V4/V5 only ever gated the carrier; nothing gated marker loss. New V6 reports a
line whose topic and KNOWN status token are both present but which does not
parse, naming file + line number. A warning, not a failure: a typo in another
repo's LOCAL state file must be visible, but is not this builder's business to
fail on. Unknown tokens stay "not a marker", keeping prose out of the channel.
A repo with only losses is still discovered - skipping it would re-open the
exact silent channel V6 closes.
Acceptance against real ~/repos: 15 markers (was 10, +5 exactly as predicted),
2 V6 warnings naming the two measured "--" lines, 0 collisions, exit 0.
Test fixtures are synthetic: marker prose is Output-A material (LOCAL-ONLY),
so quoting a real one into this public repo would be the same
durability-vs-publicity conflation the builder header warns about.
Suite 87/87 (was 78, +9). check-versions 11 OK / 0 WARN / 0 ERROR.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPHvLhn2U3j2XD3Cn8zeYa
Two findings from the inbox, both re-verified against the other repo's code
rather than its summary.
§8 -- the "contradiction" we flagged was ours to misread. We had SKILL.md:94
(union) against CLAUDE.md:67 (precedence) and asked okr to adjudicate, assuming
SKILL.md because it describes actual procedure. Right, and right for the stated
reason. Verified @52129b5: SKILL.md:35-36 "always search both, project first",
:46-47 "overrides ... ON CONFLICT", :94-95 "Glob both roots". Union is the
search SPACE; precedence is a tie-break that fires only when the same content
sits in both roots -- orthogonal, which is why one file carries both without
contradicting itself. okr fixed CLAUDE.md:67 ("else" implied a lookup stopping
at the first root). §8 stays OPEN at the convention level; only its description
of okr is refined -- retrieval carries union AND precedence as two layers, not
one axis each.
The wiki -- llm-ingestion-okf reported, unprompted, that claude-code-llm-wiki
requires exactly the construction rule §3/§6 forbids. Re-read here @59ef033:
validate.py:74 puts BUNDLE_INDEX_COMPLETE at ERROR, :1097-1104 derives expected
from the directory and demands bidirectional match, bundle.py:498 generates
indexes machine-side. This is not our trap sprung -- it is its mirror image,
chosen: we forbid derivation because a derived index CANNOT DISAGREE with the
directory and so hides what is missing, while they make "cannot disagree" an
enforced invariant with a loud outcome. Our index is a curated selection that
must be able to disagree; theirs must not be. Neither is incoherent.
Consequence (theirs): authored-vs-derived cannot be a library invariant in
either direction; it becomes policy. And the sharpest argument came back at us
-- a field carrying only "per-directory: yes" would have hidden the difference
entirely. That is a better case for splitting scope from construction than the
one we gave them.
Suite 78/78. Inbox emptied: 4 in, 2 replies, 2 closed without reply.