docs(k3): round 24, a reason that became false is struck and the emitter stays flow

`_render_sources` gave three measured reasons for refusing to emit the block
form. Two of them fell with `28f9a4b` and are struck rather than left
standing: a block list no longer round-trips to an empty value (4 609 of
4 609 concept files), and B6's acceptance test can now pass.

Reason 2 STANDS and now carries the emission rule alone, re-measured by
reading `portfolio-optimiser` at `6eb58e5`: `read_provenance` returns
`UnreadableProvenance(reason="block-sequence")` for a block value. It is not
the guard's objection -- guard 1.4.0 reads the block form on 4 609 of 4 609
of the same files -- so the answer to "should our own emitter write block" is
NO, with the number that carries it, and the measurement that would make it
decidable is named in STATE rather than deferred without one.

The README paragraph said this library "cannot read the block form" where one
reader could and one could not. It now separates the two by KEY: `sources` in
either form through every reader, every other block mapping still refused,
with the D1b pointer intact.

Report: 222 lines, S7 form. Five deviations first, including the acceptance
sentence naming THREE flat readers rather than one, a `title` denominator of
7 372 rather than 5 372, and the `okf check` rule answered NO with a
measurement (`contract_check` holds 0 occurrences of `sources`, and
`consume` already writes `sources_unreadable` for the state a rule would
restate; `len(RULES)` is 17). Honesty limits name the one-key-wide set, the
block `verified:` fixture still reading empty, and the rendering not being
byte-identical to the source.

Suite 1807 passed / 1 skipped, rc 0, 98 s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-12 16:50:26 +02:00
commit 2d4f56dc6c
5 changed files with 326 additions and 27 deletions

View file

@ -596,9 +596,12 @@ def read_sources(lines: Sequence[str]) -> tuple[tuple[Mapping[str, str], ...], b
handling one form delivers the other bundle with no address at all -- and
for N500 there is nothing else, because it carries zero locator keys.
Reading the block form is not a licence to WRITE it: this library's
line-oriented parser still cannot round-trip block lists, so the emission
rule (flow only) is untouched.
Reading the block form is not a licence to WRITE it, and since K3-24 the
reason is a different one: the line-oriented parser DOES round-trip a
block `sources` list now (it shares this function's grammar), so what
holds the emission rule at flow is the downstream consumer that classifies
a block sequence as unreadable provenance -- measured, not remembered, in
`materialize._render_sources`.
"""
for position, line in enumerate(lines):
if line[:1] in (" ", "\t") or not line.startswith("sources:"):

View file

@ -217,19 +217,29 @@ def _render_sources(sources: Sequence[Source]) -> str:
emitted form. The list is here; the block form is not, and the reason is
measured rather than argued:
- `parse_frontmatter` is line-oriented and skips indented lines, so a block
list round-trips to an EMPTY value with every entry gone, silently. We
would be writing provenance we cannot read back, and `_is_ingest_owned`
reads through that same parser.
- The consumer B6 was written for accepts `[{ k: v }, { k: v }]` plural
and classifies a block sequence as unreadable provenance. Block would hand
it exactly the state it reports as unreadable.
- B6's own acceptance test asks for a round trip through this parser. No
block form can pass it.
- **FELL 2026-09-12 (K3-24).** `parse_frontmatter` used to skip indented
lines unconditionally, so a block list round-tripped to an EMPTY value
with every entry gone, silently. It now decodes a block `sources`
sequence, measured against PyYAML 6.0.3 and the pinned guard on 4 609 of
4 609 concept files carrying one. A reason that has become false is worse
than no reason, so it is struck here rather than left standing.
- **STANDS.** The consumer B6 was written for accepts `[{ k: v }, { k: v }]`
plural and classifies a block sequence as unreadable provenance.
Re-measured 2026-09-12 by reading `portfolio-optimiser` at `6eb58e5`:
`read_provenance` returns `UnreadableProvenance(reason="block-sequence")`
for a block value. Block would hand the consumer that asked for
multi-source exactly the state it reports as unreadable. This reason
alone carries the emission rule, and it is NOT the guard's: guard 1.4.0
reads the block form on 4 609 of 4 609 of the same files.
- **FELL with the first.** B6's own acceptance test asks for a round trip
through this parser, and a block form now passes it
(`test_the_block_form_round_trips_through_the_flat_reader`).
The flow form also satisfies commons' §5 "all values MUST be single-line",
and §11 requires parseable YAML rather than block YAML. Reading block needs
the structured reader (D1b); until then the constraint binds what we write.
and §11 requires parseable YAML rather than block YAML. The flat readers
now read a block `sources`; that is a READING change and not a licence to
write one, because the standing reason above is about a consumer, not
about us.
A single source renders byte-identically to the one-entry form that shipped
before this took a list, which is what keeps all six goldens unmoved.