fix(okf): nested frontmatter keys must not forge the type that gates verdict exclusion

The frontmatter parser is a line-oriented approximation of YAML with no nesting
model, and it flattened INDENTED keys into the same mapping. Two measured
defects followed, the second load-bearing:

1. Sibling blocks sharing an inner key COLLIDED. Given OKF §10's canonical
   Attested Computation shape, `executor.resource` vanished silently and
   `attester.resource` was promoted to a top-level `resource`. No error raised.

2. An indented `type:` OVERWROTE the column-0 one, making the verdict-exclusion
   gate in `bundle_context` forgeable. A file declaring `type: verdict` at
   column 0, carrying any nested block with a `type:` in it, rendered its body
   straight into the read-context — defeating the §11 seam whose own docstring
   claimed "a mislabelled or injected edge cannot smuggle a verdict into the
   context". The type CHECK was there; the VALUE it checked was writable.

This is spec-legal input, not malformed input: method-spec §2 calls it YAML
frontmatter, and ingest-spec §7 (`:153`, `:216`) says unknown keys MAY follow
the stamp and ride through navigation.

Fix: only column-0 keys participate; indented lines are skipped, never
flattened. Nested blocks become OPAQUE — stated as a limitation in the
docstring, not dressed up as a nesting model we do not have (§1 honesty rule).

Single parse site, so the fix covers the class: `hitl.py:157` (verdict_id,
gated on .type) and `experience.py:137` (realization_rate, expected_actual)
all read through `ConceptFile.frontmatter`; `promotion.py` only emits, from a
fixed template.

Golden-neutral by measurement: 0 indented frontmatter lines across all 17
frontmatter-bearing files in `shared/examples/`.

Both tests written RED first and confirmed to die on the SEAM assertion, not on
a collateral one — the forgery test rendered `## project: Seed` before the fix.
Each negative carries a standalone positive control (sessions 17-18: a control
can itself hide behind a preceding assert).

Provenance: hypothesis received from llm-ingestion-okf, who measured the
flattening in their own parser and flagged that ours shares the form. They had
NOT measured our side. The type-clobber variant is ours, found by measuring the
neighbourhood rather than only the reported case.

Suite 688 -> 690.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJmse16bEkaSBtvXhncEUc
This commit is contained in:
Kjell Tore Guttormsen 2026-08-01 19:53:03 +02:00
commit d691510163
2 changed files with 77 additions and 1 deletions

View file

@ -17,7 +17,12 @@ from pathlib import Path
import pytest
from portfolio_optimiser_claude.okf import ConceptFile, bundle_context, navigate_bundle
from portfolio_optimiser_claude.okf import (
ConceptFile,
bundle_context,
navigate_bundle,
parse_concept_file,
)
BUNDLE = Path(__file__).resolve().parents[1] / "shared" / "examples" / "bygg-energi-mikro"
NAV_GOLDENS = Path(__file__).resolve().parents[1] / "shared" / "examples"
@ -322,6 +327,58 @@ class TestVerdictLayerExclusion:
assert "## verdict" not in context
assert "## project: A" in context
def test_nested_block_cannot_forge_the_type_that_gates_exclusion(self, tmp_path: Path) -> None:
# The exclusion in `bundle_context` gates on `.type`, and `.type` is whatever
# the frontmatter parse produced. A line-oriented parse that lets an INDENTED
# `type:` reach the same dict makes the gate forgeable: the file still declares
# `type: verdict` at column 0, but a later nested key overwrites it and the
# verdict body renders. Spec-legal input — method-spec §2 calls this YAML
# frontmatter, and ingest-spec §7 (`:153`, `:216`) says unknown keys MAY follow
# and ride through navigation.
# RED if nested keys participate in the frontmatter mapping.
marker = "NESTED-FORGERY-MARKER-0.91"
bundle = _make_bundle(
tmp_path,
"Summary. See [v](v.md) and [a](a.md).",
{
"v.md": (
"---\ntype: verdict\ntitle: Seed\n"
"provenance:\n type: project\n---\n"
f"Signal: {marker}."
),
"a.md": "---\ntype: project\ntitle: A\n---\nBody A.",
},
)
# Positive control #1 — the file IS navigated, so a marker-absence below is the
# exclusion doing work, not an unreachable file. Stands alone, behind no other
# assert (session 17: a control can itself hide behind a preceding assertion).
assert "v.md" in [c.path.name for c in navigate_bundle(bundle)]
context = bundle_context(bundle)
# Positive control #2 — a rendered concept proves the context is non-empty and
# that `## {type}: {title}` is EXACTLY the form the negatives search for.
assert "## project: A" in context
assert marker not in context
assert "## project: Seed" not in context
def test_nested_block_does_not_collide_with_a_top_level_key(self, tmp_path: Path) -> None:
# Two sibling blocks sharing an inner key (OKF §10 Attested Computation:
# `executor.resource` + `attester.resource`) must not collapse into one
# top-level `resource`, silently losing the first and promoting the second.
# RED if indented keys land in the frontmatter mapping.
_write(
tmp_path / "c.md",
"---\ntype: project\ntitle: C\nresource: top-level-value\n"
"executor:\n resource: references/skills/run-on-bq.md\n"
"attester:\n resource: references/attesters/revenue.py\n---\nBody C.",
)
frontmatter = parse_concept_file(tmp_path / "c.md").frontmatter
# Positive control — a COLUMN-0 key of the very name under test survives the
# parse. Without it, "the nested value is absent" would also hold for a parser
# that dropped `resource` entirely.
assert frontmatter["resource"] == "top-level-value"
assert "references/attesters/revenue.py" not in frontmatter.values()
assert "references/skills/run-on-bq.md" not in frontmatter.values()
def test_shared_bundle_context_carries_no_realization_signal(self) -> None:
# The seed verdict's learning signal (realization rate 0.82, expected
# actual 24 600 NOK) must be absent from the rendered context — it may