Commit graph

912 commits

Author SHA1 Message Date
814756af0d chore(catalog): bump repo-mailbox v0.14.0 -> v0.15.0
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>
2026-08-01 22:39:35 +02:00
84d9ee3495 chore(catalog): bump repo-mailbox v0.13.0 -> v0.14.0
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>
2026-08-01 22:01:10 +02:00
c4b776e4c6 fix(okf-check): required and recommended fields are read at top level only
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
2026-08-01 19:57:29 +02:00
0b1063e911 chore(catalog): pin repo-mailbox to v0.13.0
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
2026-07-31 21:41:34 +02:00
fa3c5d8482 fix(okf-check): recommended last-change field follows the bundle's okf_version
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
2026-07-31 21:27:31 +02:00
a67d7f5340 docs(catalog): repo-mailbox block describes board + route, not just coord-send
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.
2026-07-31 21:13:10 +02:00
999223508b docs(catalog): graceful-handoff block describes v3.x, not the v2 it replaced
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
2026-07-31 20:49:51 +02:00
950c7a9f94 docs(catalog): stat lines mirror each plugin's own badges
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
2026-07-31 18:36:02 +02:00
4078444d0f chore(catalog): bump repo-mailbox v0.12.0 -> v0.12.1
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>
2026-07-31 18:25:58 +02:00
6cfa6f1de6 docs(catalog): install line carries the requirement, not claims that rot
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
2026-07-31 18:21:21 +02:00
51c72f499f docs(catalog): trim voyage description 625 -> 237 chars
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
2026-07-31 18:10:53 +02:00
285b043e7b chore(catalog): bump okr v1.8.1 -> v1.8.2
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>
2026-07-31 17:39:05 +02:00
1ca27f6507 feat(okf): §6 placement follows upstream — okf_version in root frontmatter (spec 0.2 -> 0.3)
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
2026-07-31 17:36:15 +02:00
3dfc513655 chore(catalog): bump config-audit v5.12.5 -> v5.13.0
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>
2026-07-31 17:34:11 +02:00
c71738cc14 chore(catalog): bump repo-mailbox v0.11.0 -> v0.12.0
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>
2026-07-31 17:30:35 +02:00
5b9b3147cf chore(catalog): bump repo-mailbox v0.10.0 -> v0.11.0
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>
2026-07-31 15:50:59 +02:00
2efe98ba02 fix(rollup): discover git worktrees - .git tested for existence, not directory-ness
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
2026-07-31 15:48:41 +02:00
e57d2e349f chore(catalog): bump repo-mailbox v0.9.0 -> v0.10.0
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>
2026-07-31 10:23:13 +02:00
d84ea664ff chore(catalog): bump repo-mailbox v0.8.0 -> v0.9.0
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>
2026-07-28 21:15:25 +02:00
53e5b57884 chore(catalog): bump repo-mailbox v0.7.0 -> v0.8.0
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>
2026-07-27 20:31:32 +02:00
8cae6033f5 chore(catalog): bump repo-mailbox v0.6.0 -> v0.7.0
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>
2026-07-27 20:17:49 +02:00
3eb6869b6f chore(catalog): bump linkedin-studio v0.7.0 -> v0.8.0
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>
2026-07-27 09:11:47 +02:00
350d06ae1b chore(catalog): bump repo-mailbox v0.5.0 -> v0.6.0
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>
2026-07-26 21:03:48 +02:00
1eabad1d27 feat(rollup): V6 marker-loss gate + depth-1+2 discovery matching board.sh
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
2026-07-26 15:20:50 +02:00
5ddc6c77a5 docs(okf): §8 refined against okr's answer; record the wiki's opposite construction rule
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.
2026-07-25 20:40:06 +02:00
6a72b26985 feat(okf): enforce §3 okf_version shape, bump convention 0.1 -> 0.2
The 2026-07-23 reservation said enforcement waits until "the emitters have
migrated". Measured rather than assumed, and the emitter set turned out to be
TWO, not three:

  okr @0059da7       okf_version: 0.1 + okf_layout: kb-layout-2026-06. Migrated.
  linkedin-studio    scaffold.ts:38 -> okf_version: 0.1. Never carried a layout
                     string; has no okf_layout and needs none.
  ms-ai-architect    NOT an emitter. Zero index.md in the repo; okf_version
                     appears in one planning doc. The status table already said
                     "designed, not built" -- only the word "emitters" implied it.

Swept the whole marketplace plus the sibling consumer repos: every live
okf_version value is 0.1. The flip is a no-op today and locks the invariant.

The gate checks SHAPE (/^\d+(\.\d+)*$/), never membership: the upstream value
set is Google's (spec §12), so a bundle targeting a newer version passes. A
membership check would be the convention claiming a set it says it does not own
-- the over-reach class this round has corrected three times. Presence stays
unenforced (reported, not failed) as a separate §3 MUST.

Convention bumped 0.1 -> 0.2 by this log's own criterion: the set of conforming
bundles changed (the spec explicitly said a layout string "conforms today", and
rollout rule 6 defines conformance as gate output). The §12 per-plugin re-check
is pre-measured as finding zero violations.

Also closes a parity blind spot found while landing this: check-okf-parity
compared the okf_version VALUE, which is identical exactly when two impls
disagree about whether it is acceptable -- a false "agree" on the axis the gate
exists to watch. The signature now carries a boolean shape verdict, with
red-marker-layout as the committed red proof. Its "diverge" expectation encodes
okr's lag (they still pure-echo) and flips to "agree" when they mirror it.

And a correction the round earned: portfolio-optimiser enumerated their own
bundle surface and it is four, not three. The dormant fourth
(reference_domain.py:49 -> package data at :70) has no flag form at all, so our
published claim that the re-measurement surfaced "one" unreported entry was
itself one-of-two. Sharpens the standing rule: a search shaped like one entry
type cannot see another; install-vs-fixture is one instance, not the class.

Suite 73 -> 78. coord: PO replied, okr + llm-ingestion-okf notified (the latter
under the standing promise to flag any okf-check.mjs change).
2026-07-25 20:32:30 +02:00
3dad1f51ce chore(catalog): bump repo-mailbox v0.4.0 -> v0.5.0
repo-mailbox v0.5.0 — release. Catalog ref now pins the v0.5.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 18:44:40 +02:00
fdafd8b792 docs(okf): close commons' axis review — all four findings
commons reviewed the STEG 5 text at 3ccb5f6 against their own anchors.
Both questions we asked passed; the findings we did not ask about are
the ones that mattered. All four anchors re-verified here against their
files before acting — including their own mid-review correction, which
was right (the "never by directory enumeration" clause is
method-spec.md:82-83, not :70-73; :68-73 is the escape-not-depth rule).

3(b) — §3's "(directory enumeration)" was ambiguous against a rule that
forbids navigating by directory enumeration. Now "an authored
enumeration of that directory's children — never a filesystem read".
Fixed at BOTH sites: §3 and §6 (commons flagged one; the second was
found here). Their reason for flagging it hard holds: code written
against the wrong reading passes every test you would think to write.

3(a) — "This is exactly okr's okf-check.mjs semantics, generalized" read
as a restatement of upstream while being stricter than it. Upstream
binds index.md to the bundle root alone (method-spec.md:81-85); we bind
every level. That is a legitimate floor of our own under §8, but it must
not borrow upstream's authority. Now stated as a superset, with the
single point of difference named. This was also the catalog's own
longest-open proposed correction, independently confirmed.

Q2 — the precedence hole is now named OPEN in §8. The two shapes were
installed and not-installed; okr is a third, two marked roots at once,
and the marker predicate cannot say which is read. okr's answer is that
there is no single answer: precedence for the org profile
(inject-okr-context.mjs:54-56), union for retrieval
(okr-second-brain-search/SKILL.md:94), because the roots carry different
content. Free while placement is descriptive; the first question a
second implementer asks if marker-based discovery ever goes normative.

Q1 hygiene — "root" carries four specified meanings across this
ecosystem. §1's bare uses are now qualified, with the other three named
and anchored so a reader arriving from method-spec cannot misparse.

Nothing normative changed for consumers: placement stays unmandated, the
§3 floor is unchanged in substance, and no path form is mandated.

Verified: suite 73/73; check-versions 11 OK · 0 WARN · 0 ERROR. The
okf-check FAIL on docs/okf-second-brain is structural and pre-existing
(the spec directory is not itself a bundle) — confirmed identical at
HEAD before this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPHvLhn2U3j2XD3Cn8zeYa
2026-07-25 15:37:27 +02:00
c763a476b6 chore(catalog): bump okr v1.8.0 -> v1.8.1
okr v1.8.1 — release. Catalog ref now pins the v1.8.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 15:36:13 +02:00
9e98f51b9f docs(okf): method correction — the grep proved less than we claimed
p-o-claude re-measured their own source after our (b) finding and sent
back the root cause. It generalizes past them, including to us.

The counting error: their --bundle surface is four sites, not three
(run.py:554 default=None, run_s10.py:46 has a fixture default,
hitl.py:290 append/no default, contracts.py:81 required field).
Verified here against their tree, not their report.

The same blind spot in our own work: we greped both PO repos for the
installation-root signature (expanduser|Path.home|.claude/), got 0 hits,
and reported "no default". The grep was sound; the inference was wider
than it supported. Enumerating declarations instead surfaces one neither
side had reported — portfolio-optimiser's simulation.py:48
_default_bundle_dir() -> shared_root()/examples/bygg-energi-mikro, used
at simulation.py:293. Both PO repos carry a fixture-shaped default, not
just p-o-claude.

The headline is unchanged and survives contact: a fixture default aimed
at golden bytes creates no installation root and is not user-owned
second-brain state. Still one installation against three
non-installations; STEG 5 stays descriptive; §8 untouched. What changed
is the support — "caller-supplied with no default" was too strong, and
the accurate claim is the narrower one the grep actually proved: no
installation root anywhere in either src/.

Citations now pinned to commits rather than lines (PO 9e149c6, POC
bf50d2c) — portfolio-optimiser landed 8+ commits the same day and
already invalidated run.py:653, now run.py:679.

Verified: suite 73/73; 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
2026-07-25 15:25:53 +02:00
3aea016074 docs(okf): §1 — okr's two roots are not one ordering
The reference impl read the STEG 5 text and objected to one word: §1 said
okr "runs per-root over a project root … ahead of a home root". Verified
here against their code rather than their report, the objection holds —
that phrasing fused three distinct behaviours into one.

- profile axis is precedence (inject-okr-context.mjs:54-56 short-circuits
  on the project hit)
- retrieval axis is union (okr-second-brain-search/SKILL.md:94 globs both
  roots; they carry different content — project is cwd-bound cycle/work
  data, home is org identity that survives reinstall)
- checking is neither (okf-check.mjs:11 runs each root independently)

So "ahead of" was true of exactly one axis and false as a statement about
the only implementation §1 describes.

Fixed by deletion, not elaboration: §1's job is that placement is not in
this contract, and that claim never needed an ordering. The axis detail
goes to log.md instead — naming one consumer's internal resolution order
in a scope section is the same class of leak the format exists to keep
out.

Placement remains unmandated (§8); nothing in the contract changed.

Verified: suite 73/73 across the six test files; check-versions 11 OK ·
0 WARN · 0 ERROR (okr released v1.8.0 mid-session and bumped the catalog
ref themselves in 8afd4f0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPHvLhn2U3j2XD3Cn8zeYa
2026-07-25 15:17:15 +02:00
1b618c6c5d chore(catalog): bump repo-mailbox v0.3.0 -> v0.4.0
repo-mailbox v0.4.0 — release. Catalog ref now pins the v0.4.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 15:12:14 +02:00
8afd4f09bf chore(catalog): bump okr v1.7.1 -> v1.8.0
okr v1.8.0 — release. Catalog ref now pins the v1.8.0 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 15:04:58 +02:00
3ccb5f6afa docs(okf): STEG 5 — placement is descriptive, not normative
The sample does not support a mandated path form. Of the four consumers
polled, exactly one installs a bundle anywhere (okr: project .claude/okr/
ahead of home ~/.claude/okr/org/); the other three install none — the
bundle dir is a caller-supplied argument per run, with no default, no
discovery, and no $HOME/~ expansion in their sources (verified by grep in
each repo, not taken from their reports).

One installation and three non-installations makes the standing criterion
("three installations before normative text") unmeetable from this
population, so no normative path form was written.

- spec.md §1: correct the in-scope example. A lone `~/.claude/<plugin>/…`
  misstates okr's project-first precedence, i.e. it contradicts the only
  real implementation — a fix that stands on its own regardless of n.
- spec.md §8: placement unmandated; "no installation root" named a
  conforming consumer shape; installing vs. writing marked separate axes
  (a consumer may write into a bundle it never placed).
- log.md: the measured sample with file:line evidence, plus two findings
  the responses did not supply — neither portfolio-optimiser repo reads
  okf_version at all (so neither is evidence for or against marker-based
  discovery), and p-o-claude has a third --bundle entry point that does
  carry a fixture default, contra its own account.

Confirms distilled note 3 ("discovery, not placement") rather than
extending it, and bears on Stage 2 (§10): three of four consumers have
nothing to discover.

Verified: suite 73/73 across the six test files; check-versions 10 OK ·
1 WARN · 0 ERROR (okr 1.8.0 untagged — their release is still in flight).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CPHvLhn2U3j2XD3Cn8zeYa
2026-07-25 12:28:28 +02:00
e69fcd6653 chore(catalog): rename coord to repo-mailbox, pin v0.3.0
The plugin repo moved from open/coord to open/repo-mailbox. Bumps the
entry name, source URL and ref together, and updates the README heading,
link and label to match.

Also corrects the per-plugin stat line: it claimed 48 selftest checks;
the actual count has been 70 since v0.2.2.

check-versions.mjs: 11 plugins, 10 OK, 1 WARN (pre-existing okr), 0 ERROR.
2026-07-25 07:02:31 +02:00
9ca2c8bdaf docs(okf): STEG 4 — tighten §3 on okf_version/okf_layout (non-enforcing)
§3's okf_version MUST now states the value is the upstream OKF version alone;
a plugin's own layout revision belongs in the optional okf_layout marker (§12).
Marked explicitly NOT YET ENFORCED — no checker validates the value's shape, so
an emitter still carrying a layout string conforms today.

No convention version bump: §12 ties a bump to a change in the §3 floor, and the
set of conforming bundles is unchanged (a clarification, deliberately inert).

Non-enforcing is the deliberate shape. okr ratified the split and owns the
migration, but their scripts/okf-* are file-fenced frozen through the 1.8.0
consolidation. Enforcing okf_layout presence now would redden the STEG 3 parity
gate on okr with nothing they could do until that ships. Enforcement is a
separate scoped step after their migration lands.

log.md records the round's other settled items, each verified against ground
truth rather than accepted as asserted: the roll-up carrier is a no-op for the
public-mirror class (builder tolerates absence by design); the catalog runs no
index.md generator (read-side only), so commons' inherited item is stale; the
okf_version ruling already existed in §12; and the catalog's okf-check.mjs is
NOT byte-identical to okr's (141 differing lines), so parity here is behavioural
over the §3 floor in default read-mode via check-okf-parity.mjs — never byte
identity.

Verified: suite 73/73, check-okf-parity 8/8 exit 0, 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
2026-07-25 06:43:38 +02:00
d0dbf8e4f7 chore(catalog): bump coord v0.2.1 -> v0.2.2
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvTviFeoMCKJcALATRempy
2026-07-25 06:41:24 +02:00
c712d74842 chore(catalog): bump coord v0.2.0 -> v0.2.1
coord v0.2.1 — release. Catalog ref now pins the v0.2.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-25 06:20:27 +02:00
325727523d test(okf): consume nav-golden fixtures + thin STEG 0 corpus gate
Consume commons' nav-golden fixture class byte-exact from
portfolio-optimiser-commons @ b641741 (nav-golden-hierarchy positive +
nav-golden-escape boundary) into test/nav-golden-corpus/ and wire a thin
gate scripts/check-nav-golden.mjs (+ .test.mjs, 10 tests).

Scope (operator decision, thin): the catalog is the convention owner and
holds no consumer (null konsument), and the shared retrieval skill is
deferred (spec.md §10 Stage 3). So the gate does NOT run a read-context
navigator and does NOT assert the goldens byte-exact. It asserts only what
the catalog owns: each fixture bundle/ is a conformant OKF bundle under the
existing §3 checkBundle (every concept typed + root okf_version), and the
committed expected-read-context.md golden is present and non-empty. Byte-exact
navigator conformance stays a consumer concern (okr STEG 4 / Stage 3 skill).

Fixtures pinned byte-exact (.gitattributes -text); manifest carries source
repo+SHA per the vendoring-provenance rule. Naming: the stale "§5 pts 1-5"
read-context label maps to the settled method-spec §3 Step 1 (commons 9801d35);
no open §5 dependency. commons confirmed b641741 complete + goldens derived
from §3 Step 1 (via coord).

Verified: check-nav-golden 10/10; gate CLI exit 0 (2 fixtures PASS); full
suite 73/73 across the six test files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeK9hkxrU9wFPBYGYnSV1V
2026-07-24 20:35:44 +02:00
0bca9c7525 chore(catalog): bump coord v0.1.0 -> v0.2.0
coord 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>
2026-07-24 19:58:12 +02:00
23394a478e feat(catalog): add coord v0.1.0
Local inter-repo coordination mailbox — directed messages and broadcasts
between Claude Code sessions, injected as context at session start.
New plugin repo: open/coord, pinned at v0.1.0. check-versions: 11/11 OK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBbjgS5A55RVavoyjJC4FX
2026-07-24 19:44:55 +02:00
ba844976e9 feat(catalog): add state roll-up register builder (STEG 0 wiring)
Wire the two-output roll-up register per the ratified D2 contract
(~/.claude/coord/register.md; commons c66ccc3 + status vocab fe6b998),
resolving the AS#5 gate the coord notice handed catalog.

- Output A: rich LOCAL roll-up grepped from ~/repos/*/STATE.md markers.
- Output B: public status-token index, a projection of A, opt-in via a
  committed .rollup-carrier; absent/private modes excluded by design.
- V4 public-safety gate: a carrier line must be exactly "topic: <token>"
  (no prose, no em-dash, known token) or it is blocked from B.
- V5 drift-warn: committed-carrier status != STATE status -> warn; STATE wins.

Pure-function core + thin ~/repos CLI shell, zero deps, catalog script
pattern. 22/22 tests over the ratified adversarial axes. Commits no
carrier/output (AS#5 discipline: catalog is public-mirror class -> mode absent).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeK9hkxrU9wFPBYGYnSV1V
2026-07-24 01:46:53 +02:00
09521f8f2d test(okf): add running n-way per-file parity gate + adversarial corpus (STEG 3)
Make OKF §3 checker parity a RUNNING per-file red/green signal instead of a
stale one-shot claim. The catalog and okr checkers provably diverge on the same
input (catalog walks everything + no BOM/CRLF norm; okr skips innboks/dot-dirs +
normalizes); this gate turns that divergence into a monitored, tested fact.

- scripts/check-okf-parity.mjs: n-way runner, zero-dep. Normalizes each impl's
  existing checkBundle(root) return to {conceptCount, untyped[], okfVersion} and
  compares per file over default read-mode. Impl registry is availability-guarded
  so a catalog-only checkout degrades gracefully; a documented subprocess seam
  awaits llm-ingestion-okf's Python checker (fase 2) + Node port (fase 4).
- test/okf-parity-corpus/: committed byte-exact adversarial corpus + manifest.
  Red-proof fixtures (expected: diverge) the gate MUST go red on — byte axis
  (BOM+CRLF) and tree axis (innboks, dot-dir) each carry one; canon = both.
  .gitattributes -text pins the BOM/CRLF bytes. Green fixtures pin agreement
  incl. a SHARED gap (both descend into node_modules).
- check-okf-parity.test.mjs: 8/8. Corpus assertions + byte-tracking red-proof +
  runtime-materialized symlink/NFC-NFD meta-tests + graceful-skip seam.

Honest scope: only 2 impls expose a runnable per-file checker today, so the gate
runs 2-way and is architected n-way — no faked third impl, no cross-repo code.
spec §7 + log.md updated (no self-certified parity; fixes stay upstream-first).

Verified: parity 8/8, CLI exit 0; regression 33/33; check-versions 10 OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeK9hkxrU9wFPBYGYnSV1V
2026-07-24 01:23:46 +02:00
3be4321a79 docs(okf): split okf_version/okf_layout in spec §12 (STEG 2)
okf_version had been carrying two unrelated concerns — the upstream OKF
version and a plugin's own layout revision. Split into two markers:
okf_version stays the upstream Google OKF version alone (currently 0.1,
value set owned by Google, single-valued bundle-root marker); a new
optional okf_layout marker holds a plugin's layout-revision snapshot.

Verified against ground truth: okr 056b652 stamps
okf_version: kb-layout-2026-06 (fixtures + bundle roots) — a known
deviation okr itself flagged, and it proposed exactly this okf_layout split.

Lands only the decision + spec text — NOT enforcement (§3 tightening stays
deferred to its own step, so okr's current value isn't flipped to a gate
failure yet; its migration is cheap since the field is pure echo today).
Additive + disambiguating: §3 floor unchanged, okf_layout optional, so the
convention version stays 0.1 — no re-ratification triggered.

- spec.md §12: rewrite defining the split
- log.md: protocol §5 clarified (third non-version marker) + dated change-log entry

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeK9hkxrU9wFPBYGYnSV1V
2026-07-23 22:29:29 +02:00
548a9abab3 docs(okf): retract false okr verdict-parity claim + fold in 7 distilled notes
The shared checker (scripts/okf-check.mjs) was lifted from okr once (c06e4d7,
2026-06-29) and never updated; okr hardened its checker afterward (skip
innboks/dot-dirs + scoped checkBundle @ 3b45be7, 2026-06-30; BOM/CRLF
normalization @ 482effb, 2026-07-17). The two have diverged and are NOT
verdict-identical. Retract the "byte-identical / verdict parity is verified"
claim everywhere it stood (spec.md section 7, log.md incl. a handed-out
conformance flag, and both script headers), replacing it with a precise, dated
provenance note. Establishing parity is tracked separate work
(check-okf-parity.mjs); fixes go upstream-first (drift is two-way). No code
behavior changed. Also folds the round's 7 distilled architecture notes into
log.md. Tests 33/33.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 22:05:13 +02:00
1675ca36cf chore(catalog): bump linkedin-studio v0.6.0 -> v0.7.0
linkedin-studio 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>
2026-07-23 21:27:43 +02:00
09e4691c21 chore(catalog): bump okr v1.7.0 -> v1.7.1
okr v1.7.1 — release. Catalog ref now pins the v1.7.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 08:46:04 +02:00
9d42292da6 chore(catalog): bump llm-security v7.8.2 -> v7.8.3
llm-security v7.8.3 — release. Catalog ref now pins the v7.8.3 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 11:02:36 +02:00
0549921b2b chore(catalog): bump llm-security v7.8.1 -> v7.8.2
llm-security v7.8.2 — release. Catalog ref now pins the v7.8.2 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 09:34:26 +02:00
99d7b6e387 chore(catalog): bump llm-security v7.8.0 -> v7.8.1
llm-security v7.8.1 — release. Catalog ref now pins the v7.8.1 tag so `claude plugin update` resolves the release.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 09:00:40 +02:00