ktg-plugin-marketplace/docs/okf-second-brain/log.md
Kjell Tore Guttormsen 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

453 lines
38 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OKF second-brain convergence — coordination log
> Cross-repo coordination for the OKF-compatible second-brain form (`spec.md`). This is the **one
> shared place** all three plugin sessions read to know where the others are. OKF reserves `log.md`
> for change logs; this extends it with rollout status + the coordination protocol.
>
> **No writing crosses repo boundaries** — each plugin session writes only its own repo (+ the catalog
> with its own go). Status here is updated via operator relay.
## Coordination protocol
The operator runs one Claude session per plugin repo and relays between them. To keep three
independent sessions converged **without** cross-repo writes (mirrors the maskinrommet feedback-register
pattern):
1. **Single source of truth = `spec.md`.** The convention is defined once, here. No plugin redefines it
locally; a plugin's local OKF doc *references* this file. (Mirrors the global rule: don't invent
local mechanisms; extend the shared one.)
2. **This log is the cross-repo state.** Convention version, decisions, per-plugin conformance status,
open coordination items. All three sessions read it.
3. **No writing crosses repo boundaries.** Each session writes only its own repo. The catalog is shared
but needs a per-session go. A plugin records its own conformance in its own STATE/changelog; the
operator relays it here.
4. **Operator = relay + truth-source.** Convention changes are proposed by any session, written here
(with go), and the operator carries "convention changed → re-check conformance" to the other
sessions.
5. **Two version markers** (spec §12): `okf_version` (upstream Google OKF) and this convention's own
version. Either bump → log it below → each plugin re-checks. (A third spec-§12 marker, the optional
`okf_layout`, is a plugin-own layout snapshot — not a version; it triggers no cross-plugin re-check.)
6. **Conformance is verified, not asserted.** A plugin's status only moves to 🟢 after its bundle passes
the shared acceptance gate `catalog/scripts/okf-check.mjs` (spec §7) — `node catalog/scripts/okf-check.mjs <bundle-root>` → exit 0. On a relayed conformance landing, run the gate against that
plugin's bundle and record the result here. Evidence-based flips only (operator verification-plikt).
## Per-plugin conformance status
Legend: 🔵 not started · 🟡 building / partial · 🟢 conformant (+ commit-ref). **Ratification**
(spec accepted + plan adapted) is recorded in the Status cell with the plugin's own commit-ref —
distinct from conformance (code landed), which `linkedin-studio` alone holds so far.
| Plugin | Against minimal contract (spec §3) | Notes | Status |
|---|---|---|---|
| **linkedin-studio** | `type` + per-level `index.md` + root `okf_version` on `brain/`; `ingest/` excluded (round-trip-critical tributary) | Reference design. Emits frontmatter, adds no parser. Brain suite 134/134; passes the **shared gate** `catalog/scripts/okf-check.mjs` (scaffolded `brain/` → "OK: valid OKF bundle", exit 0). | 🟢 conformant @ linkedin-studio `da0a16a` (2026-06-26) |
| **okr** | `type` required + recommended-as-warnings + `okf_version` echo | Has the reference **writer + checker** (`okf-check.mjs`, `okf-index.mjs`, `lib/frontmatter.mjs`) + skill `okr-second-brain-search` v1.6.1. | 🟡 built · **spec ratified @ okr `75bfc9b` (2026-06-29)**; conformance-alignment landing = own go |
| **ms-ai-architect** | designed, not built | Targets the fuller OKF package + a retrieval skill. Builds against this spec. | 🔵 designed · **spec ratified @ ms-ai-architect `72a7e2b` (2026-06-29)**; build = own go |
## Landing protocol — how a sibling records conformance
When your plugin's bundle actually conforms (the work of step 4, done in your own session):
1. **Record it in your own repo** (STATE/changelog) — as the handoff already instructs.
2. **Update THIS file** (your own catalog-go): set your row in the status table above to
🟡 → **"claims conformant @ `<commit>`, bundle `<path>`, awaiting gate-verification"**.
3. A **linkedin-studio session** then runs the shared gate against your bundle —
`node catalog/scripts/okf-check.mjs <path>` — and, on exit 0, flips your row to 🟢 with the proof.
This puts the landing signal in the **one shared doc**, so the operator need not hand-carry status, and
any session sees the truth on its next read. **Honest limit:** there is no live push-notification across
separate sessions — a landing is discovered when a session next *reads* this log (a linkedin-studio
session is told to check it at start; see its STATE). Self-flipping straight to 🟢 is **not** the
protocol; 🟢 is reserved for the independent gate-verified step (operator verification-plikt).
## Open coordination items (what each session must confirm)
> **✅ Resolved 2026-06-29 — both siblings ratified.** okr (`75bfc9b`) and ms-ai-architect (`72a7e2b`)
> ratified `spec.md` and adapted their plans. The items below are **accepted via ratification**; they
> are kept as the record of what was asked. Any new field-gap, change-proposal, or conformance landing
> arrives as a **fresh item / status bump**, not here.
**→ okr session:**
- Confirm `okf-check.mjs` semantics are stable enough to stand as the reference contract (spec §3, §7),
and that this spec faithfully generalizes them (only-`type`-required; recommended → warnings;
`okf_version` echo).
- Canonical recommended-field name is **`resource`** (OKF), not `source` — confirm okr uses `resource`.
- Flag any field okr needs that the minimal contract + recommended set doesn't cover.
**→ ms-ai-architect session:**
- Confirm the minimal contract + extension-key model (spec §3, §5) supports the planned **"full OKF
package"** KB structure — going fuller is fine; the minimal contract is the **floor, not the ceiling**.
- **Field-name drift:** the architect brief writes `source`/`timestamp` (line 45); canonical is OKF's
**`resource`**. Align on `resource`.
- **mdcode is not an OKF tool** (spec §9.1) — drop it from the adoption plan. The `reference_agent`
enrichment is GCP/Gemini-bound (spec §9.2) — adopt the *prompt patterns*, not as drop-in code.
**→ both:**
- Ratify `spec.md` as the shared contract, or propose changes here.
- Retrieval-skill naming/home: okr shipped `okr-second-brain-search`; architect plans
`second-brain-search`. If a shared skill ever happens (Stage 3), converge naming + home (standalone
plugin, spec §11) — **not now** (Stage 2 measurement must justify it first).
## Deferred decisions
- **Spec §3/§6 vs. the gate's actual coverage.** The shared gate `okf-check.mjs` (faithfully lifted from
okr's reference) fails **only** on a concept file missing `type:`. It does **not** fail on a missing
root `okf_version` (echoed as `MISSING`, not an error), missing per-level `index.md` (§3 MUST), or an
`index.md` that carries frontmatter (§6 says it should not). So **"passes the gate" = "every concept
file has `type:`"** — a necessary but **partial** §3 signal, not full §3/§6 conformance. Surfaced when
portfolio-optimiser's bundle (index.md with frontmatter) passed. **To resolve in Stage 2 / a spec↔gate
reconciliation:** either tighten the gate to enforce more of §3/§6 (diverges this copy further from
okr — drift is two-way; fixes go upstream-first) or relax the spec's MUSTs to match what the gate
actually enforces. **Not changed now** — there is no established okr parity to protect (see the
2026-07-23 correction below); the fix belongs upstream, then re-vendored. _(linkedin-studio session,
2026-06-29; parity framing corrected 2026-07-23.)_
## Change log
- **2026-06-29** — Convention **v0.1** authored (`spec.md`) + this log. Seeded from the three per-plugin
design notes + linkedin-studio's verified premise corrections (mdcode ≠ OKF tool; no reusable OKF
ingest code; classify/convert is build-yourself). linkedin-studio recorded **🟢** (brain emits
OKF-compatible form, validated by the shared gate `okf-check`). okr / ms-ai-architect rollout =
separate per-repo go. _(Authored by the linkedin-studio session; operator relay to siblings pending.)_
- **2026-06-29** — **Stage 1 ratification complete across all three tracks.** okr ratified spec v0.1 +
adapted plan @ okr `75bfc9b`; ms-ai-architect ratified spec v0.1 + adapted plan @ ms-ai-architect
`72a7e2b` (both relayed via operator). The shared contract is now accepted by all three — the
interop goal of Stage 1 is met at the convention level. Conformance *landings* (okr form-alignment,
ms-ai-architect build) remain each their own go. _(linkedin-studio session, operator relay.)_
- **2026-06-29** — **Shared acceptance gate landed** (`catalog/scripts/okf-check.mjs` +
`okf-frontmatter.mjs` + `okf-check.test.mjs`). Lifted from okr's reference impl at `c06e4d7`; English
output, zero deps, self-contained. Verified: 33/33 catalog tests green; the gate's own §3 verdicts held
on okr fixtures (positive + negative) at lift-time; a scaffolded linkedin-studio
`brain/` validates clean (exit 0). Wired as the conformance gate (protocol §6 + spec §7): a plugin
only moves to 🟢 after passing it. The only Stage-3 remainder is reconciling the TS/mjs impls — not
required for the gate. _(linkedin-studio session.)_
- **2026-06-29** — **Ekstern form-konsument notert: portfolio-optimiser.** Et separat
Forgejo-rammeverk (MAF kostnads-optimiser, IKKE en marketplace-plugin) adopterte OKF-
minimal-formen uavhengig for sine per-prosjekt runtime-kunnskapsbundles — en ANNEN scope
enn denne konvensjonens bruker-second-brain (§1). Bundelen passerer den delte gaten
(`node catalog/scripts/okf-check.mjs <bundle>` → okf_version 0.1, "OK: valid OKF bundle",
exit 0) etter å ha lagt til rot-`okf_version`-markøren; commit portfolio-optimiser `812db23`.
Registrert så on-disk-FORMEN ikke driver fra hverandre i økosystemet (global regel: konformer
til den delte formen, ikke re-derive). IKKE et 4. konvergens-medlem — ingen bruker-second-brain,
ingen delt ingestion (spec §89: build-yourself), ingen delt retrieval. Eneste framtidige
overlapp: bygger portfolio-optimiser verdict-promotering (sitt «steg 8»), er den gjenbrukbare
skrive-primitiven okr's `okf-index.mjs` + frontmatter-skriver. Kjente avvik på bundelen:
2 `resource`-warnings (utelatelse tillatt, §4); `index.md` beholder frontmatter (avviker fra
§6 reservert-index, beholdt fordi dens `okf.py`-leser klassifiserer index på type).
_(Relayet fra portfolio-optimiser-sesjonen; bruk i en catalog-sesjon per protokoll §3.)_
**Gate re-verifisert i denne catalog-sesjonen (uavhengig):** `shared/examples/bygg-energi-mikro`
→ exit 0, 5 konsepter, 0 uten type, okf_version 0.1, nøyaktig de 2 `resource`-warnings nevnt
(`kilder-realiseringsgap.md`, `metode-ipmvp-a.md`); `index.md` bærer frontmatter (`type: index`);
commit `812db23` finnes lokalt. Påstandene stemmer.
- **2026-07-23** — **Parity claim retracted (drift correction).** Earlier entries and `spec.md` §7
stated the catalog gate is "byte-identical" to / "in verdict parity with" okr's checker. That is
**false against okr's current checker.** The copy was lifted once (`c06e4d7`, 2026-06-29) and never
updated; okr began hardening the next day (`3b45be7`, 2026-06-30: skip `innboks/`+dot-dirs, scoped
`checkBundle(root, { strictIngest, files })`) and added BOM/CRLF normalization weeks later
(`482effb`, 2026-07-17; `lib/frontmatter.mjs:23`) — none of which the catalog copy has. The two can
already diverge on the same input. The lift-time parity run was green but narrow (okr's own fixtures,
bundle-verdict) and is now stale. Establishing parity is tracked separate work: a CI-run gate over a
spec-derived adversarial corpus (`check-okf-parity.mjs`). Fixes go **upstream-first** — drift is
two-way; re-copying okr is the cause, not the cure. _(catalog session.)_
- **2026-07-23** — **`okf_version` / `okf_layout` split (spec §12).** `okf_version` had been carrying two
unrelated concerns — the upstream OKF version *and* a plugin's own layout revision. okr flagged this as
a blocker and left the call to the convention owner: its bundle roots + fixtures stamp
`okf_version: kb-layout-2026-06` (a layout snapshot, not `0.1`) — a known deviation okr already
documented, and it proposed exactly this two-field split (verified against okr `056b652`). **Decision
(owner, catalog):** `okf_version` stays the upstream Google OKF version alone (value set owned by
Google, single-valued — the bundle-root marker relies on that, §6); a new **optional** `okf_layout`
marker line holds a plugin's own layout-revision snapshot. **This step lands only the decision + spec
text** (§12) — *not* enforcement. §3 tightening that would flip okr's current value from "echoes an odd
value" to "fails the gate" stays deferred to its own step; the field's re-check semantics are pure echo
today, so okr's migration (move the value to `okf_layout`) is cheap when it happens, and it should
happen before that tightening. Additive + disambiguating: the §3 floor is unchanged and `okf_layout` is
optional, so **the convention version stays `0.1`** — no re-ratification triggered. _(catalog session.)_
- **2026-07-23** — **STEG 3: the running parity gate landed** (`scripts/check-okf-parity.mjs` +
`test/okf-parity-corpus/` + `check-okf-parity.test.mjs`). Parity is now a *running* per-file red/green
signal over a committed spec-adversarial corpus, not a stale one-shot claim (retracted above). **Verified
scope blocker (ground-truth this session, 2 independent agents + grep):** the round named ≥3 impls, but
**only two expose a runnable per-file checker** — catalog + okr. llm-ingestion-okf's Python lib is a
*producer* (no `check_bundle`, no CLI; checker is fase-2, its own repo); linkedin-studio's TS §3 logic
lives only in private test helpers (not a participant). **Decision (operator delegated on quality
grounds):** build the gate **n-way-capable, wire the 2 real impls now**, with a documented availability-
guarded seam for the Python checker (fase 2) and its Node port (fase 4) — no faked third impl, no
cross-repo code. Decisions the earlier record left open, now fixed: **(a) per-file contract** = each
impl's existing `checkBundle(root)` return normalized to `{ conceptCount, untyped[], okfVersion }`,
compared per file (concept-set + type verdict), over **default read-mode** (strictIngest off, not
files-scoped); **(b) adapter convention** = JS impls imported directly (both export `checkBundle`), zero
subprocess/zero dep; cross-repo/other-language impls get a subprocess `--json` adapter when they exist;
**(c) corpus form** = committed byte-exact fixtures (`.gitattributes -text` pins BOM/CRLF), the inspectable
"borne proof"; **(d) red-proof** = `expected: "diverge"` fixtures the gate MUST go red on (byte + tree
axes each carry one; canon = BOM+CRLF concept + `innboks/` raw file, catalog FAIL vs okr OK). Axis
decisions: IN = byte (BOM/CRLF), tree (innboks, dot-dir, node_modules[shared gap, both descend],
duplicate-name, hierarchical); **WITHDRAWN** = verbatim/trailing-newline (trinn E §1); **OUT of STEG 3** =
path-forms (rerouted to §1.2/STEG 5). The git/FS-hostile axes (live symlink, NFC/NFD filename) are
covered as **runtime-materialized meta-tests** (temp dir), not committed fixtures. The gate does **not**
claim the two checkers are identical (they provably are not) — it makes their divergence a monitored
fact. Verified: parity 8/8, `node check-okf-parity.mjs` → exit 0 ("parity holds"); regression 33/33;
`check-versions` 10 OK. Fixes stay **upstream-first** (patching BOM-norm into the catalog copy would just
re-diverge in the other direction). _(catalog session.)_
- **2026-07-24** — **STEG 0: nav-golden fixture class consumed + thin corpus gate landed**
(`test/nav-golden-corpus/` + `scripts/check-nav-golden.mjs` + `check-nav-golden.test.mjs`). commons
authored a `nav-golden` fixture class — each fixture is an OKF bundle paired with a committed
byte-exact `expected-read-context.md` golden (the fasit a conformant read-context navigator, commons
`method-spec.md §3 Step 1` + §11 Navigation boundary, must produce). **Consumed byte-exact from
portfolio-optimiser-commons `b641741`** (`nav-golden-hierarchy` positive + `nav-golden-escape`
boundary; `diff -r` identical; `.gitattributes -text` pins bytes; manifest carries source repo+SHA per
vendoring rule #7). **Scope decision (operator, thin):** the catalog is the convention owner and holds
no consumer (null konsument), and the shared retrieval skill is deferred (spec §10 Stage 3, "do not
build before Stage 2 says so") — so the gate does **not** run a 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
golden is present + non-empty. Byte-exact navigator conformance stays a consumer concern (okr STEG 4 /
the deferred Stage 3 skill). **Naming correction (relayed to + confirmed by commons via coord):** the
earlier record's "§5 pts 1-5" read-context label was stale — the settled normative location is
`method-spec §3 Step 1`'s five read-context bullets (commons `9801d35`); there is no open §5 dependency
(current spec §5 = extension keys). commons confirmed both prerequisites: Q1 `b641741` is the complete
nav-golden set (future cases additive, non-moving); Q2 the goldens derive from settled §3 Step 1.
Verified: `check-nav-golden` 10/10; gate CLI → exit 0 (2 fixtures PASS — hierarchy 5 concepts / escape 1,
`okf_version` 0.1, goldens present); full suite **73/73** across the six test files. _(catalog session.)_
- **2026-07-25** — **STEG 4: §3 tightened (non-enforcing) on the `okf_version` / `okf_layout` split.**
§3's `okf_version` MUST now states the value is the **upstream version alone**, with a plugin's own
layout revision belonging in the optional `okf_layout` marker (§12) — and marks itself **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 non-enforcing).
**Why non-enforcing (okr's answer, received via coord):** okr ratified the split and owns the
migration, but `scripts/okf-*` is file-fenced **frozen** through their 1.8.0 consolidation (Wave 4/6);
the migration runs as scoped work right after release. It is an **ETA, not an open blocker** — their
field is pure echo text with no validation semantics, so they do not fail the gate meanwhile. Making
§3 *enforce* `okf_layout` presence now would redden the STEG 3 parity gate on okr with nothing they
could do until 1.8.0 ships. Enforcement is therefore a separate scoped step, after their migration.
**Also settled this round (all verified against ground truth, not accepted as asserted):**
(a) **D2 roll-up carrier is a no-op for the public-mirror class**`build-rollup-register.mjs`
defaults `carrierMode` to `absent` and only `committed` reaches output B, so okr, ms-ai-architect and
claude-code-llm-wiki are excluded **by design**, never reported as missing/malformed; no code change.
(b) **The catalog runs no `index.md` generator** — read-side only (`okf-check.mjs:45`,
`check-nav-golden.mjs:48`); commons' inherited "catalog regenerates index.md" item (ingest-spec §6)
is **stale** and needs no §6 ruling. (c) **`okf_version` ruling already existed** — spec §12 (lines
174186) settled it; llm-ingestion-okf was pointed at the written text rather than issued a new one.
(d) **Correction issued to llm-ingestion-okf:** their premise that the catalog's `okf-check.mjs` is
"vendored byte-identical from okr" — and thus their Phase 4 conformance oracle — is **false**
(141 diff lines; okr's copy adds `strictIngest`, `files` scoping, `innboks`/dot-dir exclusion and
`lib/` deps). Parity here is **behavioural on the §3 floor in default read-mode**, gated by
`check-okf-parity.mjs`, never byte identity; their impl's real entry point is that gate's n-way
`IMPLS` registry behind `available()`, not a catalog `ref` (they are not a marketplace plugin, and
`check-versions.mjs`/`release-plugin.mjs` operate only over `marketplace.json` entries).
Verified: full suite **73/73** across the six test files; `check-versions` 11 OK · 0 WARN · 0 ERROR.
_(catalog session.)_
- **2026-07-25** — **STEG 5 (installation root) settled as _descriptive_, not normative: the sample
does not support a mandated path form.** The ecosystem was asked where each consumer installs its
bundle. Every answer was given **against code, not docs**, and each was re-verified here before
being acted on:
- **okr** — the only real installation. Two roots: project `.claude/okr/` **ahead of** home
`~/.claude/okr/org/`, each checked per-root (okr `scripts/okf-check.mjs:11`,
`lib/innboks-write.mjs:44`).
- **portfolio-optimiser-commons** — declined, correctly. Spec owner with no runnable pipeline; its
only bundle-shaped bytes are conformance fixtures, so answering would have codified a **test
artifact as an installation site**.
- **portfolio-optimiser** — **no root.** `--bundle-dir` defaults to `None` (`run.py:653`); absent
it, the feature is simply off. Verified here: **0 hits** for `expanduser|Path.home|.claude/`
across `src/`.
- **portfolio-optimiser-claude** — **no root.** `--bundle` defaults to `None` (`run.py:554`);
`bundle_dir` is a required non-empty config field (`contracts.py:81`). Verified here: **0 hits**
for the same patterns across `src/`.
**One installation, three non-installations** — so the standing acceptance criterion ("three
installations before normative text") is not merely unmet, it is **unmeetable from this
population**. Landed in `spec.md` as exactly two things: the §1 in-scope example corrected (it
showed a lone `~/.claude/<plugin>/…` form that misstates okr's project-first precedence), and a new
§8 bullet naming placement unmandated, **"no installation root" a conforming consumer shape**, and
*installing* vs. *writing* separate axes (a consumer may write into a bundle it never placed).
**No normative path form was written.**
Two things the responses did not supply, both found here: **(a)** neither portfolio-optimiser repo
reads `okf_version` at all (**0 hits** in `src/` for both), so neither is evidence for *or against*
marker-based discovery — though p-o-claude's fixture *carries* the marker, so a marker-based reader
would still recognise it. **(b)** p-o-claude's own account ("two entry points, both with no
default") is inexact: `run_s10.py:46` is a **third** `--bundle` entry point _(superseded — the full
set is **four**; see the method correction below)_ and it *does* carry a
default — `parents[2]/shared/examples/bygg-energi-mikro`, a repo-relative fixture. That leaves their
headline standing (no `~`/`$HOME`/`.claude` anywhere in `src/`) but it is the same
fixture-as-location class commons declined to answer from; returned to them.
This **confirms distilled note 3 ("discovery, not placement") rather than extending it** — the
measured population is dominated by that chain's first link, an explicit caller-supplied param. It
also bears on **Stage 2 (§10)**: the evidence points *away* from a Stage-3 discovery convention,
since three of four consumers have nothing to discover. _(catalog session.)_
- **2026-07-25** — **§1 corrected again: okr's two roots are not one ordering.** The reference impl
read the STEG 5 text and objected to a single word — §1 said okr "runs per-root over a project root
*ahead of* a home root". Verified here against their code, not their report, and the objection
holds: that phrasing **fused three distinct behaviours into one**.
- **Profile axis — precedence.** `hooks/scripts/inject-okr-context.mjs:54-56` resolves
`existsSync(projectConfigPath) ? projectConfigPath : (existsSync(homeConfigPath) ? … : null)`.
Genuine most-specific-wins; the project hit ends the lookup.
- **Retrieval axis — union.** `skills/okr-second-brain-search/SKILL.md:94` says "**Glob both
roots**" and does *not* short-circuit on the project root. The roots carry **different content**,
not two versions of the same: project = cycle/work data (cwd-bound), home = org identity
(survives reinstall). Their own source comment states it (`inject-okr-context.mjs:51-53`: "only
the org PROFILE resolves to home").
- **Checking — neither.** `scripts/okf-check.mjs:11` ("Kjoeres PER ROT") runs each root
*independently*: no precedence, no union.
So "ahead of" was true of exactly one of the three axes and false as a general 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 lives
here rather than in the spec: naming one consumer's internal resolution order in a scope section is
the same class of leak the format is meant to keep out. **Placement remains unmandated (§8);
nothing in the contract changed.** _(catalog session, on okr's correction.)_
- **2026-07-25** — **Method correction: a root-signature grep licenses "no installation root", not
"no default" — and we drew the wider conclusion too.** p-o-claude re-measured against their own
source after our (b) finding and reported the root cause, which turned out to generalize past them.
Citations pinned to commits, not lines — both consumer repos move faster than this doc
(portfolio-optimiser landed 8+ commits the same day, which already invalidated one line number
below).
- **The counting error.** p-o-claude's `--bundle` surface is **four** sites, not the three implied
above (@`bf50d2c`): `run.py:554` (`default=None`), `run_s10.py:46` (**has** a default —
`_DEFAULT_BUNDLE`, `run_s10.py:40`), `hitl.py:290` (`action="append"`, no default), and
`contracts.py:81` (required config field). Verified here against their tree; correction accepted
as theirs.
- **The same blind spot in our own measurement.** 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 the grep supported. Re-measuring
portfolio-optimiser by enumerating the declarations instead surfaces one **neither side had
reported**: `simulation.py:48` `_default_bundle_dir()``shared_root()/examples/bygg-energi-mikro`,
used at `simulation.py:293` (@`9e149c6`). So *both* PO repos carry a demo/fixture-shaped default,
not just p-o-claude.
- **Also stale:** the `run.py:653` citation above is now `run.py:679` (@`9e149c6`). The fact
(`--bundle-dir`, `default=None`) stands; the line does not.
**The headline is unchanged, and this is why it survives contact:** a fixture default resolved from
`__file__` or a re-pointable shared root aims at golden bytes, creates no installation root, and is
not user-owned second-brain state. The sample stays **one installation against three
non-installations**, STEG 5 stays descriptive, §8 is untouched. What changed is the *support*: "the
bundle dir is caller-supplied with no default" is too strong as written, and the accurate claim is
the narrower one the grep actually proved — **no installation root anywhere in either `src/`**.
Standing rule for the next round: ask for the enumeration, not the null result — a search shaped
like an install path cannot see a fixture path. _(catalog session, on p-o-claude's correction.)_
- **2026-07-25** — **The enumeration above was itself incomplete: two entries were unreported, not
one.** portfolio-optimiser answered our published finding by enumerating their own surface, and the
count is **four** (verified here against their tree @`9e149c6`, every site re-read):
`run.py:679` (`--bundle-dir`, `default=None`), `run.py:249` (library param `run_project(bundle_dir=)`,
default `None`), `simulation.py:48` `_default_bundle_dir()` (the fixture default we found), and
**`reference_domain.py:49` `Project.bundle_dir`** — a per-project path in the packaged reference
portfolio, threaded to `run_project` at `run.py:644` and resolved against **package data**
(`reference_domain.py:70`, `files("portfolio_optimiser").joinpath(f"data/{rel}")`). The shipped
`reference_projects.json` sets only `docs_dir`, so it is **dormant**: a capability with no value
today, and the day it gets one it points into Python package data.
- **What this corrects here:** the entry above says our re-measurement "surfaces **one** neither
side had reported". It surfaced one **of two**. The claim implied a completeness the enumeration
did not have — the same shape of over-reach as the null-result inference it was correcting.
- **Why the dormant one is the interesting miss:** it has no flag form at all. It is a key in
packaged JSON, so no search shaped like a CLI entry point — ours or theirs — could ever have seen
it. That sharpens the standing rule: *a search shaped like one entry type cannot see another*, of
which "an install-shaped search cannot see a fixture path" is one instance, not the general case.
- **Classification unchanged, and re-verified against their anchors:** `shared_root.py:15`
`ENV_VAR = "PORTFOLIO_SHARED_ROOT"`, `:17` `_DEFAULT = Path(__file__).resolve().parents[2]/"shared"`
— default *and* override both point at a checked-out spec subtree, never a home directory. The
env var exists so `shared/` can be extracted to its own repo without code change; re-pointing it
re-points to another spec tree. `expanduser|Path.home|\.claude/` over `src/` still gives **0
hits** @`9e149c6`. **One installation against three non-installations stands.** Their own
sharper wording, adopted: not "caller-supplied with no default" but **no *installation* default**
a fixture default in the simulation entry, a dormant package-data path in the reference portfolio.
_(catalog session, on portfolio-optimiser's unprompted enumeration.)_
- **2026-07-25** — **STEG 4 completed: §3 `okf_version` is now ENFORCED on shape; convention version
0.1 → 0.2.** The reservation added on 2026-07-23 ("enforcement waits until the emitters have
migrated") had its condition measured, not assumed. **The emitter set is two, not three:**
- **okr** @`0059da7` (v1.8.1) — migrated. `okf-index.mjs` emits `okf_version: 0.1` +
`okf_layout: kb-layout-2026-06`, with a verbatim migration path for legacy roots.
- **linkedin-studio** — `scripts/brain/src/scaffold.ts:38` emits `okf_version: 0.1`. It never
carried a layout string, and has no `okf_layout` (0 hits) because it needs none.
- **ms-ai-architect is not an emitter at all** — **zero `index.md` in the repo**; `okf_version`
occurs in exactly one planning document. This log's own status table already said so (🔵
"designed, not built"), but the reservation's phrase "the emitters" had been read as including
it. Nothing to migrate, so it cannot gate enforcement.
Swept wider than the two named: every `okf_version` value across the marketplace **and** the
sibling consumer repos is `0.1`. The only `kb-layout-2026-06` occurrences are okr's own
migration-test inputs and prose in these docs. **No live emitter anywhere carries a layout
string**, so the flip is a no-op against today's ecosystem and locks the invariant going forward.
**What the gate does and deliberately does not do.** `okf-check.mjs` rejects a value that is not
version-shaped (`/^\d+(\.\d+)*$/`). It asserts **nothing about which upstream versions exist**
that value set is Google's (§12), so a bundle targeting a newer upstream version passes. This
matters: a checker that validated *membership* would be the convention claiming ownership of a set
§12 says it does not own — the same over-reach class this round corrected three times. **Presence
stays unenforced** (absent → reported, not failed); that is a separate §3 MUST and a separate step.
**Convention version bumped 0.1 → 0.2**, by this log's own stated criterion. The 2026-07-23 entry
declined a bump because "the set of conforming bundles is unchanged (a clarification, deliberately
non-enforcing)". Here the set **does** change: the spec explicitly declared that an emitter
carrying a layout string "conforms today", and rollout rule 6 defines conformance as gate output
("verified, not asserted"). Per §12 the bump triggers a per-plugin re-check — which the sweep above
has already pre-measured as finding **zero** violations. Side benefit: the convention version is no
longer numerically confusable with upstream OKF v0.1.
**The parity gate was blind to this axis, and that is now fixed.** `check-okf-parity.mjs` compared
the normalized tuple `{conceptCount, untyped, okfVersion}` — the `okf_version` **value**. But when
two checkers disagree about whether a value is *acceptable*, the value is identical, so the axis
read **agree**. A false green on exactly the drift the gate exists to catch. The signature now
carries a boolean shape **verdict** (`okfVersionAccepted`), normalized as a verdict rather than a
message so two enforcing impls agree even if they word rejection differently. New corpus fixture
**`red-marker-layout`** (`expected: "diverge"`) is the red proof, and the CLI now prints
`(accepted)`/`(REJECTED)` because on this axis both impls print the same `okf=` value.
**Known, deliberate divergence:** catalog now enforces; okr still pure-echoes (their `CHANGELOG.md`
for 1.8.1: "verdiene valideres fortsatt ikke, siden spec §3 ennå ikke er håndhevende på form" — a
statement that was true when written and is now stale). The `diverge` expectation **encodes okr's
lag, not a design split**, and flips to `agree` when they mirror it. okr notified; the standing
promise to notify llm-ingestion-okf on any `okf-check.mjs` change was honoured in the same round.
Suite **73 → 78** across the six test files. _(catalog session.)_
- **2026-07-25** — **The §8 "contradiction" was ours to misread, and okr's own doc was the thing
that was wrong.** We had flagged `SKILL.md:94` ("Glob both roots" = union) against `CLAUDE.md:67`
("project preferred, else home" = precedence) and asked okr to adjudicate, assuming SKILL.md
because it describes actual procedure. That guess was right, and right for the stated reason.
Verified here against their files @`52129b5`, not against their summary: `SKILL.md:35-36` "always
search both, project first", `:46-47` "Project content overrides home content **on conflict**
(most-specific-wins)", `:94-95` "Glob both roots". **Union is the search space; precedence is a
tie-break that only fires when the same content exists in both roots.** The two statements were
orthogonal all along — which is exactly why one file could carry both without contradicting
itself. okr corrected `CLAUDE.md:67` (the word "else" made it false by implying a lookup that
stops at the first root). **§8's status is unchanged — still OPEN at the convention level** — but
its *description* of okr was refined: retrieval carries union **and** precedence as two layers,
not one axis each. One hole, read from three sides independently (commons from the ordering axis,
okr from their own doc, us from the §8 text). _(catalog session, on okr's answer.)_
- **2026-07-25** — **A second consumer requires the exact construction rule §3/§6 forbids, and does
so deliberately.** llm-ingestion-okf reported it unprompted while deciding whether to make our
"authored enumeration, never a filesystem read" rule a library invariant. Re-read here out of the
wiki's own code @`59ef033`, not relayed: `validate.py:74` puts `BUNDLE_INDEX_COMPLETE` at
**ERROR**, and `:1097-1104` builds `expected` by enumerating the directory's files, then requires
the index links to match **bidirectionally**; `bundle.py:498` `_index_entries` is machine
generation ("Everything sorted, so regeneration is byte-identical").
- **This is not the trap we warned about — it is its mirror image, chosen.** Our rule exists
because a derived index *cannot disagree* with the directory, so it cannot reveal that something
is missing or misfiled: a silent failure mode. The wiki makes "the index cannot disagree with
the directory" an **enforced invariant with a loud outcome**. Our rule serves a convention whose
index is a curated selection with progressive-disclosure prose, i.e. one that *must* be able to
disagree; theirs serves one where it must not. Neither is incoherent inside its own spec.
- **Consequence accepted, and it is theirs, not ours:** authored-vs-derived cannot be a library
invariant in **either** direction. It becomes policy alongside the match rule; nothing in the
library enumerates a directory unless the profile in force says the index is derived.
- **The sharpest argument came back at us:** a policy field carrying only "per-directory: yes"
would have hidden this difference entirely — two consumers, identical surface requirement,
opposite construction rule underneath. That is a better argument for splitting *scope* from
*construction* than the one we gave them. _(catalog session, on llm-ingestion-okf's measurement.)_
## Distilled architecture notes (OKF round, 2026-07)
Durable conclusions from the cross-repo round (full working context retained by the catalog session):
1. **One form, two depths.** A flat bundle is a degenerate depth-1 of the spec §3 tree, not a
separate form.
2. **A shared fixture-suite is blocked** on three things: a sibling's golden-test invariant, a
commons-owned ingest spec, and this convention's own unimplemented per-level rule.
3. **Discovery, not placement.** The bundle marker is the root `index.md` + `okf_version`; resolution
is explicit param → plugin config → environment → search root. The marker itself is inert.
4. **A closed `type` vocabulary is a writer requirement, not a form requirement** — it constrains the
`type` value, not the field-set.
5. **The parity check was actually run and was green** — but at lift-time, against okr's own fixtures,
at bundle-verdict granularity. "Spec-derived" is the load-bearing word, not "spec-owned": the
corpus is derived from the spec, not certified by any one implementation.
6. **No artifact may self-certify parity.** Parity is a gate's output over a corpus, never a claim in a
file's header or comment.
7. **Vendoring requires** a provenance pointer (source repo + SHA), a CI gate, and upstream-first fixes.