mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-18 12:39:28 +00:00
fix(learning-harness): the round-3 review findings, remediated RED-first
Eight of nine group-3 tasks were rejected. Each defect was hiding a number, and the numbers are why the loop was not learning: - The fixed side was judged against the *vulnerable* side's function ranges. 191 of 227 pairs with a resolvable labeled span (84%) have different spans on the two sides, so a leak was recorded as silence, always in the direction that flatters Youden. - Round zero measured every family with the generalist. `family:unknown` earns no credit against any real family, so every family but `unknown` baselined at a structural zero and every noise floor with it. - The cross-family sweep counted absolute failures instead of negative flips. On a corpus where most pairs fail at round zero that rejects every round for damage it did not do. Unscorable rows voted too. - K runs was declared and never threaded; `pairs --k-runs` was parsed and discarded, and its only test grepped `--help`. - The meta-agent proposer was a stub, so `learning round` could never propose anything. It now composes MetaAgent.evolve against a scratch copy of the family directory, and `--proposals FILE` runs a recorded sequence offline. - `refused_holdout` was a vocabulary word no code path could produce, and the covering test accepted either outcome. - Cost was metered once, after everything had been paid for; a stage that raised left no record at all. - The corrected lever number was published beside the earlier one rather than in place of it, and the test named for that property never checked. - Refusals were `continue` statements: `Refusal.degradation()` existed and nothing called it. A train-split identical twin was reported as `split:train`, which is untrue. Test repairs that each changed a number: two split tests measured an `x = 1` fixture that teaches nothing whatever the rule says; two CLI scoreboard tests asserted against all-zero output produced by a stub that answers twice and puts its finding outside the labeled function. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
co-authored by
Claude Opus 5
parent
c2d9c4ad01
commit
1843ef9a02
@@ -99,11 +99,14 @@ def evaluate_loo(cases: Sequence[PairCase], *, facts: SemanticFacts | None = Non
|
||||
skipped.append((case.name, "pointer_pair_not_cached" if not case.vendored else "excerpt_missing"))
|
||||
else:
|
||||
targets.append(case)
|
||||
from ..learning.split import is_teacher
|
||||
from ..learning.split import is_teacher, refuse_if_holdout
|
||||
|
||||
# learning-harness Req 5.1: every pair is still scored, but only a train-split teacher may seed a store.
|
||||
lessons = {case.name: pair_lessons(case, loaded) for case in targets if is_teacher(case)}
|
||||
outcomes = [_hold_out(case, targets, lessons, loaded) for case in targets]
|
||||
# Req 5.2: the pairs that were kept out of the teaching set are named, not silently dropped.
|
||||
refusal = refuse_if_holdout([case.name for case in targets if case.name not in lessons], targets)
|
||||
refusals = (refusal.degradation(),) if refusal is not None else ()
|
||||
return LooResult(
|
||||
outcomes=tuple(outcomes),
|
||||
per_slice=_group(outcomes, lambda item: (item.slice,)),
|
||||
@@ -112,7 +115,7 @@ def evaluate_loo(cases: Sequence[PairCase], *, facts: SemanticFacts | None = Non
|
||||
per_obligation_kind=_group(outcomes, lambda item: item.obligations),
|
||||
skipped=tuple(skipped),
|
||||
teaching_pairs=sum(1 for shapes in lessons.values() if shapes),
|
||||
degradations=_unique_degradations(outcomes),
|
||||
degradations=(*refusals, *_unique_degradations(outcomes)),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -196,7 +196,9 @@ def _skip_reason(case: PairCase) -> str | None:
|
||||
from ..learning.split import is_teacher
|
||||
|
||||
if not is_teacher(case) and case.review_tier in GATING_TIERS and case.vendored and not case.known_limit:
|
||||
return f"split:{case.split}" # learning-harness Req 5.1: only train-split, scorable pairs teach
|
||||
# learning-harness Req 5.1: only train-split, scorable pairs teach. Say which of the two it was: two
|
||||
# vibe-py rows are train-split identical twins, and calling them `split:train` is simply untrue.
|
||||
return f"unscorable:{case.unscorable}" if case.unscorable else f"split:{case.split}"
|
||||
if case.review_tier not in GATING_TIERS:
|
||||
return f"tier:{case.review_tier}"
|
||||
if case.known_limit:
|
||||
|
||||
Reference in New Issue
Block a user