Files
Open_Ultra_SAST/src/openultrasast/learn/examples.py
T
Marius CiepluchandClaude Opus 5.5 d9608b9a63 bench(learn): harvest the advisory-fix pairs
The 97 advisory-fix pairs (194 sides) harvested for the decision engine: verify a/b + agree on the 34
untrusted_destination sides and model roles on every side as plane Runs on ax ($0.38 metered, task
budgets $1.49, ceiling $5; DeepSeek balance 17.88 -> 17.73), engine features on the host (frozen
7b17eac, one container, --memory 3g: 54 ran, 58 asked no question, 82 no language model), feature
records for all 194 sides, static memory rebuilt with the merged harvest units: 724 -> 904 examples.
No unit was skipped for the 20 KB inline limit.

Instrument fix: SideReader read only the first pair-kind source, so the first rebuild left all 194
advisory sides `unread` (0 examples). It now reads every pair-kind source; test added.

Leak audit: the static profile flags only engine signals and facts.function_lines (withheld by v1);
the plane profile newly flags verify.flag_b and ms.operation (plane-only, not in any v1 prompt).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
2026-10-02 09:40:00 +02:00

325 lines
16 KiB
Python

"""The example store: the decision engine's local memory (learned-decision-engine design section 4.2, Req 3.2, 3.6).
No model. ``ousast learn memory build`` joins each verified label (``ousast learn labels``) with the feature record of
the same candidate and an excerpt of its function at the label's pin, and writes one ``example`` row per candidate
into the memory store, with the excerpt as a content-addressed blob ``excerpts/<sha>.txt``::
envelope (id, kind=example, repo, pin, run, task, population=<source>, split, image)
+ {candidate, family, language, profile, label, source, group, frameworks, unit, direction, pin_role, weight,
license, x, instruments, roles, excerpt_sha, label_set_digest}
Memory examples carry **no rationale** (code, signals, roles, family and label only). Refusals are loud:
- a row with ``origin: user`` (the opt-in adaptation layer never enters the generalisation memory, Req 7.5) or a
source that ``sources.toml`` does not list stops the build (:class:`ExampleBuildError`);
- conditional rows (``benign_control``, ``assumed_benign``) are skipped until their condition is evaluated;
- a candidate whose excerpt is empty or whose function is not found is never stored; when more than 10% of a
source's recorded candidates have no excerpt the build fails that source (exit 2 in the CLI): an unread clone is
not a small memory. A fixed side whose file was read but no longer declares the labelled function is a label
defect, counted apart as ``absent_fixed_side`` (the label builder emits a fixed-side negative only where the fixed
side declares its candidate function, so this count should stay 0). A pair label names the function its side
declares -- the labelled one, or the renamed one of a ``fixed_side_moved`` negative -- never the catalog's
``fix_function`` (a different handler of the same snapshot).
Pair labels have no commit pin (the corpus holds excerpts); their envelope pin is :func:`label_pin`, a stable
40-hex digest of the pair and its side, so the vulnerable and the fixed side stay distinct rows. The harvest keyed a
pair side's feature record by its unit's pin instead (the blob sha1 of the side's excerpt, ``plane/harvest.py``):
:func:`pair_pins` reads that mapping from the harvest ``units.json`` and the build uses it when given.
"""
from __future__ import annotations
import hashlib
import json
import re
from collections.abc import Callable, Iterable, Mapping, Sequence
from dataclasses import asdict, dataclass, field
from pathlib import Path
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
EXAMPLE_KIND = "example"
RUN = "learn-memory"
TASK = "build"
IMAGE = "host"
NO_EXCERPT_LIMIT = 0.10
DERIVED_SOURCES = {"benign_control": "population"} # sources the label builder derives from a listed source
_PIN = re.compile(r"[0-9a-f]{40}")
class ExampleBuildError(RuntimeError):
"""A label the memory must not hold (``origin: user``, a source outside ``sources.toml``) or a source whose
excerpts could not be read."""
def label_pin(label: Mapping[str, Any]) -> str:
"""The envelope pin of a label: its commit, or for a pair (no commit) a stable digest of pair and side."""
pin = str(label.get("pin") or "")
if _PIN.fullmatch(pin):
return pin
subject = f"{label.get('source')}:{label.get('source_ref')}:{label.get('pin_role', 'vulnerable')}"
return hashlib.sha1(subject.encode("utf-8")).hexdigest() # noqa: S324 -- a name, not a security digest
def pair_pins(units: Mapping[str, Mapping[str, Any]]) -> dict[tuple[str, str], str]:
"""Harvest ``units.json`` -> ``(case reference, side) -> pin`` for the pair units (the pin their records carry)."""
return {(str(u["ref"]), str(u["side"])): str(u["pin"]) for u in units.values() if u.get("source") == "pairs"}
def record_key(repo: str, pin: str, candidate: str, family: str, unit: str) -> tuple[str, str, str, str, str]:
return repo_key(repo), pin, candidate, family, unit
def _as_dict(label: Label | Mapping[str, Any]) -> dict[str, Any]:
return asdict(label) if isinstance(label, Label) else dict(label)
def label_set_digest(labels: Iterable[Label | Mapping[str, Any]]) -> str:
lines = sorted(json.dumps(_as_dict(row), sort_keys=True, default=list) for row in labels)
return hashlib.sha256("\n".join(lines).encode("utf-8")).hexdigest()
@dataclass
class SourceCount:
labels: int = 0
no_record: int = 0
recorded: int = 0
no_excerpt: int = 0 # unread side, or the labelled function not found where it must be (counts to the 10%)
unread: int = 0
absent_fixed_side: int = 0 # file read, the function is gone at the fix: a label defect, reported apart
examples: int = 0
@dataclass
class MemoryBuild:
rows: list[dict[str, Any]] = field(default_factory=list)
sources: dict[str, SourceCount] = field(default_factory=dict)
skipped: dict[str, int] = field(default_factory=dict)
def skip(self, reason: str) -> None:
self.skipped[reason] = self.skipped.get(reason, 0) + 1
def failing(self, limit: float = NO_EXCERPT_LIMIT) -> list[str]:
"""Sources where more than ``limit`` of the recorded candidates have no excerpt."""
return sorted(s for s, c in self.sources.items() if c.recorded and c.no_excerpt / c.recorded > limit)
def summary(self) -> dict[str, Any]:
return {
"examples": len(self.rows),
"by_source": {s: asdict(c) for s, c in sorted(self.sources.items())},
"skipped": dict(sorted(self.skipped.items())),
"failing_sources": self.failing(),
}
LinesOf = Callable[[Mapping[str, Any], str], Sequence[str] | None] # (label, pin_role) -> file lines at that side
def _counter_role(label: Mapping[str, Any]) -> str:
return "vulnerable" if label.get("pin_role") == "fixed" else "fixed"
def build_examples(
labels: Iterable[Label | Mapping[str, Any]],
records: Mapping[tuple[str, str, str, str, str], Mapping[str, Any]],
lines_of: LinesOf,
*,
sources: Sources,
store: MemoryStore | None = None,
profile: str = "static",
roles_of: Callable[[Mapping[str, Any]], Sequence[Mapping[str, Any]]] | None = None,
license_of: Callable[[Mapping[str, Any]], str] | None = None,
function_of: Callable[[Mapping[str, Any], str], str | None] | None = None,
bounds: Bounds = EXAMPLE,
pins: Mapping[tuple[str, str], str] | None = None,
) -> MemoryBuild:
"""Example rows for the verified labels that have a feature record (``records`` by :func:`record_key`) and an
excerpt; with ``store`` the excerpt blobs and the rows are written. Delta units append the base->head diff.
``pins`` (:func:`pair_pins`) gives a pair side the pin its harvest record was stored under."""
rows = [_as_dict(label) for label in labels]
allowed = {s.id for s in sources.sources} | {d for d, kind in DERIVED_SOURCES.items() if any(s.kind == kind for s in sources.sources)}
for row in rows:
if row.get("origin") == "user":
raise ExampleBuildError(f"label {row.get('candidate')!r} has origin: user -- the adaptation layer never enters the memory")
if row.get("source") not in allowed:
raise ExampleBuildError(f"label source {row.get('source')!r} is not in {sources.path}: it cannot enter the memory")
digest = label_set_digest(rows)
build = MemoryBuild()
for label in rows:
if label.get("conditional") is not None or label.get("source") == "assumed_benign":
build.skip("conditional label (condition not evaluated)")
continue
count = build.sources.setdefault(str(label["source"]), SourceCount())
count.labels += 1
side = (str(label.get("source_ref")), str(label.get("pin_role") or "vulnerable"))
pin = (pins or {}).get(side) if label.get("source") == "pairs" else None
pin = pin or label_pin(label)
candidate, family, unit = str(label["candidate"]), str(label["family"]), str(label["unit"])
record = records.get(record_key(str(label["repo"]), pin, candidate, family, unit))
if record is None or record.get("profile") != profile:
count.no_record += 1
continue
count.recorded += 1
path, _, function = candidate.partition("::")
function = (function_of(label, str(label.get("pin_role") or "vulnerable")) if function_of else None) or function
language = str(record.get("language") or label.get("language") or "other")
identities = identities_of(str(label.get("repo") or ""), path, [str(label.get("pin") or "")])
lines = lines_of(label, str(label.get("pin_role") or "vulnerable"))
diff = None
if unit == "delta" and lines:
base = lines_of(label, _counter_role(label))
head_span, base_span = function_bounds(lines, language, function), function_bounds(base or (), language, function)
if base and head_span and base_span:
diff = delta_diff(base[slice(*base_span)], lines[slice(*head_span)], language, identities=identities)
shown = excerpt(lines, language, function, bounds=bounds, identities=identities, diff=diff)
if shown is None:
if not lines:
count.unread += 1
elif label.get("pin_role") == "fixed":
count.absent_fixed_side += 1
continue
count.no_excerpt += 1
continue
if store is not None:
store.put_blob("excerpts", shown.text.encode("utf-8"))
subject = f"{candidate}\x00{family}\x00{unit}\x00{label.get('pin_role')}\x00{label.get('source_ref')}"
build.rows.append(
{
"id": row_id(EXAMPLE_KIND, RUN, TASK, f"{label['repo']}\x00{pin}\x00{subject}"), "kind": EXAMPLE_KIND,
"repo": repo_key(str(label["repo"])), "pin": pin, "run": RUN, "task": TASK, "population": str(label["source"]),
"split": str(label.get("split") or label["source"]), "image": IMAGE,
"candidate": candidate, "family": family, "language": language, "profile": profile, "label": int(label["label"]),
"source": str(label["source"]), "group": str(label.get("group") or ""),
"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": dict(record["instruments"]),
"roles": list(roles_of(label)) if roles_of else [], "excerpt_sha": shown.sha, "label_set_digest": digest,
}
) # fmt: skip
count.examples += 1
if store is not None and build.rows:
store.put_rows(build.rows)
return build
@dataclass(frozen=True)
class Example:
"""An example row as retrieval and the program use it (no envelope identity beyond ``id`` and ``group``)."""
id: str
group: str
source: str
frameworks: tuple[str, ...]
family: str
label: int
language: str
profile: str
unit: str
x: Mapping[str, Any]
instruments: Mapping[str, Mapping[str, Any]]
roles: tuple[Mapping[str, Any], ...]
excerpt_sha: str
license: str = ""
@classmethod
def from_row(cls, row: Mapping[str, Any]) -> Example:
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"]),
instruments={k: dict(v) for k, v in row["instruments"].items()}, roles=tuple(row.get("roles") or ()),
excerpt_sha=str(row["excerpt_sha"]), license=str(row.get("license") or ""),
) # fmt: skip
def load_examples(store: MemoryStore, profile: str | None = None) -> list[Example]:
"""Every example row in the store (optionally one profile), in key then id order."""
where = {"profile": profile} if profile else None
return [Example.from_row(r.row) for r in store.rows(kind=EXAMPLE_KIND, where=where)]
# --- reading the label sides --------------------------------------------------------------------------------------------
class SideReader:
"""File lines of a label's side, read-only: pairs from the corpus excerpts, populations and adjudications from
their clones (``git show pin:path``), development recipes from their checkouts. ``None`` when unread."""
def __init__(self, root: Path, cache: Path, sources: Sources, labels: Sequence[Mapping[str, Any]]) -> None:
from .labels import Clone
self.root, self.cache, self.sources = Path(root), Path(cache), sources
self._pairs: dict[str, Any] | None = None
self._clones: dict[str, Clone | None] = {}
self._case_of: dict[str, str] = {}
for label in labels:
source = next((s for s in sources.sources if s.id == label.get("source")), None)
if source is not None and source.kind == "population":
self._case_of.setdefault(str(label.get("repo")), f"{source.options.get('cache', 'independent')}/{label.get('source_ref')}")
def _pair_cases(self) -> dict[str, Any]:
if self._pairs is None:
from ..pairs import load_pair_catalog
# every pair-kind source (the corpus catalog and e.g. advisory-fixes): labels name both as source "pairs"
self._pairs = {}
for source in (s for s in self.sources.sources if s.kind == "pairs"):
self._pairs.update({case.name: case for case in load_pair_catalog(self.root / source.files[0])})
return self._pairs
def license(self, label: Mapping[str, Any]) -> str:
if label.get("source") != "pairs":
return ""
case = self._pair_cases().get(str(label.get("source_ref")))
return str(getattr(case, "license", "") or "")
def __call__(self, label: Mapping[str, Any], pin_role: str) -> list[str] | None:
from .labels import Clone, LabelSourceError
source = str(label.get("source"))
path = str(label.get("candidate", "")).partition("::")[0]
if source == "pairs":
case = self._pair_cases().get(str(label.get("source_ref")))
if case is None:
return None
file = case.vuln_file if pin_role == "vulnerable" else case.fixed_file
return Path(file).read_text(encoding="utf-8", errors="replace").splitlines() if Path(file).is_file() else None
if source == "dev-php":
name = str(label.get("source_ref", "")).partition(":")[0]
file = self.cache / "repos" / name / str(label.get("pin"))[:12] / path
return file.read_text(encoding="utf-8", errors="replace").splitlines() if file.is_file() else None
case_dir = self._case_of.get(str(label.get("repo")))
if case_dir is None:
return None
if case_dir not in self._clones:
try:
self._clones[case_dir] = Clone(self.cache / case_dir)
except LabelSourceError:
self._clones[case_dir] = None
clone = self._clones[case_dir]
return clone.lines(str(label.get("pin")), path) if clone is not None else None
def read_jsonl(path: Path) -> list[dict[str, Any]]:
return [json.loads(line) for line in Path(path).read_text(encoding="utf-8").splitlines() if line.strip()]
def records_by_key(rows: Iterable[Mapping[str, Any]]) -> dict[tuple[str, str, str, str, str], dict[str, Any]]:
"""Feature records (``features`` rows of the store, or records with ``repo`` and ``pin`` beside them) by
:func:`record_key`."""
out: dict[tuple[str, str, str, str, str], dict[str, Any]] = {}
for row in rows:
key = record_key(str(row["repo"]), str(row["pin"]), str(row["candidate"]), str(row["family"]), str(row.get("unit", "pin")))
out[key] = dict(row)
return out
__all__ = [
"EXAMPLE_KIND", "NO_EXCERPT_LIMIT", "Example", "ExampleBuildError", "MemoryBuild", "SideReader", "build_examples",
"label_pin", "label_set_digest", "load_examples", "pair_pins", "read_jsonl", "record_key", "records_by_key",
] # fmt: skip