docs(okf-v0.2): the F1 disposition, and A-E6's rationale after catalog 1ca27f6

Three corrections to the alignment plan, two of them because a fact a peer
repo gave us stopped being true.

**P1 dispositions.** F1 is fixed before the tag; the other five are not. The
line is whether a finding bites in code the pilots will pin. F1 did. F2/F3
do not: measured, all three `TypePolicy.rejection` call sites hard-code
`DEFAULT.types`, and both `DEFAULT` and `OKF_V0_2` set `allowed=None`, so the
closed-set branch is unreachable in shipped code and fires only for a caller
constructing `STRICT_V1` directly — which is what the sweep did. Dequoting in
`TypePolicy` would repair a write path that never sees a quote, and would fix
the meaning of a quote without a value model able to express one. F2/F3/F4
are one root cause and go to D1b; F5/F6 stay P4's.

**A-E6's reason did not survive, though the expectation did.** It justified
"unquoted" as a property of catalog's gate — their shape regex read quotes as
part of the value and so rejected upstream's own §12:773 example. Catalog
resolved that in `1ca27f6`: from spec 0.3 the value is unquoted before the
form check and both forms pass. The expectation stands on a different ground
now, supplied by commons the same day: `method-spec.md:90` parses frontmatter
line-oriented, so a quote is a character in the value rather than syntax a
parser removes, and upstream emits the same way. Recorded as a supersession
rather than swapped silently — reading a stale rationale as current is this
expectation's own defect class.

**TEST B must name the reader revision.** `okf-check.mjs` changed in the same
commit, and the reader's placement-blindness is now a deliberate choice
rather than an unanchored regex. A report that does not say which revision it
ran is not reproducible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JqCmfJ2ukpFXeFjfab8wvy
This commit is contained in:
Kjell Tore Guttormsen 2026-07-31 18:16:30 +02:00
commit 128109bef0

View file

@ -469,8 +469,24 @@ enumerates nothing.
Every finding below is on the **judge** path. None of them touches what the
library emits, so none of them blocks `v0.5.0a1`, P2 or P3: both remaining pilot
tests are emit-side. They are recorded here against GA exit criterion 1 and are
P4's work, not this session's.
tests are emit-side. They are recorded here against GA exit criterion 1.
**Disposition, decided by the operator 2026-07-31: F1 is fixed before the tag,
the other five are not.** The line between them is whether the finding bites in
code the pilots will actually pin. F1 does — `IndexPolicy.violations` is public,
`OKF_V0_2` names the key, and the profile contradicted its own emitter. The
others do not: F2 and F3 need a value model the parser does not have (which is
D1b, already scheduled), and the surface where they would bite — a read path
built on `TypePolicy.allowed` — is not wired to any profile. Measured: all three
call sites (`manifest.py:202`, `inbox.py:105`, `inbox.py:245`) hard-code
`DEFAULT.types`, and both `DEFAULT` and `OKF_V0_2` set `allowed=None`, so the
closed-set branch is unreachable in shipped code and fires only for a caller
that constructs `STRICT_V1` and calls `rejection` directly — which is what this
sweep did. Patching `TypePolicy` to dequote would therefore add a repair to a
write path that never sees a quote, and would fix the meaning of a quote without
a value model able to express one — precisely what commons warns against for a
line-oriented format (`method-spec.md:90`). F2, F3 and F4 are one root cause and
go to D1b together; F5 and F6 stay P4's.
**P1-F1 — `root_frontmatter` conflates "permitted and ordered" with "required",
and the emitter and the judge disagree about the same key.** `IndexPolicy`
@ -485,6 +501,16 @@ correctly and grade it as a MUST. `STRICT_V1` is unaffected in substance — the
wiki emits all three of its pinned keys (measured) — but it is the same field
carrying two meanings, so the fix has to separate them rather than relax them.
**FIXED before the tag.** `IndexPolicy` gained `root_frontmatter_required`:
`root_frontmatter` permits a key and fixes its position, the new field demands
it, and a required key outside the ordered set now fails at construction.
`OKF_V0_2` leaves it empty (upstream's MAY), `STRICT_V1` names all three
(unchanged behavior for the proving consumer), `DEFAULT` is untouched.
Re-measured over the eight bundle-root indexes reachable locally — our four
goldens and upstream's four: **7 of 8 failing under the old semantics, 0 of 8
after**, matching this finding's own numbers. The emit path is byte-identical;
the golden suite would have caught it otherwise.
**P1-F2 — `TypePolicy.allowed` cannot be used against a consumer that quotes its
scalars.** All **526/526** wiki documents are rejected as `okf_type_not_allowed`
under `STRICT_V1`; **526/526** are clean when values are dequoted before judging.
@ -878,13 +904,29 @@ output is the baseline. Materialize it twice with the *same* explicit
must not conflate them** — doing so would be this expectation's own defect
class:
- **Unquoted** is a property of **catalog's gate**, NOT of OKF v0.2. Their
shape regex `/^\d+(\.\d+)*$/` reads the quotes as part of the value and
exits 1. Upstream's §12:773 is the only line in the whole spec showing the
key *with* a value, and it shows it **quoted** — so their gate rejects
upstream's own canonical example. That is catalog's defect to resolve, not
ours to work around, but while it stands, an unquoted value is what passes.
We emit unquoted, and A-E6 expects unquoted **of catalog's gate**.
- **Unquoted** is not a property of OKF v0.2 either way. The expectation
stands; its ORIGINAL REASON DID NOT SURVIVE 2026-07-31, and the reason is
recorded here rather than quietly swapped because reading a stale rationale
as current is this expectation's own defect class.
*What it said, and why that is now wrong.* It said unquoted was a property
of **catalog's gate**: their shape regex `/^\d+(\.\d+)*$/` read the quotes
as part of the value and exited 1, which meant the gate rejected upstream's
§12:773 — the only line in the whole spec showing the key *with* a value,
and it shows it **quoted**. We called that catalog's defect to resolve, and
they resolved it: **from spec 0.3 (`1ca27f6`) the value is unquoted before
the form check, so `okf_version: 0.2` and `okf_version: "0.2"` both pass.**
"An unquoted value is what passes" is no longer a discriminating statement
about their gate.
*Why the expectation survives anyway.* Commons settled the same question
from the other side on 2026-07-31: `method-spec.md:90` (frozen since
`7d2b46c`) parses frontmatter line-oriented as `key: value` strings, so a
quote would be **a character in the value, not syntax a parser removes**
there is no transparent quoting in the format at all. Upstream emits the
same way (`by: human:jsmith@acme`, colon in the value and no quotes). So we
emit unquoted because that is the format's own convention, not because a
consumer's gate would otherwise reject it.
- **BOM-free** is a property of the file we emit, full stop. A BOM makes the
marker invisible to their gate *while still exiting 0* — a failure that
reports success.
@ -894,12 +936,22 @@ output is the baseline. Materialize it twice with the *same* explicit
sees it, so a parsed assertion masks precisely these two defects.
**A green TEST B does not confirm the placement, and a red one does not
identify it.** The shape regex is unanchored, so it matches in the frontmatter
block and in a body line alike — green measures the value, never the position.
Catalog sharpened the other direction on 2026-07-31: moving the marker into
frontmatter *with* quoting, as §12 literally shows it, also yields FAIL. So a
red run cannot distinguish "wrong quoting" from "wrong placement". Read TEST B
as a statement about the value's shape only, in both directions.
identify it.** The reader is placement-blind: green measures the value, never
the position. What changed on 2026-07-31 is only the REASON — it was an
unanchored regex matching a frontmatter line and a body line alike; from 0.3
it is a deliberate choice, reading frontmatter first and falling back to the
body, reporting which form it found. Catalog's stated ground for not enforcing
placement: `check-okf-parity` runs okr's LIVE checker, and enforcing before the
emitters have migrated would redden that gate without making a single bundle
more conformant. Read TEST B as a statement about the value's shape only, in
both directions. A red run still cannot separate "wrong quoting" from "wrong
placement" — but quoting is now the *less* likely of the two, since both forms
pass.
**TEST B must record the reader revision.** `okf-check.mjs` changed in
`1ca27f6`, and catalog invoked their standing promise to notify on any change
to it. A TEST B report that does not name the revision it ran is not
reproducible, whatever it says about the result.
**What would surprise us — report immediately:** any diff outside the frontmatter
block (the profile seam leaks); `at` differing from the `ingested_at` they passed