okr v1.10.0 — release. Catalog ref now pins the v1.10.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
applyRelease()'s `try` spanned both the catalog README read AND its write, so a
real EACCES/ENOSPC on the write was swallowed and reported as readme:'missing'
("no catalog README to update") with verdict WROTE and exit 0 — a bumped ref
with a stale label, announced as success. Pre-existing form, not a regression.
The `try` now covers the READ only: a catalog without a README stays a tolerated
state, a README that cannot be written throws.
Known narrow guarantee: the throw propagates out of main() AFTER marketplace.json
is written, so the working tree is left half-applied (bumped ref, stale label).
That is the same hazard ac7ad42 closed for gate ordering — but strictly better
than today's silent exit 0, and widening the fix is not in scope here.
Test is path-selective on purpose: a fake that throws for every path dies on the
marketplace write above the try (in both the old and the new code) and would go
green against the unfixed file. Verified red before the fix.
Tests 25 -> 26 (suite total 131 -> 132).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A839v1MGa3Bm8icX8dTHYi
Both notes dated the decision 2026-08-11. It was made on 2026-08-10, the
same evening as ac7ad42 — the date was taken from a local-time clock read
as if it were UTC (20:52 CEST is 18:52Z, still 08-10).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019i3rnU2VNRdGcrUFMnRb6R
`--create-tag` minted AND PUSHED a plugin tag to a public remote without
`--write`, on the entry point CLAUDE.md documents as "dry-run by default".
The tag was public before the plan was even printed.
Extracts `shouldCreateTag(args, observed, target)` as a pure exported
predicate ('create' | 'dry-run' | 'skip') so the flag's write-ness is
testable, and gates minting on `--write`. Without it the CLI now reports
what it would mint, printed after the missing-tag blocker that points at
the flag.
Deliberately NOT placed behind the catalog-wide pre-flight: every
precondition it checks is local to the plugin being released
(plugin.json == target, badge agrees, tag absent), so the tag is correct
by construction. A red *other* plugin can only make the tag early, never
wrong, and the tag-absent check makes the retry idempotent. Gating it
would let plugin Y block the tagging of plugin X — the same over-coupling
that reading the ERROR set only (never `failed`) exists to avoid.
Tests 19 -> 25; 131/131 across the six suites. check-versions 12 OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019i3rnU2VNRdGcrUFMnRb6R
release-plugin.mjs --write wrote marketplace.json and the catalog README label
first, and only THEN ran check-versions via execFileSync (which throws on exit
1). A red catalog therefore left a half-applied release in the working tree —
exactly the state a parallel session has already been observed carrying to the
public remote.
Adds applyRelease() with an injected io seam so the ORDER is testable: runGate()
runs first, and any ERROR aborts with nothing written. The pre-flight reads the
ERROR set only, never failed/--strict — pre-bump the released plugin is SUPPOSED
to be WARN (catalog ref behind plugin.json), so a WARN gate would brick every
release. Verified against the real classifier, not synthetic data.
The post-write gate stays: pre-flight validates the old state, that one
validates the new state.
Known remaining hole, documented not built: --create-tag mints and pushes the
plugin tag before the pre-flight runs.
Tests 14 -> 19 (120 -> 125 across the six suites); check-versions 12 OK.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Ga5tZ3AgUxAcdLtWB8Kig
Two stat corrections plus a ref bump, together because release-plugin.mjs left a
half-state that could only be closed with the gate green.
repo-standard v0.5.0 -> v0.9.0 (operator-approved). Approved as "bump to the
latest tag, v0.8.1", but v0.8.1 became unreachable while the session ran:
plugin.json had moved to 0.9.0, and the helper refuses a target its plugin.json
does not match ("asked to release 0.8.1 — bump plugin.json first"). v0.9.0 was
tagged at 22:05 today (1dfd408), plugin.json == README badge == 0.9.0, so it is
a consistent released version and the faithful reading of the approval. Same
breaking v0.8.0 boundary that was already accepted, one minor further.
Ungated axes re-measured at the new ref, per CLAUDE.md: tests 135 -> 170
(`node --test` on a `git archive v0.9.0` extract), checks 14 -> 14 (the README
check table still has 14 rows; v0.6.0-v0.9.0 re-levelled finding CODES under
existing rows). Badges at v0.9.0 are version/platform/skills-1/license, so
both numbers stay ungated and rot silently — they were measured, not carried.
repo-mailbox 406 -> 402. This reverses the refusal sent from here 20 minutes ago
(and d60ad40's 406), and the reversal is legitimate rather than a flip-flop: 402
was wrong then and is right now because the REF MOVED underneath it. When
repo-mailbox asked, v0.21.0 did not exist as a tag and the catalog pinned
v0.20.3, whose badge says 406 — writing 402 then would have produced a hard
ERROR and a dangling ref. A parallel session has since bumped the ref to
v0.21.0 (9d04179), and the badge AT that ref says 402. The catalog documents
what installs, so the number follows the tag.
That parallel commit knowingly landed a red gate for the catalog to clean up;
this commit is that cleanup. Gate now: 12 OK, 0 WARN, 0 ERROR, 0 SKIP.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPz4FNKSn2QwoMhRFn4WNo
repo-mailbox removed route.sh's --opus-xhigh-failed flag and Fable rows
5-6 as a rubric outcome (operator policy decision) - a hand-written
override now, never produced by the calculator.
Known gate result: check-versions.mjs reports 1 expected ERROR for
repo-mailbox (catalog stat line still says 406 selftest checks, plugin's
own badge now says 402 - the release dropped three checks that tested a
command shape row_advisor() can no longer produce). repo-mailbox already
sent a coord-send correction superseding its earlier 406 notice with the
current 402; that stat-line prose is catalog's to update, not committed
here per the repo boundary. repo-standard's pre-existing WARN (v0.5.0 ref
vs 0.9.0 plugin.json, untagged) is unrelated and untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ap1WKHCDPcSfpjo4ds2dQX
The ref bump in 2b38c27 moved graceful-handoff v3.1.0 -> v3.2.1, and that MOVED
this axis out of the gate's reach. At v3.1.0 the plugin carried a `tests-30`
shields badge, so `30 tests` was mirrored and enforced. At v3.2.1 the badge set
is version / platform / skill-1 / STATE--helper-deterministic / license -- no
tests badge -- so the claim became ungated in the same commit that made it wrong.
Measured at the pinned tag per the calibrated rule in CLAUDE.md (`ℹ tests` from
`node --test`, in a `git archive v3.2.1` extract, never the sibling worktree):
48 tests. The catalog understated by 18.
Badge coverage therefore moves 27 gated / 15 ungated -> 26 / 16 across the same
42 axis-claims; `1 pipeline` was already ungated (it is alt-text over a
deterministic-helper badge, not a count). This is the re-measurement pass
CLAUDE.md requires whenever a ref moves -- not a hand-edit to silence the gate,
which stays silent on an axis it cannot see.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPz4FNKSn2QwoMhRFn4WNo
graceful-handoff v3.2.1 — release. Catalog ref now pins the v3.2.1 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The catalog understated repo-mailbox's selftest count. Source of truth is the
plugin's own badge at the PINNED ref: `git show v0.20.3:README.md` line 17 says
`selftest_checks-406` (coord 191 + board 142 + route 73 = 406). The catalog said
398, measured at v0.20.2 before coord-selftest went 183 -> 191.
Flagged by repo-mailbox via coord; check-versions.mjs had it as the only ERROR
in the gate. That mattered beyond the stale number: release-plugin.mjs:200 calls
the gate through execFileSync, which throws on exit 1 -- AFTER writing
marketplace.json and README.md but BEFORE committing. Any `--write` run would
have landed a half-state, so this had to be green first.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPz4FNKSn2QwoMhRFn4WNo
release-plugin.mjs wrote the ref + version-label bump; committing by
hand because the closing check-versions.mjs gate blocked on repo-mailbox's
own stale stat-line prose (398 -> 406 selftest checks), which is not this
script's job to edit. Correction queued to catalog via coord message
20260809T191518Z-4678230575-from-repo-mailbox.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CHmf1VfCvaYXamJxe5y6Vt
okr closed patch-lane #2 (commit 35a0bb8): scripts/okf-check.mjs now reads
type: at root level only, so a type nested only in a sources[] entry no
longer passes as typed. Both implementations now agree the fixture's
concept is untyped, so the manifest's own note2 prediction ("flips to
'agree' only if okr scopes the checker's reader without touching inject")
has come true. Renamed the fixture (manifest key + corpus directory) to
match the red-*/green-* naming convention the parity unit test enforces,
and updated okf-frontmatter.mjs's header comment to match.
check-okf-parity.mjs: 10/10 fixtures pass. Full suite: 120/120.
Ref bump requested by repo-standard (two coord messages: v0.4.0 then
v0.5.0, superseding). Stat line re-measured at the v0.5.0 tag per the
badge-mirroring rule: checks table unchanged at 14, tests 111 -> 135
(node --test on a git-archive extraction of the tag, "ℹ tests" not
"ℹ pass"). check-versions.mjs: 12 OK / 0 WARN / 0 ERROR / 0 SKIP.
okr 1.9.0 "Styringssloeyfa lukkes" -- release. Catalog ref now pins the v1.9.0
tag so `claude plugin update` resolves the release.
Stat-linja rettet i samme slag: 14 -> 16 commands. Driften ble skapt av denne
releasen selv -- fase D la til /okr:rapport og /okr:arkivklar -- og
release-plugin.mjs flagget den som ERROR i stedet for aa gjette, som er riktig
oppfoersel. Tallet er verifisert mot disk (`ls commands/*.md | wc -l` = 16) og
mot pluginens egen badge, ikke lest fra prosa. Agenter (7) og hooks (3) uendret.
check-versions: 12 OK, 0 WARN, 0 ERROR, 0 SKIP.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EQ9kk8ZewiXsv5N98XFNwN
repo-standard v0.3.0 — release. Catalog ref now pins the v0.3.0 tag so `claude plugin update` resolves the release.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
"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
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