docs(okf-v0.2): read upstream's reference bundles, not just its spec

V-A1 is discharged: everything is now read at pinned commit 3fcbb9f, not off
main. v0.2 itself landed in 780fe9d; SPEC.md was edited after it, so "the v0.2
commit" and "the current spec text" are different objects.

Session 19 read the spec. It never read the four bundles the tooling migrated
to v0.2, and reading them corrected things a spec reading had settled wrongly.
okf/samples/ga4_merch_store is not a bundle -- it is a runner config that
generates one, so it says nothing about output shape.

- U1 No reference bundle declares okf_version. All four root index.md files
  have no frontmatter at all. A-E6 is therefore a stricter posture than
  upstream's own implementation -- defensible, but a decision rather than an
  assumption. po-claude's "deviation" #2 was conformance. catalog's gate reports
  MISSING on every official Google bundle.
- U2 Root index.md is the ONLY index permitted to carry frontmatter (12).
  Constrains the fixture and the index policy.
- U3 `generated` is used for HUMAN-authored content upstream, so it cannot be a
  machine-generated or ownership predicate. Empirical confirmation of commons'
  axis finding, stronger than their spec-text argument.
- U4 Real v0.2 frontmatter is multi-line block YAML: flow sequences, block lists
  of flow mappings, nested mappings, block lists of multi-key mappings, booleans,
  dates. Requirement 1 was scoped against a list of strings; the canonical shape
  is a list of five-key mappings. The one-session sizing must be redone.
- U5 7's actor convention gives `<producer>/<version>` for tools, and upstream
  uses it. That is real evidence for (b), against the (d) we recommended to
  commons today. Sent to them as a correction.
- U6 Conformance and the consumer-tolerance MUSTs quoted verbatim, including the
  bare-`verified`-as-one-element-list requirement on D1's reader.
- U7 An undocumented `not:` family observed in a bundle, unresolved, recorded so
  it is not mistaken for checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2aKJxLejT9S8jYwoZ9fut
This commit is contained in:
Kjell Tore Guttormsen 2026-07-26 19:09:03 +02:00
commit 9bffc92abc

View file

@ -31,13 +31,159 @@ verdict wire formats and the full attestation runtime protocol to a future
revision**. The *format* is fully supportable; an unspecified runtime is not.
See D4.
## Provenance of the facts below
## Provenance of the facts below — V-A1 is DISCHARGED
Read from `GoogleCloudPlatform/knowledge-catalog`, `okf/SPEC.md` at **`main` on
2026-07-26** — a branch, not a tag. **First implementation step is to re-read the
spec at a pinned commit and record it**, exactly as assumption C2 pins the
proving consumer's validator to `9ee5a8e`. An enumeration read off a moving
branch is a premise, not a fact.
**Pinned 2026-07-26 to `3fcbb9f828c2f23d109c855ee403c3a4c81f3a96`** in
`GoogleCloudPlatform/knowledge-catalog` (2026-07-24, "Update SPEC.md"). v0.2
itself landed one commit earlier in `780fe9d30b5bbca8931256edf1d0290d6bda5462`
(2026-07-24, "okf: migrate format and tooling to Open Knowledge Format v0.2
(#227)"). Note that `SPEC.md` was edited **after** the migration commit, so "the
v0.2 commit" and "the current spec text" are not the same object — which is
precisely why the pin exists.
The earlier reading was taken from `main` on 2026-07-26 — a branch, not a tag —
and commons independently confirmed their own check hit the same moving
reference. Two readings of one unstable reference are not two confirmations.
That is now closed: everything below is read at the pinned commit.
Minor correction while pinning: `CLAUDE.md` says v0.2 shipped 2026-07-25. The
commit dates say 2026-07-24. Not load-bearing, but it was asserted rather than
measured.
## Grounding against upstream's own reference bundles (2026-07-26)
The spec was read in session 19. **The shipped examples were not**, and reading
them changed several things a spec reading alone had settled wrongly. A normative
spec says what is *permitted*; the reference bundles show what upstream actually
*emits* — and we were about to freeze a fixture and hand it to three pilots.
Read at the pinned commit: `okf/bundles/{acme_retail,crypto_bitcoin,ga4,stackoverflow}/`
— four bundles migrated to v0.2 by the tooling itself. `okf/samples/ga4_merch_store/`
is **not** a bundle: it is a runner config (`README.md` + `seeds.txt`) that drives
the reference agent to *generate* one, so it says nothing about output shape.
### U1 — No reference bundle declares `okf_version` at all
Measured on all four root `index.md` files: no frontmatter block whatsoever, no
BOM, LF-terminated, body starts directly at `# Subdirectories`. §12 makes the
declaration a **MAY**, and upstream's own tooling declines it.
Three consequences, all live:
- **A-E6 asks for a stricter posture than the reference implementation.** That is
a defensible choice — a bundle that declares its target version is more useful
to a gate than one that does not — but it must be a *decision*, not an
assumption that we are following upstream. It is now the former.
- **po-claude's "deviation" #2 was conformance, not deviation.** Their root
`index.md` has no frontmatter — the same shape as all four reference bundles.
Our expectation text was the outlier.
- **catalog's gate reports `MISSING` on every official Google reference bundle.**
Their gate reads `^okf_version:` from the root index. Worth telling them: the
BOM hole they measured is one way to get a meaningless green, and a
spec-conformant bundle that simply exercises the MAY is another.
### U2 — Root `index.md` is the ONLY index permitted to carry frontmatter
§12, verbatim: `okf_version` goes "in a bundle-root `index.md` frontmatter block
(**the only place frontmatter is permitted in an `index.md`**)". Confirmed in the
bundles: `tables/index.md` has no frontmatter. This constrains D5's fixture and
the index policy directly — a nested index that grows a frontmatter block is
non-conformant, not merely unusual.
### U3 — `generated` is attribution, and it is used for HUMAN-authored content
`metrics/gross-margin-legacy.md` carries
`generated: { by: human:jsmith@acme, at: 2024-01-15T10:00:00Z }`.
This is the empirical confirmation of commons' axis finding, and it is stronger
than the argument they made from the spec text alone: `generated` **cannot** serve
as a machine-generated predicate, because upstream writes it for hand-authored
files. Any implementation deriving "is this generated?" or "do we own this file?"
from the presence of `generated` is wrong under v0.2. `_is_ingest_owned` must key
on `generated.by == <our actor>` **and** `ingest_manifest`, exactly as commons
specified — presence alone is meaningless.
### U4 — Real v0.2 frontmatter is multi-line block YAML, not `key: value` lines
This is the finding with the largest implementation cost, and it invalidates the
sizing of tag requirement 1. Observed verbatim in `computations/gross-margin-period.md`:
```yaml
tags: [finance, margin, attested]
parameters:
- { name: period_start, type: date, required: true }
executor:
resource: skills/run-on-bq.md
receipt: [job_id, executed_sql, result]
generated: { by: reference_agent/gemini-2.5-pro, at: 2026-06-30T14:00:00Z }
verified:
- { by: human:jsmith@acme, at: 2026-07-01T09:00:00Z }
sources:
- id: margin-standard
resource: policies/margin-standard.md
title: Cost Allocation & Margin Standard (FY2026)
author: human:jsmith@acme
last_modified: 2026-06-15
```
Present in one file: flow sequences (`tags`, `receipt`), block lists of flow
mappings (`parameters`, `verified`), nested block mappings (`executor`), block
lists of **multi-key** mappings (`sources`), booleans (`required: true`), and
bare dates. §11 requires "a parseable **YAML** frontmatter block".
So requirement 1 — "`emit` accepts a block-list value (`sources`)" — was scoped
against a list of *strings*. The canonical shape is a list of *mappings with five
keys*. The plan's own rule applies to itself here: measure, do not reason. The
tag's emitter work is larger than one value type, and the sizing must be redone
before committing to a one-session estimate.
It also sharpens the §5 tension for commons: their ingest-spec requires "All
values MUST be single-line" (`:158`). `generated` as an inline flow mapping
satisfies that, which is what commons measured. Upstream's canonical `sources`
does **not** — it is inherently multi-line. Expressible as inline flow if forced,
but that is a deviation from the reference shape, and it is a `DEFAULT`-profile
question rather than an `OKF_V0_2` one.
### U5 — §7 actor convention is counter-evidence to our own V1 recommendation
Verbatim, three forms: `<producer>/<version>` for agents and tools (example given:
`reference_agent/gemini-2.5-pro`), `human:<id>` for a person, `process:<id>` for
an automated process. Consumers keying trust off the `human:` prefix means
producers **MUST** use it for hand-authored or human-confirmed content.
We recommended (d) `process:<fixed id>` to commons earlier today, partly on the
argument that a producer-and-version string inside a byte-compared shared golden
breaks `:29`. That argument stands. But **upstream's own reference implementation
uses the `<producer>/<version>` form**, which is real evidence for (b) that we did
not have when we wrote. Sent to commons as a correction rather than left to
surface during ratification — the option set they hand the operator has to carry
both facts.
### U6 — Conformance and consumer tolerance, verbatim
A bundle is conformant if every non-reserved `.md` has a parseable YAML
frontmatter block, every block has a non-empty `type`, and reserved filenames
(`index.md`, `log.md`) follow §8/§9. §4: `type` is "the only always-required key;
a concept carrying just `type` is fully conformant".
Consumers **MUST** treat a bare `verified` mapping as a one-element list (§5.2) —
a hard requirement on D1's reader, not a nicety. Consumers **MUST NOT** reject on:
missing optional frontmatter, unknown `type` values, unknown additional keys,
broken cross-links, missing `index.md`. `status` absent defaults to `stable`.
### U7 — One unresolved observation
`metrics/gross-margin.md` carries a `not:` family (`- term / why / instead`) that
we could not locate in the spec sections read. It is either a v0.1 field we never
enumerated or an undocumented one. **Not resolved**, recorded so it is not
mistaken for something already checked. It touches nothing in the tag.
### What this changes
Tag requirement 1 needs re-sizing (U4). Requirement 5's fixture must respect U2
and take U1 as an explicit decision. `_is_ingest_owned` gets U3 as its governing
fact. D1's reader gets the §5.2 bare-mapping MUST from U6. V1's option set gets
U5. None of it blocks steps 13, which change no behavior.
## What v0.2 actually changes