test(okf): the one unquoting rule was pinned at its edge, not in its three clauses

D7 mirroring candidate (a)/(i) `unquote_scalar`, measured. The sibling grew that
function after a duplicated conversion had drifted; our counterpart
`okf._strip_matching_quotes` is genuinely ONE rule -- one definition, one call
site, and `unquote` appears in 0 of 76 .py files under src+tests (positive
control: the same query finds `parse_frontmatter`). So the drift shape is absent.

But the rule was covered only at its edge. Detaching it outright is red; each of
its three clauses was green-but-dead against the whole 950-test suite -- weakening
the length guard, dropping the matching requirement, and widening the quote set
with a symmetric delimiter all left the suite green. Same class as the
_STRUCTURE_MARKERS hole: named and edge-covered is not covered.

tests/test_okf_unquote_loadbearing.py closes the three clauses (950 -> 955). Each
clause test is green before and red after exactly its own mutation, with the
population control green in both, clause 3 pinned on its line via --red-at.

A measuring trap, measured: the first clause-3 mutation added '[' to the quote
set and the suite stayed green -- which reads as "not covered" but is a NO-OP,
since '[' can never satisfy the matching clause. Flow-form values are protected
by the matching clause, not the quote set. The harness cannot distinguish a
behaviour-preserving mutation from an undetected seam; both surface as "stayed
GREEN". A mutation must be shown to change behaviour before its green is read as
a hole.

No flow decoding is added here -- that is the sibling's B4 work, and these tests
pin today's boundary so it cannot land silently on this side.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-08-31 23:31:17 +02:00
commit 607f017537
2 changed files with 190 additions and 1 deletions

View file

@ -41,7 +41,7 @@ kandidater, ikke som planlagt arbeid:
- S3.2
- S4.0 (`126807a`)
- (p) `to_ore` — TO kallsteder
- (a)/(i) `unquote_scalar`
- ~~(a)/(i) `unquote_scalar`~~ — **MÅLT 2026-08-31, se under**
- `mandate.py`
- A5 — TO halvdeler
- ~~B4 `ToolCallRecorder`~~ — **BESVART 2026-08-25, se under**
@ -77,6 +77,55 @@ grønn er nettopp populasjons-kontrollen, som den skal. SDK-fila ble restaurert
**Datering (D7-rammen):** dette er arbeid ETTER 2026-08-09 og skal **ikke** leses som
uavhengig konvergens selv om svaret er identisk med søskenets.
### (a)/(i) `unquote_scalar` — svaret er JA, den var ÉN regel, men pinnet bare i kanten (målt 2026-08-31)
Kandidaten står i køen fordi søskenet vokste en navngitt `unquote_scalar` etter at en
**duplisert konvertering hadde driftet** — to steder som fjernet anførselstegn fra en
frontmatter-skalar, etter to regler. Speilings-spørsmålet er derfor ikke «har vi funksjonen»,
men det søskenets defekt faktisk stiller: **er den ÉN regel hos oss, og er selve regelen
load-bearing?**
**Populasjonen først.** `unquote_scalar` finnes ikke hos oss: **0 treff av 76 undersøkte
`.py`-filer** i `src`+`tests` (positiv kontroll: samme spørring finner `parse_frontmatter` i
`okf.py`), og `unquote` finnes ikke i repoet utenfor `.venv`. Vår motpart er
`okf._strip_matching_quotes`**én definisjon, ett kallsted** (`_parse_frontmatter_and_body`).
Søskenets drift-form finnes altså ikke her.
**Men regelen var dekket bare i kanten.** Med `scripts/mutation_harness.py`, nevner `tests/`
(hele suiten, 950 tester), hver kjøring sha256-restaurert:
- Å detache regelen helt (`return value[1:-1]``return value`) er **RØD**
`test_okf.py::TestFrontmatter::test_unknown_fields_preserved_and_quotes_stripped` fanger den.
- Hver av de tre **klausulene** var **grønn-men-død**: å svekke lengdevakten (`>= 2``>= 1`),
å droppe matching-kravet (`value[0] == value[-1] and`), og å utvide quote-settet med en
symmetrisk delimiter (backtick) lot hele suiten stå grønn.
Samme klasse som `_STRUCTURE_MARKERS`-hullet i økt 32: sømmen var NAVNGITT og kant-dekket, som
ikke er det samme som dekket. **Pinnet av** `tests/test_okf_unquote_loadbearing.py` (5 tester,
950 → 955). Value-beviset er kjørt, ikke påstått: hver klausul-test er grønn før og rød etter
nøyaktig sin egen mutasjon, med populasjons-kontrollen grønn i begge (mutasjonen landet ikke
for bredt), og ledd 3 pinnet på linje via `--red-at`.
**EN MÅLETRAP, MÅLT — ny lærdom om harnesset.** Første forsøk på klausul 3 utvidet settet med
`'['`. Suiten forble grønn, hvilket leses som «klausulen er ikke dekket» — men mutasjonen er en
**no-op**: `'['` kan aldri tilfredsstille matching-kravet, siden `[` ikke er `]`. Flow-form-
verdier er altså beskyttet av **matching-klausulen, ikke av quote-settet**, og en grønn kjøring
under den mutasjonen var aldri bevis om quote-settet i det hele tatt. **Harnesset kan ikke
skille en oppførsels-bevarende mutasjon fra en udekket søm — begge kommer ut som «stayed
GREEN».** En mutasjon må vises å endre oppførsel før dens grønne leses som et hull. Dette er
Verifiseringsloven ansikt 4 anvendt på selve måleapparatet: et negativt resultat fra en
spørring som ikke KAN finne, er ikke null — det er ikke målt.
**Ærlig grense — hva dette IKKE sier.** Å pinne at flow-verdier passerer **urørt** er ikke
flow-DEKODING, og fila legger ingen til: `tags: [a, b]` forblir strengen `"[a, b]"`. Den
linje-orienterte parseren har ingen nesting-modell ved design (§1 ærlighets-regelen). Den
additive flow-dekoderen er søskenets B4-arbeid i `portfolio-optimiser` og er bevisst **ikke**
bygget her; testene pinner dagens grense slik at det arbeidet ikke kan lande stille på denne
siden.
**Datering (D7-rammen):** arbeid ETTER 2026-08-09 — skal **ikke** leses som uavhengig konvergens.
Rammen rundt køen: å lese søskenets kode er tillatt (`3bdf7f0`), men kopiering skal kun skje
der det tjener løsningen, aldri som snarvei. **Uavhengighets-beviset er DATERT** t.o.m.
2026-08-09; arbeid etter den datoen kan ikke leses som uavhengig konvergens.

View file

@ -0,0 +1,140 @@
"""(a)/(i) `unquote_scalar`: is our one unquoting rule pinned, or pinned only at the edge?
The D7 mirroring queue (``docs/2026-08-18-funn-koeer-og-gater.md § D7-speilingskøen``)
carries this candidate because the MAF sibling grew a named ``unquote_scalar`` after
a DUPLICATED conversion had drifted two places unquoting a frontmatter scalar, by
two rules. Our counterpart is ``okf._strip_matching_quotes``: one definition, one
call site (``_parse_frontmatter_and_body``). The mirroring question is therefore not
"do we have the function" but the one the sibling's defect actually poses — **is it
the ONE rule, and is the rule itself load-bearing in each of its three clauses?**
MEASURED 2026-08-31 with ``scripts/mutation_harness.py``, denominator ``tests/``
(the whole suite, 950 tests), each run restored sha256-verified:
- Detaching the rule outright (``return value[1:-1]`` -> ``return value``) is RED
``test_okf.py::TestFrontmatter::test_unknown_fields_preserved_and_quotes_stripped``
catches it. The seam has an edge guard.
- Each of the three CLAUSES is GREEN-BUT-DEAD. Weakening the length guard
(``>= 2`` -> ``>= 1``), dropping the matching requirement
(``value[0] == value[-1] and``), and widening the quote set with a SYMMETRIC
delimiter (adding a backtick) each left the pre-existing suite green. Nothing
noticed.
So the answer mirrors økt 32's ``_STRUCTURE_MARKERS`` hole, not B4's: the seam was
NAMED and edge-covered, which is not the same as covered. This file closes the three
clauses. Each test below was proved RED under exactly the mutation it names.
WHY THIS CANDIDATE, NOW. ``llm-ingestion-okf`` pins its emission to FLOW form, so a
frontmatter value may legally arrive as ``[a, b]`` or ``{k: v}``. Which clause
actually protects those turned out NOT to be the one reached for first see below.
A MEASURING TRAP, MEASURED. The first attempt at the third clause widened the set
with ``'['``. The suite stayed green, which reads as "clause not covered" but the
mutation is a NO-OP: ``'['`` can never satisfy the matching clause, since ``[`` is
not ``]``. So flow-form values are protected by the MATCHING clause, not by the
quote set, and a green run under that mutation was never evidence about the quote
set at all. The harness cannot tell a behaviour-preserving mutation from an
undetected seam both surface as "stayed GREEN". A mutation must be shown to
change behaviour before its green is read as a hole; the backtick, being
symmetric, does change it and is what the clause is pinned with below.
HONEST LIMIT what this does NOT say. Pinning that flow values pass through
UNTOUCHED is not flow DECODING, and this file does not add any: ``tags: [a, b]``
stays the string ``"[a, b]"``. The line-oriented parser has no nesting model by
design (``_parse_frontmatter_and_body``'s own docstring, §1 honesty rule). An
additive flow decoder is the sibling's B4 work in ``portfolio-optimiser`` and is
deliberately NOT built here; these tests pin today's boundary so that work cannot
land silently on this side.
Dated under the D7 frame: this is work AFTER 2026-08-09 and must NOT be read as
independent convergence with the sibling.
"""
from __future__ import annotations
import ast
from pathlib import Path
from portfolio_optimiser_claude.okf import parse_concept_file
SRC_PKG = Path(__file__).resolve().parents[1] / "src" / "portfolio_optimiser_claude"
OKF_SOURCE = SRC_PKG / "okf.py"
RULE_NAME = "_strip_matching_quotes"
def _concept_with(tmp_path: Path, value: str) -> dict[str, str]:
"""Parse ``title: <value>`` through the PUBLIC path and hand back the frontmatter.
Through ``parse_concept_file``, never by calling the private rule directly: a
layer you do not run is not a seam (økt 37). What is asserted below is what the
parser actually hands downstream.
"""
path = tmp_path / "a.md"
path.write_text(f"---\ntype: reference\ntitle: {value}\n---\nBody.\n", encoding="utf-8")
return parse_concept_file(path).frontmatter
class TestTheUnquotingRuleIsOneRule:
"""The population control — and it runs first, because every clause below is
worth only as much as the claim that there is exactly ONE place to pin."""
def test_exactly_one_definition_and_one_call_site(self) -> None:
# This is the sibling's defect made measurable on our side: their duplicate
# drifted. RED the day a second unquoting rule appears, or the single call
# site becomes two. Read from the AST, not from a grep of prose.
tree = ast.parse(OKF_SOURCE.read_text(encoding="utf-8"))
definitions = [
n for n in ast.walk(tree) if isinstance(n, ast.FunctionDef) and n.name == RULE_NAME
]
call_sites = [
n
for n in ast.walk(tree)
if isinstance(n, ast.Call) and isinstance(n.func, ast.Name) and n.func.id == RULE_NAME
]
assert len(definitions) == 1, f"the ONE unquoting rule is now {len(definitions)}"
assert len(call_sites) == 1, (
f"{RULE_NAME} gained a second call site — the sibling's drift shape: "
f"lines {[c.lineno for c in call_sites]}"
)
def test_the_rule_still_strips_the_ordinary_case(self, tmp_path: Path) -> None:
# POSITIVE CONTROL FOR EVERY NEGATIVE BELOW. Each clause test asserts that
# some value comes through UNSTRIPPED; that is vacuous unless stripping
# demonstrably happens at all on this path.
frontmatter = _concept_with(tmp_path, '"Quoted title"')
assert frontmatter["title"] == "Quoted title"
class TestEachClauseOfTheRuleIsLoadBearing:
"""One test per clause of ``len(value) >= 2 and value[0] == value[-1] and
value[0] in {'"', "'"}`` each proved RED under its own mutation."""
def test_length_guard_protects_a_single_quote_character(self, tmp_path: Path) -> None:
# RED under `len(value) >= 2` -> `len(value) >= 1`.
# A lone quote is its own first AND last character, so without the length
# guard it satisfies the other two clauses and `value[1:-1]` erases it.
# A malformed scalar must survive as itself — OKF robustness: tolerate,
# never silently rewrite.
assert _concept_with(tmp_path, '"')["title"] == '"'
def test_matching_requirement_protects_an_unterminated_quote(self, tmp_path: Path) -> None:
# RED under dropping `value[0] == value[-1] and`.
# Without it, an unterminated `"Oslo` is stripped from BOTH ends and
# arrives as `Osl` — a silent corruption strictly worse than the
# malformed input it came from.
assert _concept_with(tmp_path, '"Oslo')["title"] == '"Oslo'
assert _concept_with(tmp_path, "Oslo'")["title"] == "Oslo'"
def test_the_quote_set_is_exactly_two_characters(self, tmp_path: Path) -> None:
# RED under widening the set with a SYMMETRIC delimiter:
# `{'"', "'"}` -> `{'"', "'", '`'}`. A backtick pair is not a YAML quote,
# and the set is closed at two.
assert _concept_with(tmp_path, "`code`")["title"] == "`code`"
# Flow-form values (llm-ingestion-okf pins its emission to flow form) must
# ride through navigation UNTOUCHED (ingest-spec §7). These are guarded by
# the MATCHING clause above, not by the quote set — `[` is not `]` — and
# they are asserted here because that is where a flow decoder would first
# be reached for. Stripping the delimiters would hand downstream a string
# that is neither the flow value nor its decoding.
assert _concept_with(tmp_path, "[a, b]")["title"] == "[a, b]"
assert _concept_with(tmp_path, "{k: v}")["title"] == "{k: v}"