docs(upstream): move the OKF pin to canonical ad30107, re-record V-A8

The operator authorized the move from `3fcbb9f` (frozen `knowledge-catalog/okf/`)
to `ad30107` in `GoogleCloudPlatform/open-knowledge-format`. Cost to our fixtures
was measured at zero bytes before the decision and is unchanged: `okf_spec_commit`
is a key `STRICT_V1` names, its value is the caller's under D5, and no shipped
fixture carries one.

The old hash stays in the alignment plan rather than being rewritten. Every fact
under that heading was *read* at `3fcbb9f`; replacing the hash would give those
facts a provenance they do not have. What moves is the tree we measure against.

V-A8 re-run at the new pin: 9/9 of our golden documents parse under upstream's
reader, 0 failures, 27/27 semantic-reader calls (`trust_tier`,
`normalize_verified`, `is_stale`) return without raising. The zeroes are
measurements — the harness was put to a known-positive in both directions first:
`type: [unclosed` raises `OKFDocumentError` while a well-formed control parses,
and `is_stale` returns True for a past `stale_after` and False for a future one.
Types recovered: `ingested_at` -> str (was datetime), `generated` -> dict,
`sources` -> list, `okf_version` -> float (A-E6, still upstream's).

The `38c713f` divergence is carried forward as a written known divergence rather
than left to evaporate with the pin, and it is now recorded at pin-level
precision. `38c713f` is not an ancestor of `3fcbb9f` (`merge-base
--is-ancestor` exits 1) — it landed three weeks forward of the pin we left, so
both the old and the new pin carry the bare-scalar `tags:` form and the move
loses nothing. The accurate statement is that canonical ships a form its own
frozen predecessor has already repaired.

The open question is closed rather than deferred, because it was cheap: across
129 tracked text files present in both trees, 9 carry frozen-only lines - 8 are
`38c713f` and the 9th is the freeze notice in `README.md`. Zero files are
frozen-only. The divergence is fully enumerated.

Runbook Step 3a gains the harness trap that cost this round a re-run: the
semantic readers take the frontmatter mapping, not the document, and passing the
document raises an AttributeError that reads like an upstream incompatibility.
This commit is contained in:
Kjell Tore Guttormsen 2026-08-23 20:30:22 +02:00
commit e286b5a173
3 changed files with 109 additions and 15 deletions

View file

@ -24,9 +24,9 @@ Everything below was read at a fixed commit, never at a branch.
| What | Commit | Date | Role |
|---|---|---|---|
| `GoogleCloudPlatform/open-knowledge-format` | `ad30107c31c06aec8a7d5636e0d1058118604e6f` | 2026-08-21 | **New canonical source.** Read at this pin |
| `GoogleCloudPlatform/open-knowledge-format` | `ad30107c31c06aec8a7d5636e0d1058118604e6f` | 2026-08-21 | **New canonical source.** Read at this pin, and **our pin since 2026-08-23** |
| `GoogleCloudPlatform/knowledge-catalog` | `395a0c311979858dcecfed767810658baf3ca3f3` | 2026-08-22 | Frozen `okf/` snapshot, read for divergence |
| `GoogleCloudPlatform/knowledge-catalog` | `3fcbb9f828c2f23d109c855ee403c3a4c81f3a96` | 2026-07-24 | **Our current pin**, the v0.2-round baseline |
| `GoogleCloudPlatform/knowledge-catalog` | `3fcbb9f828c2f23d109c855ee403c3a4c81f3a96` | 2026-07-24 | Our pin until 2026-08-23, the v0.2-round baseline |
The order that authorized this run named `62432a09` as the target. That commit is
real (`okf: make every timestamp an ISO 8601 datetime with an explicit offset
@ -296,11 +296,13 @@ declare a version upstream has not minted. *Conform first, claim after.*
**zero bytes in our fixtures.** `okf_spec_commit` is a key the `STRICT_V1` profile
requires (`profiles.py:721,726`); its *value* is the caller's under D5, and no
shipped fixture carries one. The cost lands where D5 says it should — on the
caller that stamps it, as a re-run. This is a separate decision and is **not taken
here**, per the order.
caller that stamps it, as a re-run. **DONE 2026-08-23** on the operator's decision;
recorded in `docs/plan/okf-v0.2-alignment.md` § Provenance of the facts below.
3. **Re-record V-A8 at the new pin** in `docs/plan/okf-v0.2-alignment.md`'s
verification table, which currently reads *"DONE 2026-07-31 @ `3fcbb9f`: 13/13"*.
Pending the pin decision, so the two move together.
verification table. **DONE 2026-08-23 @ `ad30107`: 9/9 documents parse across all
four goldens, 0 failures, 27/27 semantic-reader calls clean**, with the harness put
to a known-positive first in both directions (malformed → `OKFDocumentError`;
`is_stale``True` on a past `stale_after`).
4. **Notify consumers** (Step 7) with the three questions above. Not sent this
round — the order scoped this to analysis and a plan document, and notification
is a sent action.
@ -315,6 +317,58 @@ question inside frontmatter we already gate; the persist gates are unchanged, an
standing posture that everything entering a bundle passes the guard is unaffected.
Noted, not built.
## Known divergence, carried forward past the pin move
The pin moved on 2026-08-23. This section exists so the divergence recorded in
Step 3 does not move with it, silently, and become a premise someone inherits in
three weeks.
**The divergence, at pin-level precision.** Step 3 measured it between the frozen
repository's *head* (`395a0c3`, 2026-08-23) and canonical `ad30107`, and that
measurement stands. What it did not say, and what matters when the pin actually
moves, is where our **old pin** sits:
| Tree | `tags:` form, the eight stackoverflow files |
|---|---|
| our old pin `3fcbb9f` (2026-07-24) | `tags: stackoverflow, users, community, reputation` — bare scalar |
| our new pin `ad30107` (2026-08-21, canonical) | `tags: stackoverflow, users, community, reputation` — bare scalar |
| frozen repo head `395a0c3` (2026-08-23) | `tags: [stackoverflow, users, community, reputation]` — flow sequence |
`38c713f` is dated 2026-08-14 and is **not an ancestor of `3fcbb9f`**
(`git merge-base --is-ancestor` → exit 1); it landed three weeks *forward* of the
pin we are leaving. **So the pin move loses nothing** — neither pin ever had the
fix. The correct statement is not "moving the pin drops `38c713f`" but: *a fix
upstream has already written is unreachable from the canonical tree, and the move
does not change that.* Canonical ships the form its own frozen predecessor has
repaired.
Writing it the loose way — "the frozen tree carries it, canonical lacks it" —
reads as content lost by moving, and would send a later session looking for a
regression the move did not cause.
**Is `38c713f` the only content that exists only in the frozen tree? Yes.** The
question was cheap, so it was answered rather than deferred. Denominator: 129
tracked text files present in both `395a0c3:okf/` and `ad30107`, compared as line
multisets. **Nine** files carry at least one frozen-only line: **eight** are
exactly `38c713f`'s `tags:` lines, and the ninth is `README.md`, whose eleven
frozen-only lines are upstream's own freeze notice — which by definition can only
exist in the frozen repository. **Zero** files exist only in the frozen tree;
canonical adds three (`CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `connectors/`).
Nothing else is frozen-only, so this divergence is fully enumerated and does not
need re-deriving next round.
**Our exposure: zero, and unchanged by the move.** This library never writes
`tags` (`grep` across 11 modules; one unrelated hit at `extract.py:86`, about HTML
tags). Door C merges external concepts verbatim by design, so a consumer importing
the canonical `stackoverflow` bundle carries the scalar form through unchanged —
the verbatim invariant working, not a defect.
**Related, not the same finding:** G33 records that `tags` and `description` block
bundle import universally at the guard, measured by
`llm-ingestion-pipeline-security`. That is a guard-grammar question on their side
of the seam. Noted here only so a later reader does not merge two `tags` findings
that share a key name and nothing else.
## Step 8 — Verification log
Every claim above and the command class that produced it. Corrections stay visible.
@ -337,6 +391,10 @@ Every claim above and the command class that produced it. Corrections stay visib
| V-A8 harness can detect failure | Deliberate `type: [unclosed``OKFDocumentError`; control parses |
| All 8 consumers present | `find ~/repos -maxdepth 3 -type d -name <n>`, with a known-positive control |
| Suite green | `.venv/bin/python -m pytest -q` → 596 passed |
| `38c713f` not an ancestor of `3fcbb9f` | `git merge-base --is-ancestor 38c713f 3fcbb9f` → exit 1 |
| Both pins carry the bare-scalar `tags:` | `grep -m1 '^tags:'` on the same 8 files in both `git archive` exports |
| `38c713f` is the only frozen-only content | Line-multiset difference over 129 files present in both trees: 9 files, 8 = `tags:`, 1 = the freeze notice in `README.md`; query validated by the 65/65 `tags:` control |
| V-A8 re-run @ `ad30107` | 9/9 parsed, 27/27 semantic calls clean; harness shown able to fail (`type: [unclosed``OKFDocumentError`) and able to report a positive (`is_stale``True` on a past `stale_after`) |
**Corrections made during this run, kept visible:**

View file

@ -33,7 +33,22 @@ See D4.
## Provenance of the facts below — V-A1 is DISCHARGED
**Pinned 2026-07-26 to `3fcbb9f828c2f23d109c855ee403c3a4c81f3a96`** in
**RE-PINNED 2026-08-23 to `ad30107c31c06aec8a7d5636e0d1058118604e6f`** in
`GoogleCloudPlatform/open-knowledge-format` (2026-08-21, merge of
`okf-iso-datetimes`, 132 tracked files) — the canonical home since upstream moved
OKF out of `knowledge-catalog` and froze the copy under `okf/`. Ordered
2026-08-23; the round that measured the move is
`docs/plan/okf-2026-08-timestamp-tightening.md`, and the cost of the move to our
fixtures was measured at zero bytes before it was taken.
**The old hash below is not stale text — it is provenance.** Every fact in this
document was *read* at `3fcbb9f`, and rewriting the hash would give those facts a
provenance they do not have. What moves with the pin is the tree we measure
*against* from now on, plus V-A8, which is re-recorded at the new pin in the
verification table. What upstream changed between the two pins is the subject of
the tightening round, not of this document.
**Originally 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
@ -1864,11 +1879,23 @@ everything after. **Done 2026-07-26** (`1215f98`, `7bc366b`).
| V-A5 | No profile hard-codes an upstream version | Step 3 |
| V-A6 | Adding v0.2 support is behavior-neutral for v0.1 profiles | Golden suite byte-for-byte under `DEFAULT` **and** `STRICT_V1`; existing tests unmodified and green (C1 extended). **SUPERSEDED for `DEFAULT` 2026-08-09 — by commons, not by v0.2 support.** V1 moved `DEFAULT`'s `generated` and four goldens with it. The claim as written holds for what it was written about: adding v0.2 support changed no `DEFAULT` byte, and `STRICT_V1` is still byte-stable and its tests unmodified. A future session reading a golden diff here should not file it as a v0.2 regression |
| V-A7 | No profile can emit `timestamp` together with a malformed `generated` | Named construction-time test, same shape as C3's verdict reservation |
| V-A8 | A v0.2 bundle we emit is accepted by an independent v0.2 consumer | Validate the D5 fixture against upstream's reference implementation, not only against our own reader. **DONE 2026-07-31 @ `3fcbb9f`: 13/13.** Procedure is runbook Step 3a |
| V-A8 | A v0.2 bundle we emit is accepted by an independent v0.2 consumer | Validate the D5 fixture against upstream's reference implementation, not only against our own reader. **RE-RECORDED 2026-08-23 @ `ad30107`: 9/9 documents parse across all four goldens, 0 failures; 27/27 semantic-reader calls (`trust_tier`, `normalize_verified`, `is_stale`) return without raising.** Earlier: DONE 2026-07-31 @ `3fcbb9f`, 13/13 — the two counts are not comparable (different harness scope; see the note below). Procedure is runbook Step 3a |
V-A8 is the one that keeps this honest. Every other test asks whether we agree
with ourselves.
**Why the two V-A8 counts do not compare, 2026-08-23.** The 2026-07 harness
counted concept documents in one bundle; the 2026-08 harness walks all four
golden bundles and counts root `index.md` files too. A lower number is a wider
scope, not a regression. The re-run was put to a known-positive before its zeroes
were believed: a document with `type: [unclosed` raises `OKFDocumentError` while a
well-formed control parses, and `is_stale` returns `True` for a past
`stale_after` and `False` for a future one — so the harness is shown able to
report both a failure and a positive. Types recovered at `ad30107`:
`ingested_at``str` (was `datetime` at `3fcbb9f`), `generated``dict`,
`sources``list`, `okf_version``float`. The float coercion is A-E6, still
real and still upstream's.
**Executed 2026-07-31, and it was nearly weakened on a false premise.** The
standing note said V-A8 had to be re-scoped to parse-and-render because "there is
no validator in `okf/`". Enumerating the tree instead of the subdirectory showed
@ -1946,7 +1973,9 @@ is also where an upstream reader change would be caught.
additions only).
4. V-A7 and V-A5 named tests present and failing-by-construction if removed.
5. V-A8: the v0.2 fixture validates under upstream's reference implementation.
**Done 2026-07-31 @ `3fcbb9f`, 13/13.** Re-run per upstream release via runbook
**Re-recorded 2026-08-23 @ `ad30107`: 9/9 documents, 0 parse failures, 27/27
semantic-reader calls clean.** Earlier: done 2026-07-31 @ `3fcbb9f`, 13/13.
Re-run per upstream release via runbook
Step 3a — it is a procedure, not a pytest test, because it needs PyYAML and
upstream's source and this package has exactly one runtime dependency.
6. Boundary grep-gate still empty (`sanitize|quarantine|lexicon` absent outside

View file

@ -155,12 +155,18 @@ Assert, over each file of the current version's golden bundle:
structures. Only an outside parser can.
2. The values arrive as the *shapes* the profile intends — `generated` as a
mapping, `sources` as a list of mappings — not merely as something that parsed.
3. `validate()` passes. Note what this does and does not buy: at `3fcbb9f`
`REQUIRED_FRONTMATTER_KEYS = ("type",)`, so it checks one key. Treating a green
`validate()` as "upstream accepts our bundle" would overclaim badly; the parse in
(1) and the shape assertions in (2) are where the signal is.
3. `validate()` passes. Note what this does and does not buy:
`REQUIRED_FRONTMATTER_KEYS = ("type",)`, so it checks one key — measured
unchanged at `3fcbb9f` and at `ad30107`. Treating a green `validate()` as
"upstream accepts our bundle" would overclaim badly; the parse in (1) and the
shape assertions in (2) are where the signal is.
4. The semantic readers upstream ships run over our frontmatter without raising —
at `3fcbb9f`: `trust_tier` (§5.3), `normalize_verified` (§5.2), `is_stale` (§5.5).
at `3fcbb9f` and at `ad30107`: `trust_tier` (§5.3), `normalize_verified` (§5.2),
`is_stale` (§5.5). **They take the frontmatter mapping, not the document.**
Passing the `OKFDocument` raises `AttributeError: 'OKFDocument' object has no
attribute 'get'` — a harness bug that reads exactly like an upstream
incompatibility if the traceback is not read. Cost this round: one re-run.
`OKFDocument.parse()` likewise takes the text only; there is no `path=` keyword.
**Record the type each value arrives as, not just that it parsed.** A real YAML
parser coerces, and the coercions are load-bearing facts about the value space —
@ -175,7 +181,8 @@ block form.
*Result, 2026-08 round at `ad30107`:* 9/9 of our bundle documents parse, across all
four goldens, with the three semantic readers running over each without raising;
78/78 of upstream's own bundle documents parse. Do not compare the two counts —
78/78 of upstream's own bundle documents parse. **Re-run 2026-08-23 when the pin
moved to `ad30107`: 9/9 parsed, 0 failures, 27/27 semantic-reader calls clean.** Do not compare the two counts —
the second harness asserted `validate()` on root `index.md` files too, which
correctly fails (an index carries no `type`), so it counts differently by
construction. **A clean sweep is worth nothing until the harness is shown able to