Files
Open_Ultra_SAST/src/openultrasast/hunt/table.py
T
Marius CiepluchandClaude Opus 5.5 602ec23e03 fix(hunt): lines read through a tool count as shown; an unparseable answer is an empty answer
The answer check counted only the rendered function text as shown, so 7 of
8 baseline suspicions citing lines the model had read with read_file were
marked unknown (baseline 1/12 against the pilot hunter's 6/12). Tools now
record the lines they return. A DSPy parse failure scores as zero findings
with a flag instead of a broken run. The per-run response cache now takes
effect through dspy.configure_cache.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 13:10:40 +02:00

97 lines
4.3 KiB
Python

"""Versioned rows of repository features, labels and producer provenance."""
from __future__ import annotations
import hashlib
import json
from collections.abc import Iterable
from copy import deepcopy
from pathlib import Path
from typing import Any
SCHEMA_VERSION = 1
KEY_COLUMNS = ("change_id", "repo", "head", "path", "line", "kind", "fold")
LABEL_COLUMNS = ("label", "family", "fix_span", "label_ref", "verification")
FEATURE_NAMES = {
"diff": ("hunks", "on_changed_line", "distance"),
"source": ("function", "span", "callers", "entry_points", "language"),
"semantic": ("roles", "def_use", "obligations"),
"taxonomy": ("families",),
}
PROVENANCE_NAMES = ("ok", "reason", "version", "bytes_read")
FEATURE_COLUMNS = tuple(f"feature.{producer}.{name}" for producer, names in FEATURE_NAMES.items() for name in names)
PROVENANCE_COLUMNS = tuple(f"provenance.{producer}.{name}" for producer in FEATURE_NAMES for name in PROVENANCE_NAMES)
def canonical_json(value: object) -> str:
"""Serialize data with stable keys and no ambiguous non-finite numbers."""
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=False, allow_nan=False)
class FeatureTable:
"""Hold flat schema-v1 rows; JSONL starts with a version and mask header."""
schema_version = SCHEMA_VERSION
def __init__(self, rows: Iterable[dict[str, Any]], *, masked: Iterable[str] = ()) -> None:
self.rows = deepcopy(list(rows))
self.masked = tuple(sorted(set(masked)))
self._validate()
def _validate(self) -> None:
allowed = set(KEY_COLUMNS + LABEL_COLUMNS + FEATURE_COLUMNS + PROVENANCE_COLUMNS)
for row in self.rows:
if set(row) - allowed:
raise ValueError("unknown feature table column")
label = row.get("label")
if label is not None and (type(label) is not int or label not in (0, 1)):
raise ValueError("label must be 1, 0 or None")
for column in row:
if column.startswith("feature."):
producer = column.split(".")[1]
if any(f"provenance.{producer}.{name}" not in row for name in PROVENANCE_NAMES):
raise ValueError("feature column is missing producer provenance")
canonical_json(self.rows)
def write_jsonl(self, path: Path | str) -> None:
self._validate()
with Path(path).open("w", encoding="utf-8") as stream:
stream.write(canonical_json({"schema_version": self.schema_version, "masked": self.masked}) + "\n")
for row in self.rows:
stream.write(canonical_json(row) + "\n")
@classmethod
def read_jsonl(cls, path: Path | str) -> FeatureTable:
with Path(path).open(encoding="utf-8") as stream:
header = json.loads(next(stream, "{}"))
if header.get("schema_version") != SCHEMA_VERSION:
raise ValueError("unsupported feature table schema version")
return cls((json.loads(line) for line in stream if line.strip()), masked=header.get("masked", ()))
def to_pandas(self) -> Any:
"""Create a dataframe only when the optional research dependency is installed."""
try:
import pandas
except ImportError as error:
raise RuntimeError("pandas is required; install openultrasast[hunt]") from error
return pandas.DataFrame(deepcopy(self.rows))
def digest(self) -> str:
self._validate()
payload = {"schema_version": self.schema_version, "rows": self.rows}
return hashlib.sha256(canonical_json(payload).encode("utf-8")).hexdigest()
def mask(self, drop: Iterable[str]) -> FeatureTable:
names = set(drop)
unknown = names - set(FEATURE_NAMES) - set(FEATURE_COLUMNS)
if unknown:
raise ValueError("mask names an unknown producer or feature column")
columns = {c for c in FEATURE_COLUMNS if c in names or c.split(".")[1] in names}
return FeatureTable(({k: v for k, v in row.items() if k not in columns} for row in self.rows), masked=(*self.masked, *names))
def feature_columns(self) -> list[str]:
return sorted({column for row in self.rows for column in row if column.startswith("feature.")})
def labelled(self) -> FeatureTable:
return FeatureTable((row for row in self.rows if row.get("label") is not None), masked=self.masked)