fix(okf): one unquoting rule for frontmatter scalars (kø-(a)/(i))

Two rules existed. verdicts._unquote took quotes off correctly; the
bundle_context title renderer stripped only `"`. Measured before the fix:
`title: "  Spaced  "` rendered as `## concept:   Spaced  ` (the whitespace
half kø-(a) named), and `title: 'Single'` rendered its quotes verbatim —
both ordinary YAML a hand-authoring curator writes, and both reach the
agent's read-context.

The (p) defect class: a duplicated conversion drifts, and the drifted copy
decides something. Same fix shape — ONE source, owned by the module that
owns parse_frontmatter. okf.unquote_scalar is now the rule; verdicts
delegates by identity, so the structural key that _mint_id hashes is
unchanged.

The commons-owned nav-goldens could never have caught this: every golden
title is double-quoted with no inner whitespace, so both rules render them
byte-identically. That is asserted as a control, and it goes RED if a
future golden gains a discriminating title.

Load-bearing MEASURED against the whole suite, three mutations:
- weaken the renderer back to .strip('"') -> ONLY the 2 new rows red,
  643 others green (incl. nav-goldens) = it covers ground nothing did
- reintroduce a private _unquote copy in verdicts -> only the identity
  test red, 644 green (the copy is behaviourally identical TODAY, which
  is exactly why identity is the only thing that catches the class)
- (control, kø-(n)) add `import numpy` to a second src module -> the
  existing test_semretrieval_is_the_sole_numpy_importer goes red alone,
  confirming that gate is live rather than green-but-dead

638 -> 645 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DVMsih6tXx39VMyq6wJ5H7
This commit is contained in:
Kjell Tore Guttormsen 2026-08-04 21:23:18 +02:00
commit fbc7a6120a
3 changed files with 130 additions and 5 deletions

View file

@ -41,6 +41,20 @@ _COST_BASELINE = "cost-baseline.json"
_LINK_RE = re.compile(r"\]\(([^)]+\.md)\)")
def unquote_scalar(raw: str) -> str:
"""The ONE unquoting rule for a frontmatter scalar — ``parse_frontmatter`` preserves quotes
(OKF SPEC §4), so every consumer of a scalar has to take them off, and they must all take them
off the SAME way.
It lives here because this module owns ``parse_frontmatter``. It was a private copy in
``verdicts`` (structural key) while ``bundle_context`` stripped only ``"`` (rendered title) —
two rules, and the weaker one in the path that becomes the agent's read-context. Both quote
styles, and whitespace on either side of them, are ordinary YAML a hand-authoring curator
writes. Mirrors the (p) precedent: a duplicated conversion drifts, and the drifted copy decides
something. Gated by ``tests/test_frontmatter_unquote_loadbearing.py``."""
return raw.strip().strip('"').strip("'").strip()
def parse_frontmatter(path: str | Path) -> dict[str, str]:
"""Read the leading ``---``-delimited YAML frontmatter block as key:value strings.
@ -213,7 +227,7 @@ def bundle_context(bundle: Bundle, *, dimension: str | None = None) -> str:
file_dim = f.frontmatter.get("dimension")
if file_dim is not None and file_dim != dimension:
continue
title = f.frontmatter.get("title", f.name).strip('"')
title = unquote_scalar(f.frontmatter.get("title", f.name))
body = f.body.strip("\n")
sections.append(f"## {f.type or 'document'}: {title}\n\n{body}")
return "\n\n".join(s for s in sections if s.strip())

View file

@ -488,10 +488,12 @@ class VerdictFrontmatterError(ValueError):
malformed files because anyone may drop anything there."""
def _unquote(raw: str) -> str:
"""``parse_frontmatter`` preserves quotes (OKF SPEC §4); the structural fields are compared and
hashed against the IR projection's RAW JSON values, so the quotes have to come off here."""
return raw.strip().strip('"').strip("'").strip()
# ``parse_frontmatter`` preserves quotes (OKF SPEC §4); the structural fields are compared and
# hashed against the IR projection's RAW JSON values, so the quotes have to come off. DELEGATED,
# not copied: this was a private implementation while ``okf.bundle_context`` stripped only ``"``,
# and a duplicated conversion drifts (the (p) precedent). ``okf`` owns ``parse_frontmatter``, so it
# owns the unquoting rule. Gated by ``tests/test_frontmatter_unquote_loadbearing.py``.
_unquote = okf.unquote_scalar
def _parse_affected_codes(raw: str) -> frozenset[str]:

View file

@ -0,0 +1,109 @@
"""Kø-(a)/(i) — ONE unquoting rule for frontmatter scalars, and it renders the read-context.
Two rules existed. ``verdicts._unquote`` (``.strip().strip('"').strip("'").strip()``) unquoted the
structural key correctly; ``okf.bundle_context`` unquoted a title with a bare ``.strip('"')``. The
weaker one sat in the path that becomes the agent's read-context and that the commons-owned
nav-goldens byte-compare. Measured before the fix:
title: " Spaced " -> ``## concept: Spaced `` (the whitespace half — what (a) named)
title: 'Single' -> ``## concept: 'Single'`` (single quotes rendered verbatim)
Both are frontmatter YAML writes any hand-authoring curator may make, and both reach the model.
This is the (p) defect class two copies of one conversion, the drifted copy where it matters
so the fix is the same shape: ONE source, owned by the module that owns ``parse_frontmatter``.
Detach points, each its own test: weaken the renderer back to ``.strip('"')`` -> RED; reintroduce
a private copy in ``verdicts`` -> RED. The control proves the gate covers ground the nav-goldens
do not: every golden title is double-quoted with no inner whitespace, so the goldens stay byte-
identical under BOTH rules and can never have caught this.
"""
from __future__ import annotations
from pathlib import Path
import pytest
from portfolio_optimiser import okf
from portfolio_optimiser import verdicts as verdicts_mod
_GOLDEN_ROOT = Path(__file__).resolve().parents[1] / "shared" / "examples"
def _bundle(tmp_path: Path, title_line: str) -> str:
"""A minimal two-file bundle whose single concept file carries ``title_line`` verbatim."""
(tmp_path / "index.md").write_text(
'---\ntype: index\ntitle: "Root"\n---\n\nSummary.\n\n- [A](a.md)\n',
encoding="utf-8",
)
(tmp_path / "a.md").write_text(
f"---\ntype: concept\n{title_line}\n---\n\nbody a\n", encoding="utf-8"
)
return str(tmp_path)
def _heading(bundle_dir: str) -> str:
ctx = okf.bundle_context(okf.navigate_bundle(bundle_dir))
return next(line for line in ctx.splitlines() if line.startswith("## "))
@pytest.mark.parametrize(
("title_line", "expected"),
[
('title: " Spaced "', "## concept: Spaced"),
("title: 'Single'", "## concept: Single"),
('title: "Plain"', "## concept: Plain"),
("title: Bare", "## concept: Bare"),
],
)
def test_rendered_title_is_unquoted_and_trimmed(
tmp_path: Path, title_line: str, expected: str
) -> None:
"""The rendered heading carries the TITLE, not the frontmatter's quoting artifacts.
Detach point: revert ``bundle_context`` to ``.strip('"')`` -> the first two rows go RED
(``## concept: Spaced `` and ``## concept: 'Single'``). The last two rows are the control
that the stronger rule did not change the cases that already worked."""
assert _heading(_bundle(tmp_path, title_line)) == expected
def test_frontmatter_unquoting_has_exactly_one_source() -> None:
"""``verdicts`` must DELEGATE, not carry its own copy — the (p) rule applied to unquoting.
Identity, not equal behaviour: two implementations that agree today are exactly the state
this defect class starts from. Reintroduce a private copy in ``verdicts`` -> RED."""
assert verdicts_mod._unquote is okf.unquote_scalar, (
"verdicts must delegate to okf.unquote_scalar; a private copy is the defect class"
)
def test_verdict_structural_key_still_unquotes_after_delegation() -> None:
"""The delegation must be behaviour-identical on the structural key, because ``_mint_id``
hashes these values a normalising change would re-key every promoted verdict.
Not a tautology against the source: the expected values are written out longhand here."""
assert okf.unquote_scalar('" Spaced "') == "Spaced"
assert okf.unquote_scalar("'Single'") == "Single"
assert okf.unquote_scalar(" bare ") == "bare"
assert okf.unquote_scalar('"18000"') == "18000"
def test_nav_goldens_cannot_have_caught_this() -> None:
"""CONTROL — the commons-owned byte-level fasit is blind to this defect by construction.
Every golden title is double-quoted with no inner whitespace, so ``.strip('"')`` and
``unquote_scalar`` render byte-identically there. If a future golden gains a single-quoted or
space-padded title this test goes RED and says so: the fasit would then be load-bearing for
the rule, and this file's claim to cover uncovered ground would no longer hold."""
titles = [
line.split(":", 1)[1].strip()
for path in sorted(_GOLDEN_ROOT.glob("nav-golden-*/**/*.md"))
for line in path.read_text(encoding="utf-8").splitlines()
if line.startswith("title:")
]
assert titles, "no golden titles found — the control has lost its subject"
for raw in titles:
assert raw.strip('"') == okf.unquote_scalar(raw), (
f"golden title {raw!r} now discriminates between the two rules — the nav-goldens "
"have become load-bearing for unquoting, so this control must be re-stated"
)