mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
feat(learn): candidate feature schema and builders (decision-engine task 1)
learn/schema.py is the closed, typed allow-list of candidate features: 66 features over 11 instruments (language one-hot, quick rules with 23 mechanism buckets and a prior count, engine, repo-facts, source span, entry-point distance, roles, delta, verify, agree, model sinks), two profiles (static 57; plane adds verify, agree and model sinks for 66), schema_version and a feature-set digest. No repository, path, file, function, rule or commit identity is a feature; site_match, in_fix_range, fixed-pin alerts, case.json fields and costs are refused. Missing is not zero: each record carries per-instrument state (ran | none | failed | not_applicable), and every feature of an instrument that did not run is null. learn/features.py builds records on the host (build_for_scan, whole repository or base..head delta); plane/tasks/features.py builds them per case in a Run from the delivered artifacts, dropping site_match and in_fix_range on read and ignoring fixed-pin alerts. The generator adds a model-free `features` entry per case before `remember`, which stores the records as `features` rows (re-validated). memory KINDS gains features, label, decision, experiment, arm_outcome and experiment_result. The committed validation-46 manifests are regenerated (entries appended; the first Run's entries are unchanged). The runner image must be rebuilt and re-pinned before a Run executes the new task. Proof on real artifacts (scratch store, not committed): the recorded validation-46 run gives 75 feature records over 15 cases (43 verify candidates plus vulnerable-pin alerts), each case's vulnerable pin exported and read (0.5k-9k files); remember stored 75 features rows beside 43 verdict, 84 alert, 61 unit_cost, 15 facts and 8 coverage rows. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
edcf145b00
commit
d1896cb8e7
@@ -56,7 +56,8 @@ def test_model_prices_are_the_endpoint_prices() -> None:
|
||||
|
||||
def test_validation_run_resolves_and_renders_every_task(tmp_path: Path) -> None:
|
||||
run, manifests = reconciler.load_run(RUN)
|
||||
assert len(run.tasks) == 105 # per case: facts, va, vb, agree, then vc, final, then remember (harnessx-removal task 4)
|
||||
# per case: facts, va, vb, agree, then vc, final, then features (learned-decision-engine task 1) and remember
|
||||
assert len(run.tasks) == 120
|
||||
population = {c["id"]: c for c in tomllib.loads(POPULATION.read_text())["case"]}
|
||||
ax_names: set[str] = set()
|
||||
for task in manifests.tasks.values():
|
||||
@@ -96,7 +97,9 @@ def test_tiebreak_appends_thirty_tasks_and_keeps_the_first_sixty_byte_identical(
|
||||
first = text.split(" - name: budibase-mongo-template-nosqli-vc\n", 1)[0]
|
||||
assert hashlib.sha256(first.encode()).hexdigest() == FIRST_RUN_ENTRIES
|
||||
run, manifests = reconciler.load_run(RUN)
|
||||
old, new, remembered = run.tasks[:60], run.tasks[60:90], run.tasks[90:]
|
||||
old, new, appended = run.tasks[:60], run.tasks[60:90], run.tasks[90:]
|
||||
assert [e.name.rsplit("-", 1)[1] for e in appended] == ["features", "remember"] * 15
|
||||
remembered = appended[1::2]
|
||||
assert [e.name.rsplit("-", 1)[1] for e in old] == ["facts", "va", "vb", "agree"] * 15
|
||||
assert [e.name.rsplit("-", 1)[1] for e in new] == ["vc", "final"] * 15
|
||||
for vc, final in zip(new[::2], new[1::2], strict=True):
|
||||
@@ -112,9 +115,15 @@ def test_tiebreak_appends_thirty_tasks_and_keeps_the_first_sixty_byte_identical(
|
||||
for entry in (vc, final):
|
||||
name = reconciler._ax_name(run.metadata.name, entry.name, limit=reconciler.TASK_NAME_LIMIT)
|
||||
assert len(name) <= reconciler.TASK_NAME_LIMIT
|
||||
for entry in appended[::2]: # learned-decision-engine task 1: model-free, the chain's artifacts in, records out
|
||||
case = entry.name.removesuffix("-features")
|
||||
assert entry.inputs["agreed"] == f"{case}-final/agreed.json" and entry.outputs == ("features.jsonl", "summary.json")
|
||||
assert entry.budget is not None and (entry.budget.usd, entry.budget.calls) == (0, 0)
|
||||
assert reconciler.MODEL_ANNOTATION not in manifests.tasks[entry.task].metadata.annotations
|
||||
for entry in remembered: # harnessx-removal task 4: appended after the tie-break, model-free
|
||||
case = entry.name.removesuffix("-remember")
|
||||
assert entry.inputs["agreed"] == f"{case}-final/agreed.json" and entry.inputs["pass_c"] == f"{case}-vc/units.jsonl"
|
||||
assert entry.inputs["features"] == f"{case}-features/features.jsonl"
|
||||
assert entry.budget is not None and (entry.budget.usd, entry.budget.calls) == (0, 0)
|
||||
assert reconciler.MODEL_ANNOTATION not in manifests.tasks[entry.task].metadata.annotations
|
||||
assert len(reconciler._ax_name(run.metadata.name, entry.name, limit=reconciler.TASK_NAME_LIMIT)) <= reconciler.TASK_NAME_LIMIT
|
||||
|
||||
Reference in New Issue
Block a user