From 1f525ff54054160a9bda391ca69467b329ca20b0 Mon Sep 17 00:00:00 2001 From: Marius Ciepluch <11855163+norandom@users.noreply.github.com> Date: Fri, 2 Oct 2026 17:24:49 +0200 Subject: [PATCH] fix(learn): example rows drop another profile's null features when written and read Static-profile feature records carry the nine plane-only features (agree.*, ms.*, verify.*) as null in x; after cb85542 the 937 live example rows loaded, but the renderer's validate_x refused every one of them ("features outside the static allow-list"), so no program could prepare a prompt (found while probing exp-002 model-free). profile_x drops a null feature outside the row's profile and keeps a valued one, so a real leak still fails. Test added. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo --- src/openultrasast/learn/examples.py | 20 ++++++++++++++++---- tests/test_learn_examples.py | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/openultrasast/learn/examples.py b/src/openultrasast/learn/examples.py index a97a819..592def3 100644 --- a/src/openultrasast/learn/examples.py +++ b/src/openultrasast/learn/examples.py @@ -40,6 +40,16 @@ from typing import Any from ..plane.memory import MemoryStore, repo_key, row_id from .excerpt import EXAMPLE, Bounds, delta_diff, excerpt, function_bounds, identities_of from .labels import Label, Sources +from .schema import features_for + + +def profile_x(x: Mapping[str, Any], profile: str) -> dict[str, Any]: + """``x`` without another profile's features stored as null: a static feature record carries the plane-only + features (``agree.*``, ``ms.*``, ``verify.*``) as null, and :func:`.schema.validate_x` refuses a name outside + the profile's allow-list whatever its value. A foreign feature with a value stays, so the refusal still fires.""" + known = {spec.name for spec in features_for(profile)} + return {k: v for k, v in x.items() if v is not None or k in known} + EXAMPLE_KIND = "example" RUN = "learn-memory" @@ -208,7 +218,8 @@ def build_examples( "frameworks": list(label["frameworks"]) if label.get("frameworks") is not None else None, "unit": unit, "direction": label.get("direction"), "pin_role": label.get("pin_role", "vulnerable"), "weight": float(label.get("weight", 1.0)), "license": (license_of(label) if license_of else "") or "", - "x": dict(record["x"]), "instruments": {k: dict(v) for k, v in record["instruments"].items() if v is not None}, + "x": profile_x(record["x"], profile), + "instruments": {k: dict(v) for k, v in record["instruments"].items() if v is not None}, "roles": list(roles_of(label)) if roles_of else [], "excerpt_sha": shown.sha, "label_set_digest": digest, } ) # fmt: skip @@ -238,13 +249,14 @@ class Example: license: str = "" @classmethod - # An instrument that is not part of the row's profile may be stored as null (feature records carry every - # instrument name); it is not a table and is skipped, both when a row is written and when it is read. + # An instrument or a feature that is not part of the row's profile may be stored as null (feature records carry + # every instrument and feature name); both are skipped when a row is written and when it is read. def from_row(cls, row: Mapping[str, Any]) -> Example: + profile = str(row.get("profile") or "static") return cls( id=str(row["id"]), group=str(row.get("group") or ""), source=str(row["source"]), frameworks=tuple(row.get("frameworks") or ()), family=str(row["family"]), label=int(row["label"]), language=str(row.get("language") or "other"), - profile=str(row.get("profile") or "static"), unit=str(row.get("unit") or "pin"), x=dict(row["x"]), + profile=profile, unit=str(row.get("unit") or "pin"), x=profile_x(row["x"], profile), instruments={k: dict(v) for k, v in row["instruments"].items() if v is not None}, roles=tuple(row.get("roles") or ()), excerpt_sha=str(row["excerpt_sha"]), license=str(row.get("license") or ""), ) # fmt: skip diff --git a/tests/test_learn_examples.py b/tests/test_learn_examples.py index 49f3e00..ed8e6a8 100644 --- a/tests/test_learn_examples.py +++ b/tests/test_learn_examples.py @@ -229,3 +229,27 @@ def test_null_instruments_are_skipped_when_reading_and_writing() -> None: } # fmt: skip example = Example.from_row(row) assert set(example.instruments) == {"language"} + + +def test_null_foreign_features_are_skipped_but_a_valued_one_stays() -> None: + """Every live static example row (937 on 2026-10-02) carried the nine plane-only features as null in ``x``; the + renderer's ``validate_x`` refused them all. A foreign feature with a value is a leak and must still reach it.""" + from openultrasast.learn.examples import Example, profile_x + from openultrasast.learn.schema import features_for + + static = {spec.name for spec in features_for("static")} + plane_only = sorted({spec.name for spec in features_for("plane")} - static) + kept = sorted(static)[0] # a static feature stored as null (its instrument failed) is kept for validate_x + assert "verify.votes" in plane_only + x: dict[str, object] = {name: None for name in plane_only} + x[kept] = None + assert profile_x(x, "static") == {kept: None} + assert profile_x({**x, "verify.votes": 3}, "static") == {kept: None, "verify.votes": 3} + row = { + "id": "x", "kind": "example", "repo": "o/r", "pin": "p", "run": "learn-memory", "task": "build", "population": "pairs", + "split": "train", "image": "host", "candidate": "a.py::f", "family": "injection", "language": "python", + "profile": "static", "label": 1, "source": "pairs", "group": "o/r", "frameworks": None, "unit": "pin", + "direction": None, "pin_role": "vulnerable", "weight": 1.0, "license": "MIT", "x": x, + "instruments": {"language": {"state": "ran"}, "verify": None}, "roles": [], "excerpt_sha": "0" * 64, "label_set_digest": "1" * 64, + } # fmt: skip + assert set(Example.from_row(row).x) == {kept}