docs(k3): round 22, frontmatter a YAML reader reads back the same
K3-22's report, CHANGELOG under [Unreleased], and two corrections of a sentence measured false. README and CLAUDE.md both said of the flow form "both are valid YAML, and a real YAML consumer recovers the same structure from either". An unquoted URL with a query string inside a flow mapping is not valid YAML for PyYAML, and the quoted form is refused by the pinned guard; the paragraph now states the limit. CLAUDE.md also records the K3-22 invariant and the new refusal of a `--frontmatter` flow value with such a leaf. Measured, fix `ed0418f` against base `0308169`, each tree built twice from frozen exports: five-document project 0 files moved; R761 XML and HTML 1 line each; K2 default 42 `title` lines, after which 454 of 454 frontmatters parse and read back the same (base 413 parse, 412 read back). hit@k on R761 base = fix, S1-S6 6/6 at hit@1/8/50 at both k, KP rank 1; okf check 32 of 32 payloads 0 findings over 16 rules; K2 pin 7 passed in the export. Found outside the order: the pinned guard refuses nearly every segmented concept okf writes, on its scalar flow sequences (`source_offset`, `references`, `derived`) -- identical before and after, so older than K3-22. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ed0418f228
commit
e717b1c87a
4 changed files with 350 additions and 6 deletions
32
CHANGELOG.md
32
CHANGELOG.md
|
|
@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Frontmatter this library writes is YAML a YAML reader reads back the same
|
||||
(K3-22).** SPEC § 11 point 1 requires "a parseable YAML frontmatter block" in
|
||||
every file. Measured with PyYAML 6.0.3 before the change, the pinned K2
|
||||
default bundle failed `safe_load` on 41 of 455 blocks (and a 42nd parsed to
|
||||
a truncated title), and each R761 build on 1 -- every one a block scalar
|
||||
written verbatim: a title with `": "` or `" #"`, a leading `- `, `*` or `**`,
|
||||
a trailing `:`.
|
||||
- **Block scalars:** a value K3-19's plain-scalar rule refuses is written
|
||||
double-quoted, `\` and `"` escaped; every other value keeps its bytes.
|
||||
Rebuilt, the five-document project moves 0 files, each R761 build 1 line
|
||||
and the K2 default bundle 42 `title` lines, after which all 454 of its
|
||||
frontmatters parse and read back the same.
|
||||
- **Flow leaves (`sources`, Door A's list, a run-stated flow value):** the
|
||||
pinned guard refuses any quote inside a flow mapping, so a leaf PyYAML
|
||||
would refuse (`?`, `,[]{}`, `": "`, `" #"`, a quote, a leading indicator)
|
||||
has no form both read and is refused with the door's existing code
|
||||
(`inbox_source_file_unaddressable`, `inbox_source_title_unaddressable`,
|
||||
`source_reference_unquotable`, `run_frontmatter_invalid`).
|
||||
- **Behaviour change:** `okf build --frontmatter 'sources=[{ resource: <URL
|
||||
with a query string>, … }]'` now exits 2 and writes nothing. K3-19's own
|
||||
flagged R761 build used such a URL and wrote 2 761 of 2 761 frontmatters
|
||||
PyYAML refuses.
|
||||
- **Readers** (`parse_frontmatter`, the index and structure readers, both
|
||||
`read_sources` branches) unquote a `"`-wrapped value; `'`-wrapped values
|
||||
are untouched. On 25 273 files of existing bundles the readers return
|
||||
exactly what they returned before.
|
||||
- The generated `SKILL.md` header goes through the same block rule.
|
||||
- PyYAML joins the `dev` dependency group only; `src/` imports no yaml.
|
||||
- Report: `docs/2026-09-11-k3-runde22-yaml-lesbar-frontmatter.md`.
|
||||
|
||||
## [0.8.3] — 2026-09-11
|
||||
|
||||
### Added
|
||||
|
|
|
|||
28
CLAUDE.md
28
CLAUDE.md
|
|
@ -301,14 +301,30 @@ specifies it. Because "always latest" decays silently, the release checklist
|
|||
carries an upstream-version re-check.
|
||||
|
||||
**Structured frontmatter values are emitted in YAML *flow* form, never block.**
|
||||
Both are valid YAML and an upstream reader recovers the same structure from
|
||||
either, but this library's parser is line-oriented: it round-trips a flow
|
||||
Both can be valid YAML -- within the flow-scalar limit below -- and an upstream
|
||||
reader then recovers the same structure from either, but this library's parser
|
||||
is line-oriented: it round-trips a flow
|
||||
mapping as an opaque value and cannot read the block form at all — two block
|
||||
mappings sharing an inner key (§10.2's `executor` and `attester`, both carrying
|
||||
`resource`) collapse into one namespace and the first is lost silently.
|
||||
Emitting block would produce bundles we cannot read back. Reading it needs the
|
||||
structured reader (D1b); until then the constraint binds what we write.
|
||||
|
||||
**Every value is written so a YAML reader reads it back the same (K3-22).**
|
||||
SPEC § 11 point 1 requires "a parseable YAML frontmatter block", and before
|
||||
K3-22 the pinned K2 default bundle failed PyYAML on 41 of 455 blocks and each
|
||||
R761 build on 1 -- block scalars written verbatim. A block scalar that is not
|
||||
plain-safe (`profiles.yaml_block_plain`, K3-19's rule) is now written
|
||||
double-quoted with `\` and `"` escaped; every other value keeps its bytes. A
|
||||
FLOW leaf has no quoted form -- the pinned guard refuses any quote inside a
|
||||
flow mapping -- so a leaf PyYAML would refuse or misread (`?`, `": "`, `" #"`,
|
||||
a quote, a leading indicator) is refused by `profiles.yaml_flow_plain` with the
|
||||
door's existing code, never written. Readers unquote a `"`-wrapped value only:
|
||||
0 such values existed in any measured bundle, while 11 193 `'`-wrapped ones do
|
||||
and stay untouched. PyYAML is a dev dependency that validates the rules in
|
||||
`tests/test_yaml_frontmatter.py`; `src/` imports no yaml. Report:
|
||||
`docs/2026-09-11-k3-runde22-yaml-lesbar-frontmatter.md`.
|
||||
|
||||
**Every upstream release runs `docs/upstream-okf-upgrade-runbook.md`.** Pin the
|
||||
commit, enumerate the whole `okf/` tree, **read the shipped example bundles and not
|
||||
only `SPEC.md`**, classify the diff, measure our exposure and each consumer's, plan
|
||||
|
|
@ -587,9 +603,13 @@ and fixtures, never code.
|
|||
`docs/2026-09-08-k3-runde3-per-filtype.md`.
|
||||
- **`--frontmatter KEY=VALUE` (K3-19, repeatable) is not a segmentation flag**
|
||||
and moves no byte unless given: it stamps a key on every concept of the run,
|
||||
split on the FIRST `=` and written verbatim on ONE line -- a block-form
|
||||
split on the FIRST `=` and written on ONE line -- a block-form
|
||||
`sources` is invisible to `parse_frontmatter`, so the flow form is the only
|
||||
one that survives our own readers. It adds any key and REPLACES only
|
||||
one that survives our own readers. Since K3-22 a scalar goes out
|
||||
double-quoted where a YAML reader would not read it plain, and a flow value
|
||||
goes out as given but is REFUSED (exit 2) when a leaf has no flow form both
|
||||
PyYAML and the guard read -- so a `sources` URL with a query string, the form
|
||||
K3-19's own flagged build wrote on 2 761 of 2 761 concepts, fails the build. It adds any key and REPLACES only
|
||||
`sources` and `description`, the two with a derived layer below them:
|
||||
precedence flag > what the document declares > file name. Every other key
|
||||
the door writes (`inbox._door_keys`, including Door A's `ingest_manifest`,
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -858,8 +858,15 @@ frontmatter parser is line-oriented. It reads inline **flow** mappings
|
|||
(`executor: { resource: …, receipt: [ … ] }`) as opaque values that round-trip
|
||||
unchanged, but it cannot read the block form — two block mappings that both
|
||||
carry a `resource` collapse into one namespace and the first is lost. Write the
|
||||
flow form; both are valid YAML, and a real YAML consumer recovers the same
|
||||
structure from either.
|
||||
flow form, and know its limit: it is valid YAML only while every plain value
|
||||
inside it avoids what ends a flow scalar — `,`, `[`, `]`, `{`, `}`, and for
|
||||
PyYAML also `?` — as well as `": "`, `" #"`, a trailing `:` and a leading YAML
|
||||
indicator. Within that limit a YAML consumer recovers the same structure from
|
||||
either form. Beyond it no flow form works: quoting satisfies PyYAML, but the
|
||||
guard refuses a quoted value inside a flow mapping, so this library refuses
|
||||
such a value rather than write frontmatter a reader cannot parse. An earlier
|
||||
version of this paragraph said "both are valid YAML" without that limit; it was
|
||||
measured false for an unquoted URL with a query string.
|
||||
|
||||
## Non-goals
|
||||
|
||||
|
|
|
|||
285
docs/2026-09-11-k3-runde22-yaml-lesbar-frontmatter.md
Normal file
285
docs/2026-09-11-k3-runde22-yaml-lesbar-frontmatter.md
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
# K3 round 22 — frontmatter a YAML reader reads back the same
|
||||
|
||||
Order K3-22, 2026-09-11. Red `06e61a5`, fix `ed0418f`, base `0308169`
|
||||
(v0.8.3). PyYAML 6.0.3, guard 1.3.0, Python 3.14.0 (working tree and the
|
||||
frozen exports, run through the repository's own interpreter with the export
|
||||
first on `PYTHONPATH`; `__file__` verified under the scratch export for both).
|
||||
|
||||
## Deviations, first
|
||||
|
||||
1. **The order's form for the flow mapping cannot ship.** It asked for
|
||||
`sources: [{ resource: "https://…?x=nb", title: … }]` -- a double-quoted
|
||||
leaf inside the flow mapping. PyYAML reads that; the pinned guard does not.
|
||||
Guard 1.3.0 `okf.parse_frontmatter` refuses ANY quote inside a flow mapping
|
||||
("a quoted scalar inside a flow mapping is not a supported form"), double
|
||||
or single, measured below. Writing it would have moved 4 605 PyYAML
|
||||
failures to 4 605 guard failures, and broken the promise
|
||||
`tests/test_provenance.py` already holds ("what Door B writes must survive
|
||||
the guard's own frontmatter grammar"). So a flow leaf is VALIDATED, never
|
||||
quoted: a value no flow form both readers accept is refused with the door's
|
||||
existing code. Quoting is used where the guard admits it -- a block scalar.
|
||||
2. **The failure is bigger in this repository's own output than the order's
|
||||
table shows, and in the other place.** The order's table has no bundle
|
||||
`okf` built with its defaults. The pinned K2 default bundle fails
|
||||
`safe_load` on **41 of 455** frontmatter blocks, and **1 more** parses
|
||||
while PyYAML reads a different value than ours (a title carrying `" #"` --
|
||||
PyYAML stops at the comment, no error). All 42 are block `title` scalars
|
||||
(FEIL B); **0** `sources` values okf wrote failed anywhere measured. The
|
||||
4 605 `?` failures (FEIL A) come from a consumer's own `sources` writer,
|
||||
which does not go through this library.
|
||||
3. **The consumer repository is at `f783e52`, not `6fad6a2`.** The hit@k
|
||||
instrument was taken from `6fad6a2`, as ordered, into private scratch with
|
||||
the payload path changed (2 lines differ from the original). Its tree was
|
||||
clean before and after (`git status --porcelain`: 0 lines both times).
|
||||
4. **The default-`k` hit@k run passes four flags, not five** (`--bundle
|
||||
--questions --okf --out`, no `--k`), reproducing how the previous round ran
|
||||
it; the `k = 50` run passes all five.
|
||||
|
||||
## 1. The standard
|
||||
|
||||
SPEC (`_okf-canonical` `ad30107`), verbatim:
|
||||
|
||||
- **§ 4, opening:** "Every concept is a UTF-8 markdown file with two parts:
|
||||
1. A **YAML frontmatter block**, delimited by `---` on its own line at the
|
||||
start of the file and a closing `---` on its own line." (l. 155-158)
|
||||
- **§ 11, Conformance, point 1:** "Every non-reserved `.md` file in the tree
|
||||
contains a parseable YAML frontmatter block." (l. 740-741)
|
||||
|
||||
**What the spec does not say, and it is a weakness of the spec:** it names no
|
||||
YAML version and no subset -- 0 hits for a version number, "YAML version" or
|
||||
"subset", with the query validated against the known-positive `YAML` (5 hits).
|
||||
"Parseable" is therefore whatever reader the consumer has, and PyYAML is the
|
||||
common one. That is why the reader, not this corpus, decides the rule.
|
||||
|
||||
## 2. The measurement, reproduced
|
||||
|
||||
`yaml.safe_load` over the block between the two fences; the denominator is
|
||||
files WITH a frontmatter block (index files without one are not counted --
|
||||
e.g. 5 514 `.md` against 2 757 with frontmatter in the first row).
|
||||
|
||||
| tree | with frontmatter | OK | FAIL | order's figure |
|
||||
|---|---|---|---|---|
|
||||
| consumer R761 (N-route) | 2 757 | 1 | 2 756 | same |
|
||||
| consumer N100 | 447 | 1 | 446 | same |
|
||||
| consumer N200 | 1 134 | 1 | 1 133 | same |
|
||||
| consumer N500 | 271 | 1 | 270 | same |
|
||||
| consumer R761, built by `okf build` | 2 763 | 2 762 | 1 | same |
|
||||
| this repository's `tests/fixtures` | 12 | 12 | 0 | same |
|
||||
| **K2 default bundle (pinned)** | **455** | **414** | **41** (+1 misread) | not in the order |
|
||||
| R761 HTML build (v0.8.3) | 3 208 | 3 207 | 1 | not in the order |
|
||||
| R761 XML build (v0.8.3) | 2 763 | 2 762 | 1 | not in the order |
|
||||
| five-document project (v0.8.3) | 29 | 29 | 0 | not in the order |
|
||||
| `examples/` · `skills/` | 14 · 3 | 14 · 3 | 0 · 0 | not in the order |
|
||||
|
||||
Every figure the order gave reproduces exactly.
|
||||
|
||||
## 3. The two causes
|
||||
|
||||
**FEIL A -- `?` inside a flow mapping.** The consumer writes
|
||||
`sources: [{ resource: https://<viewer>/api/…/860019?languageCode=nb, title: … }]`
|
||||
unquoted. PyYAML's scanner ends a plain scalar in FLOW context at `?`:
|
||||
|
||||
```
|
||||
while parsing a flow mapping ... expected ',' or '}', but got '?'
|
||||
```
|
||||
|
||||
The colon in `https:` is not the cause: `https://h.no/a/1` in the same place
|
||||
parses.
|
||||
|
||||
**FEIL B -- a block scalar written verbatim.** The profile emitter wrote every
|
||||
value as `key: value`. A title ending in `:` gives
|
||||
|
||||
```
|
||||
mapping values are not allowed here
|
||||
```
|
||||
|
||||
and the K2 bundle adds a leading `- ` ("sequence entries are not allowed
|
||||
here"), a leading `*` or `**` ("expected alphabetic or numeric character" /
|
||||
an undefined alias) and `": "` inside a title.
|
||||
|
||||
## 4. The constructs, measured
|
||||
|
||||
PyYAML 6.0.3 (`BaseLoader`), and guard 1.3.0 `okf.parse_frontmatter`:
|
||||
|
||||
| construct | PyYAML | guard |
|
||||
|---|---|---|
|
||||
| `sources: [{ resource: https://h.no/a/1?x=nb, title: T }]` | FAIL, `got '?'` | admits |
|
||||
| `sources: [{ resource: https://h.no/a/1, title: T }]` | OK | admits |
|
||||
| `sources: [{ resource: a=b&c.pdf, title: T }]` | OK | admits |
|
||||
| `sources: [{ resource: fil.pdf, title: N100:2023 }]` | OK | admits |
|
||||
| `sources: [{ resource: fil.pdf, title: N100: 2023 }]` | FAIL, `got ':'` | -- |
|
||||
| `sources: [{ resource: fil.pdf, title: Kap #3 }]` | FAIL, `<stream end>` | -- |
|
||||
| `sources: [{ resource: fil.pdf, title: -x }]` | OK | admits |
|
||||
| `sources: [{ resource: fil.pdf, title: *x }]` | FAIL, alias | -- |
|
||||
| `sources: [{ resource: "https://h.no/a/1?x=nb", title: T }]` | OK | **REFUSES** |
|
||||
| `sources: [{ resource: 'https://h.no/a/1?x=nb', title: T }]` | OK | **REFUSES** |
|
||||
| block `sources:` / `- resource: https://h.no/a/1?x=nb` / `title: T` | OK | admits |
|
||||
| `title: Eksempel kontur:` | FAIL, mapping values | refuses |
|
||||
| `title: "Eksempel kontur:"` | OK | admits (keeps the quotes) |
|
||||
| `title: N100: 2023` · `title: - punkt` · `title: *stjerne` | FAIL | -- |
|
||||
| `title: Kap #3` | **OK, as `Kap`** | admits |
|
||||
| `utgave: R761 Prosesskoden:2025` · `title: Kap#3` | OK | admits |
|
||||
|
||||
## 5. The form, and why it is the narrowest
|
||||
|
||||
**Block scalars: double-quote exactly the values K3-19's rule refuses.** The
|
||||
rule (`no leading indicator, no ": ", no " #", no trailing ":", no tab or line
|
||||
break`) is now `profiles.yaml_block_plain`, and over every top-level value in
|
||||
eleven measured trees it agrees with PyYAML read verbatim on every one: **0
|
||||
refused that PyYAML returns verbatim, 0 kept that it does not** (K2 5 524
|
||||
values, the HTML build 38 752, the XML build 35 177, the five consumer bundles
|
||||
and the rest). Quoting everything would move bytes in every concept of every
|
||||
bundle and buy no valid file; this moves only the values that were failing.
|
||||
|
||||
**Double, never single -- counted.** Values wrapped in a surrounding `"` pair:
|
||||
**0** in twelve trees (the eleven plus `skills/`). Wrapped in `'`: **11 193**,
|
||||
all in the consumer bundles (10 937 + 67 + 86 + 103), written that way on
|
||||
purpose. A reader that unquotes `"` changes the meaning of no value that
|
||||
exists; one that also unquoted `'` would change 11 193.
|
||||
|
||||
**Flow leaves: no quoted form exists, so validation.** Plain fails PyYAML on
|
||||
`?`, `,[]{}`, `": "`, `" #"`, a trailing `:` and a leading indicator; quoted
|
||||
fails the guard. `profiles.yaml_flow_plain` is the block rule plus
|
||||
`,[]{}?'"`, with one exception the block rule does not make: a leading `-`
|
||||
followed by a non-space, which both readers take (`del/-utkast.pdf`). Refusing
|
||||
that would refuse a document both read; the block rule keeps refusing it
|
||||
because it also decides which spec points are written at all, and in a block a
|
||||
refusal costs only a pair of quotes. The refusal uses each door's existing
|
||||
code: `inbox_source_file_unaddressable` (also when the FILE NAME, which becomes
|
||||
the entry's `title`, is not plain), `inbox_source_title_unaddressable`,
|
||||
`source_reference_unquotable` (Door A), `run_frontmatter_invalid`
|
||||
(`--frontmatter` with a flow value).
|
||||
|
||||
Over a constructed list of 39+ values (in `tests/test_yaml_frontmatter.py`)
|
||||
the safe direction is required and the over-refusals are pinned: block keeps 0
|
||||
PyYAML would misread and over-refuses 3 (`-punkt`, `?spm`, `:kolon`, which get
|
||||
quoted); flow keeps 0 that PyYAML or the guard would refuse and over-refuses 0.
|
||||
|
||||
**Readers read both forms.** `materialize.parse_frontmatter`, the index
|
||||
reader's and the structure reader's copies, and both `read_sources` branches
|
||||
unquote a `"`-wrapped value, decoding `\"` and `\\` and nothing else. Other
|
||||
backslash escapes (`\n`, `\t`, `\x..`, `\u....`) are kept as written: the
|
||||
emitter never writes them. `'`-wrapped values are untouched -- except in the
|
||||
structure reader, which already unquoted both forms before K3-22 on its own
|
||||
rule (`version: '2021'` is a string) and keeps doing so. The flow-mapping
|
||||
split is quote-aware, so `{ title: "a, b" }` is one pair; a `"` opens a quoted
|
||||
scalar only where a value can start, so a plain value with a `"` in its middle
|
||||
splits as before.
|
||||
|
||||
The generated `SKILL.md` header goes through the block rule too:
|
||||
`description` carries the root index's `bundle_id` raw.
|
||||
|
||||
## 6. What moved bytes, and what did not
|
||||
|
||||
Each tree built twice, from the base export and the fix export, and compared
|
||||
with `diff -rq`:
|
||||
|
||||
| build | concepts / md | files that differ | the line |
|
||||
|---|---|---|---|
|
||||
| five-document project | 26 / 52 | **0** | -- |
|
||||
| R761 XML (`--bundle-id r761-prosesskoden-2025 --okf-version 0.2 --ingested-at 2026-09-08T12:00:00Z`) | 2 761 / 5 501 | **1** | a title ending in `:`, now double-quoted |
|
||||
| R761 HTML, 828 files | 3 206 / 6 015 | **1** | the same section's title |
|
||||
| K2 default, rebuilt (43 documents) | 453 / 864 | **42** | 42 `title` lines, now double-quoted: the 41 that failed `safe_load` and the 1 that parsed to a truncated title |
|
||||
|
||||
The K2 base rebuild is byte-identical to the pinned K2 artefact on every file
|
||||
but `log.md`, which the corpus harness had not yet written when the two were
|
||||
compared -- so the 42 lines are K3-22's and nothing else's.
|
||||
|
||||
- **Goldens and fixtures: 0 bytes.** The golden tests are byte-exact and pass;
|
||||
`tests/fixtures` is untouched and still 12 of 12.
|
||||
- **Readers on existing bundles: 0 differences.** Base readers and fix readers
|
||||
return identical `parse_frontmatter` and `read_sources` results on **25 273
|
||||
of 25 273** files across nine trees (the five consumer bundles, the pinned K2
|
||||
bundle, the HTML and XML builds, `tests/fixtures`). N100/N200/N500 are read
|
||||
exactly as before.
|
||||
- **One behaviour moved, and it is a refusal.** `okf build --frontmatter
|
||||
'sources=[{ resource: <URL with ?>, … }]'` now exits 2 and writes nothing.
|
||||
Measured on R761 with K3-19's flags: the base export writes **2 761 of 2 761**
|
||||
concepts PyYAML refuses (2 760 on `?`, 1 on the title), the fix export
|
||||
refuses the run. Two K3-19 tests built with such an address; they now build
|
||||
with one without `?`, and a new test holds the refusal.
|
||||
- **The K2 pin** holds concept count and hit ranks, not bytes, so it did not
|
||||
need moving: **7 of 7 passed** in the frozen fix export, with the gold set
|
||||
copied in (without it the pin is 7 skipped, which is not a measurement).
|
||||
|
||||
## 7. Acceptance
|
||||
|
||||
| check | result |
|
||||
|---|---|
|
||||
| PyYAML valid, fix builds | five-document 28/28 · R761 XML 2 763/2 763 · HTML 3 208/3 208 · K2 **454/454** (base 413/454) |
|
||||
| dict-equal to `parse_frontmatter` + `read_sources`, every file | 28/28 · 2 763/2 763 · 3 208/3 208 · K2 **454/454** (base 412/454) |
|
||||
| generated `SKILL.md` headers, `safe_load` | **4 of 4** (five-document, R761 XML, HTML, K2) |
|
||||
| hit@k R761, base = fix | S1-S6 hit@1/8/50 **6/6 · 6/6 · 6/6** at default `k` and at `k = 50`; KP rank **1** at both; KN not delivered at both |
|
||||
| `okf check` on every payload | **32 of 32** exit 0, "conformant: 16 rules … 0 findings" (`len(RULES)` = 16) |
|
||||
| `grep -rc "import yaml" src/` | **0 on each of 22 files** |
|
||||
| `[project.dependencies]` | unchanged, `["llm-ingestion-guard>=1.2,<2.0"]`; `uv.lock` +2 lines, the dev dependency |
|
||||
| suite, working tree | 1 667 passed / 1 skipped before; **1 753 / 1** after (85 + 1 new) |
|
||||
| suite, frozen fix export from a scratch cwd | 1 750 / 1 / 3 failed: the two known (`test_segmented_golden` four-goldens, `test_guard_adapter` cwd-relative path) and `test_cli_build::…installed_copy`, which fails identically on the base export under this runner -- the runner's `PYTHONPATH` reaches the subprocess the test installs into |
|
||||
|
||||
The hit@k base row reproduces the previous round's before anything else was
|
||||
read.
|
||||
|
||||
## 8. Found, and outside this order
|
||||
|
||||
**The guard's parser refuses nearly every segmented concept okf writes, for a
|
||||
reason that is not YAML.** Guard 1.3.0 admits a flow sequence of MAPPINGS only
|
||||
("a flow sequence admits flow mappings only"), and okf writes scalar flow
|
||||
sequences at top level: `source_offset: [1, 24]`, `source_lines`,
|
||||
`source_pages`, `derived: [references]`, `references`. Measured with
|
||||
`okf.parse_frontmatter` over whole frontmatters: five-document 26 of 28
|
||||
refused, R761 XML 2 761 of 2 763, HTML 3 206 of 3 208, pinned K2 412 of 455 --
|
||||
identical on base and fix, so it predates K3-22. PyYAML reads all of them.
|
||||
What this means for Door C importing an okf bundle is **not measured** here
|
||||
(`import_bundle` was not run).
|
||||
|
||||
## Honesty limits
|
||||
|
||||
- **PyYAML is one reader.** The rules are validated against it and the guard;
|
||||
a YAML 1.2 reader accepts more (`?` inside a flow scalar), so the rules are
|
||||
stricter than 1.2, never looser than PyYAML on the values measured.
|
||||
- **The flow-collection exemption trusts its producers.** The emitter writes a
|
||||
value shaped `[...]` or `{...}` as it stands. Over the eleven trees only
|
||||
structural keys carry that shape and no `title` does; a producer that built a
|
||||
malformed collection would still be written. The run-stated route
|
||||
(`--frontmatter`) is validated; the internal producers are measured, not
|
||||
checked at emission.
|
||||
- **Two escapes.** `\"` and `\\` are written and decoded; any other escape is
|
||||
neither.
|
||||
- **The 217 descriptions stay omitted.** A derived spec point carrying `": "`
|
||||
is still not written (K3-19), although it could now be written quoted.
|
||||
Writing it would add values, which this order excluded.
|
||||
- **The constructed list is constructed.** The "0 / 0" over real values is the
|
||||
measurement; the constructed list pins the directions on shapes the corpora
|
||||
may not carry.
|
||||
- **Conformance is the floor, never the proof.** § 11 point 1 now holds on
|
||||
every build measured; that says the frontmatter parses, not that a bundle is
|
||||
good.
|
||||
|
||||
## Corrected
|
||||
|
||||
`README.md` said of the flow form: "both are valid YAML, and a real YAML
|
||||
consumer recovers the same structure from either". Measured false: an unquoted
|
||||
URL with a query string inside a flow mapping is not valid YAML for PyYAML.
|
||||
The paragraph now states the limit, and `CLAUDE.md` carried the same sentence
|
||||
and is corrected with it.
|
||||
|
||||
## Reproduce
|
||||
|
||||
```sh
|
||||
# PyYAML validity, denominator = files with a frontmatter block
|
||||
python3 - <<'EOF'
|
||||
import sys, yaml, pathlib
|
||||
root = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else ".")
|
||||
fm = ok = 0
|
||||
for p in root.rglob("*.md"):
|
||||
lines = p.read_text(encoding="utf-8").splitlines()
|
||||
if not lines or lines[0].strip() != "---":
|
||||
continue
|
||||
fm += 1
|
||||
try:
|
||||
yaml.safe_load("\n".join(lines[1:lines.index("---", 1)])); ok += 1
|
||||
except yaml.YAMLError:
|
||||
pass
|
||||
print(f"with frontmatter={fm} ok={ok} fail={fm - ok}")
|
||||
EOF
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue