feat(okf-v0.2): D5 — the v0.2 golden fixture, with okf_version in root frontmatter

Placement settled by catalog's own reading of upstream at the pinned commit
3fcbb9f: SS8:509-510 and SS12:773-775 both put `okf_version` in a bundle-root
`index.md` frontmatter block, and SS12 calls it the only place frontmatter is
permitted in an index. Catalog's spec says the opposite about the same file;
that divergence is theirs against upstream, and we conform to upstream.

The value never touches a profile. `OKF_V0_2.index.root_frontmatter` names the
key; the caller supplies the value through a new keyword-only
`root_frontmatter_values` mapping. That keeps V4/V-A5 intact - `okf_version`'s
value tracks the upstream Google version and belongs to catalog (E1), so a
constant here would claim a decision we do not own and would have to be chased
on every upstream release. In the fixture the value is fixture DATA
(`okf-version.txt`), not a literal in our source.

Ordering comes from the policy, not the caller's mapping: a dict preserves
insertion order, so two callers passing the same keys would otherwise emit
different bytes. A key the policy does not name is refused fail-fast, before
any disk mutation. Omitting the argument emits no block at all - SS12 is a MAY
and none of upstream's four reference bundles declares the key.

The block is written only when the index is CREATED, so a re-run into an
existing bundle stays byte-identical (A-E5).

Raw-byte assertions rather than parsed ones, on the committed fixture as well
as on fresh runs: catalog measured that a quoted value fails their shape regex
with exit 1 and that a BOM hides the marker while still exiting 0.
`yaml.safe_load` returns "0.2" either way and strips a BOM first, so a parsed
assertion masks exactly those two defects. Asserting the frozen fixture catches
what a self-comparison cannot - regenerating from a broken emitter moves both
sides together.

A-E6 is now placement-explicit (promised catalog in 99cf987), and separates the
two byte properties: BOM-free is a property of the file, unquoted is a property
of CATALOG'S GATE and not of OKF v0.2 - upstream's own SS12 example is quoted,
so their gate rejects the spec's canonical form.

README gains the upstream-version section it was missing; CLAUDE.md gains the
mechanism behind "no profile hard-codes an upstream version": a profile names a
key, a caller owns its value.

550 -> 559 tests. test_profile_threading's `OKF_V0_2.index is DEFAULT.index`
assertion is replaced rather than deleted: object identity was a proxy for "the
shipped profiles differ in no NAME-bearing field", which is what makes the
synthetic test profile necessary, so the guard now asserts that directly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dgkSPjkLpACjMayd9R5jx
This commit is contained in:
Kjell Tore Guttormsen 2026-07-31 17:27:48 +02:00
commit 2504011010
14 changed files with 470 additions and 34 deletions

View file

@ -0,0 +1,6 @@
---
okf_version: 0.2
---
Golden OKF v0.2 bundle: regional sales extracted from a CSV source.
- [Regional Sales](ingest-sales.md)

View file

@ -0,0 +1,16 @@
---
type: dataset
title: Regional Sales
source_system: golden-v0-2-sales
source_query: sales.csv
ingested_at: 2026-07-16T12:00:00Z
ingest_manifest: manifest@a83c86e8f847eca2
generated: { by: process:llm-ingestion-okf, at: 2026-07-16T12:00:00Z }
sources: [{ id: golden-v0-2-sales, resource: fixture }]
---
| region | units | revenue |
| --- | --- | --- |
| nord | 412 | 88120 |
| vest | 297 | 61540 |
| sor | 158 | 33010 |

View file

@ -0,0 +1,4 @@
region,units,revenue
nord,412,88120
vest,297,61540
sor,158,33010
1 region units revenue
2 nord 412 88120
3 vest 297 61540
4 sor 158 33010

View file

@ -0,0 +1 @@
2026-07-16T12:00:00Z

View file

@ -0,0 +1,18 @@
{
"manifest_version": 1,
"source": {
"type": "file",
"id": "golden-v0-2-sales",
"root": "fixture"
},
"bundle_summary": "Golden OKF v0.2 bundle: regional sales extracted from a CSV source.",
"extractions": [
{
"id": "sales",
"title": "Regional Sales",
"query": "sales.csv",
"okf_type": "dataset",
"max_rows": 10
}
]
}

View file

@ -0,0 +1 @@
0.2