Files
Open_Ultra_SAST/.kiro/specs/hunter-learning-loop/requirements.md
T
Marius CiepluchandClaude Fable 5.1 3b8327ee51 spec(hunter-learning-loop): requirements
The hunter gets an annotation model (named, versioned facts about the push)
and statistical ablation decides which annotations stay. Labels from fix
sites and ordinary pushes, training set apart from the held-out pilot,
compiled replayable program, train-and-holdout acceptance rule, two stages
reported separately, no thresholds set in this spec.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-13 08:47:51 +02:00

19 KiB

Requirements Document

Project Description (Input)

Maintainer, 2026-10-13: "the hunter would then need a dspy process now, so that we iteratively refine our llm integration. we can distinct positives from false positives. and dspy can mutate prompts with its statistical tools. the key is to produce enough information for the llm to use it correctly." Then: "threshold based assessments come later. right now the search is too bad. if I cut a threshold at 50:50 that is coinflip optimization. what we need rather than that is an annotate model for the llm, with statistical ablation." And: "the answer to our problem is feature engineering + math." Before that: "proof should be a resort to face with certainty. before our search problem needs to be solved to reduce what we have to proof."

Who has the problem: the pre-push safety net. The valid benchmark pilot (benchmarks/measurements/2026-10-12-valid-benchmark-pilot/NOTES.md) measured the LLM tool hunter at 5 of 12 verified positives found and 54 false alarms per 100 ordinary pushes after the decision-engine classifier. The hook as shipped found 0 of 12.

Current situation: the hunter's search prompt is a hand-written string, its family answer is free text, and it never sees the diff. Of 343 ordinary-push suspicions the classifier called vulnerable, 250 sit more than 10 lines from any changed line: the hunter re-reports the repo's old code on every push. Every precision gain so far was a hand rule or a threshold picked after looking at the misses, in-sample. A threshold on today's output is a coin flip dressed as a decision. The learning harness that compiles the decision-engine classifier (bootstrapped demonstrations, instruction proposals, grouped folds, a leak audit, paired A/B experiments with cluster bootstrap, a cached and replayable model caller) exists, but the hunter does not run on it, and the compile step accepts the best score on one validation split with no train-against-holdout check, no per-family regression check, and no prompt length cap.

What should change: the search gets better before anything is thresholded. The hunter receives an annotation model: a named, versioned set of facts about the push computed from the repository (changed hunks with line numbers, the enclosing function and its callers, entry-point evidence, source, sink and sanitizer roles, framework facts, def-use inside the function, guards and obligations, closed taxonomy families with the classifier's answer format). Which facts the model needs is decided by statistical ablation: each annotation is switched on and off in pre-registered, paired experiments over the same changes, and its effect on search recall over fix sites and on suspicions per ordinary push is reported per family with intervals. An annotation or a prompt change is kept only when it helps on held-out folds. Labels come from the benchmark's rule: a suspicion is a true positive when it lands on a verified fix site, a false positive when it sits on an ordinary push. Training data is sourced separately (about 100 advisories through the fix-site catalog and verifier, about 40 accepted positives) with repository-level folds and the leak audit; the 252-change pilot stays held out and is only used to report the gain. Thresholds and operating points come after the search is good; this spec reports the whole recall against false-alarm curve and sets none. The proof arm runs only on what survives.

Introduction

This spec turns the LLM hunter from a hand-written prompt into a measured search stage. It owns four things: the labelled data the loop learns from, the annotation model the hunter is given about a push, the ablation method that decides which annotations stay, and the rule by which a changed prompt or annotation set is kept or thrown away. It reports in the benchmark's own terms: recall, false alarms per 100 pushes, precision, per family, with intervals. It sets no threshold.

Boundary Context

  • In scope: labelling hunter suspicions from fix-site positives and ordinary pushes; sourcing a training set separate from the held-out pilot; the annotation model and its producers; statistical ablation of annotations; the hunter as a versioned, replayable compiled program; the acceptance rule for a prompt, demonstration or annotation-set change; re-measuring the pilot and reporting the gain.
  • Out of scope: choosing confidence or scope thresholds and operating points (later, once the search is measured good); wiring the compiled hunter into the pre-push hook (pre-push-safety-net); the proof arm itself (search-with-proof, proof-arm-opencode); building new deterministic analyses such as a whole-repo call graph or taint engine (engine-change-scoped-analysis owns those; this spec consumes what exists); growing the benchmark beyond what this loop needs (valid-detection-benchmark).
  • Adjacent expectations: the fix-site catalog and verifier produce the labels; the benchmark scorer and metrics are the only scorekeepers; the decision-engine classifier stays as the second stage and is not retrained here; the earlier freeze on hunter changes ("no hunter prompt, tool or configuration may change before that measurement") is lifted by the pilot measurement, which is the baseline.

Requirements

Requirement 1: Labels from fix sites and ordinary pushes

Objective: As the maintainer, I want every hunter suspicion labelled true or false by the benchmark's own rule, so that the loop learns from facts and not from my reading of the misses.

Acceptance Criteria

  1. When a hunter suspicion names a path and line inside a verified fix-site function of a positive change, or within the benchmark scorer's location tolerance of it, and its family equals the change's family, the Learning Loop shall label it a true positive.
  2. When a hunter suspicion is raised on an ordinary push, the Learning Loop shall label it a false positive.
  3. When a hunter suspicion is raised on a positive change but outside every verified fix site of that change, the Learning Loop shall label it unknown and shall exclude it from training and scoring.
  4. The Learning Loop shall label at the level of the suspicion (path, line, family), and shall also derive the push-level outcome (caught, alarmed) with the benchmark scorer, so that both the search stage and the push-level metric are measurable from the same records.
  5. When a positive change is used for training, the Learning Loop shall record its fix-site verification record (model checks and human decision) next to the label, so that a label can be traced to its evidence.
  6. If a label's source cannot be traced to a verified fix site or a frozen ordinary draw, the Learning Loop shall reject it.

Requirement 2: A training set apart from the held-out pilot

Objective: As the maintainer, I want the loop to learn on data the benchmark never reports on, so that the pilot number stays a measurement.

Acceptance Criteria

  1. The Learning Loop shall source its training positives through the fix-site catalog and verifier from advisories and repositories that are not in the held-out pilot, and shall record the sourcing run.
  2. The Learning Loop shall draw its training negatives as ordinary pushes from the training repositories only, at the benchmark's ratio of at least 20 ordinary pushes per positive change.
  3. The training set shall contain at least 40 accepted positive changes across at least two languages before the first ablation result is reported; a run on fewer is marked a dry run.
  4. While an ablation, compile or evaluation runs, the Learning Loop shall never read the held-out pilot's changes, labels or records, and every artifact shall record which data digests it did read.
  5. The Learning Loop shall split the training set by repository group into folds, so that no repository appears on both sides of a split.
  6. Before the first ablation, the Learning Loop shall run the leak audit over every annotation and shall report any annotation that separates positives from negatives on its own above the audit's threshold, so that an annotation that encodes the label is found before it is credited.
  7. If a training repository is later found in the held-out pilot or in any benchmark report, the Learning Loop shall mark every run that used it as contaminated and shall exclude those runs from any reported gain.

Requirement 3: The annotation model

Objective: As the maintainer, I want the facts the hunter sees about a push to be a named, versioned set that each can be switched on or off, so that "enough information for the model" is something we can measure rather than guess.

Acceptance Criteria

  1. The Learning Loop shall define the annotation model as a versioned schema of named annotations, each with a producer, a bound on its size, and a digest, and shall record the schema version on every hunter run.
  2. The Learning Loop shall compute every annotation from the repository at the push's revisions and from the tool's own framework knowledge only; no annotation shall read a label, an advisory, a CVE or GHSA identifier, a fix commit, or security-worded commit text.
  3. The annotation model shall include at least: the changed hunks with head-side line numbers; the enclosing function's full text at head; the names and locations of that function's callers; entry-point evidence (an in-repo route, handler, command or public API that reaches the function); source, sink and sanitizer roles for the identifiers in the function; the framework facts that apply to the file; def-use evidence inside the function; the guards and obligations on the changed path; and the closed list of taxonomy families with a one-line definition each.
  4. When an annotation's producer cannot compute it for a push, the Learning Loop shall record the annotation as absent with the reason, and shall not substitute a default that could be read as a fact.
  5. The Learning Loop shall render the enabled annotations into the hunter's input in a fixed order with fixed labels, so that two runs with the same annotation set and the same push produce the same input.
  6. The Learning Loop shall require the hunter's family answer to come from the closed list; an answer outside the list is recorded as unknown and counts against the program.
  7. The Learning Loop shall require the hunter's answer in the same fixed structure the classifier uses (verdict, family, confidence, rationale, cited lines), and shall reject an answer whose cited lines fall outside the text it was shown.
  8. When the hunter reports a suspicion, the Learning Loop shall record whether it lies on a changed line, within 10 lines of one, or farther away, so that scope is a measured property of every suspicion and not a filter.

Requirement 4: Statistical ablation decides what the model needs

Objective: As the maintainer, I want each annotation's worth measured by switching it off, so that the input the hunter gets is built from effects with intervals, not from intuition.

Acceptance Criteria

  1. Before an ablation runs, the Learning Loop shall register it: the annotation set under test, the annotations switched off, the folds, the metric, the sample size, the budget and the decision rule.
  2. The Learning Loop shall run every ablation arm over the same changes as its comparison arm, paired by change, with the same program, model and sampling, so that the only difference between arms is the annotation set.
  3. For each ablation, the Learning Loop shall report the paired effect on search recall over fix sites and on suspicions per ordinary push, per family and pooled, with a 95% interval from a bootstrap clustered by repository and a paired test on the per-change outcomes.
  4. The Learning Loop shall report, after a full ablation round, an importance table: for every annotation, its effect on recall and on suspicions per ordinary push when removed from the full set and when added to the baseline, with intervals and sample counts.
  5. The Learning Loop shall keep an annotation in the hunter's input only when its removal lowers search recall or raises suspicions per ordinary push on held-out folds with an interval that excludes zero, or when its removal has no measurable effect and it is needed by an annotation that does.
  6. If an annotation raises suspicions per ordinary push without raising recall, the Learning Loop shall drop it and shall record the result where the next round can see it.
  7. The Learning Loop shall not use a confidence cut, a scope cut or any other threshold on the hunter's output as the quantity being optimised; confidence is reported, not tuned, in this spec.
  8. The Learning Loop shall report the full recall against suspicions-per-push curve of each annotation set, so that a later operating-point decision has the whole curve and not one point of it.

Requirement 5: The hunter as a compiled, replayable program

Objective: As the maintainer, I want every version of the hunter's prompt, demonstrations and annotation set to be an artifact I can name, diff, replay and roll back, so that an improvement is a fact and not a memory.

Acceptance Criteria

  1. The Learning Loop shall store each compiled hunter as a single content-addressed artifact holding the instruction, the demonstrations, the annotation schema version and enabled set, the model, the data digests, every scored configuration and the spend.
  2. When the hunter runs, the Learning Loop shall record the program id and the annotation set on every suspicion it emits.
  3. The Learning Loop shall route every hunter model call through a cached, metered caller, so that a rerun of the same program on the same inputs reproduces the same answers at no cost.
  4. The Learning Loop shall keep the scorer, the labels and the held-out data outside every surface the compile step may edit, so that a proposal cannot read its own answer key.
  5. If a run exhausts its budget before finishing, the Learning Loop shall write no program artifact and shall report the run as unfinished with the spend so far.
  6. The Learning Loop shall cap the instruction length per family, and shall reject a proposal that exceeds the cap regardless of its score.

Requirement 6: Accepting or rejecting a change

Objective: As the maintainer, I want a prompt, demonstration or annotation-set change kept only when it helps on data it was not tuned on, so that the loop cannot overfit its way to a better number.

Acceptance Criteria

  1. When a candidate program is scored, the Learning Loop shall score it on the compile folds and on the held-out folds separately, per family, and shall report both.
  2. The Learning Loop shall accept a candidate only when its compile-fold and held-out-fold results are both non-negative against the current program and at least one is strictly positive.
  3. If any family's held-out result falls below its regression budget, the Learning Loop shall reject the candidate, whatever the aggregate shows.
  4. If a candidate ties the current program within the pre-registered tolerance, the Learning Loop shall reject it.
  5. The Learning Loop shall report every result with its sample count and a 95% interval, and shall not accept a candidate on a point estimate alone.
  6. The Learning Loop shall keep rejected candidates and their scores where the next proposal round can see them, and shall never show the held-out results to the proposer.
  7. When a candidate is accepted, the Learning Loop shall record the comparison (both programs' ids, both fold results, the decision rule) in the new program's artifact.
  8. The Learning Loop shall change one thing per round (one annotation, or one instruction, or one demonstration set), so that an accepted gain is attributable.

Requirement 7: Two stages, reported for what each owns

Objective: As the maintainer, I want the search stage and the classifier stage measured separately, so that we fix the search problem before paying for proof.

Acceptance Criteria

  1. The Learning Loop shall report the search stage on recall over verified fix sites (did a suspicion land on the fix site with the right family) and on suspicions per ordinary push, per family.
  2. The Learning Loop shall report the classifier stage on precision over the suspicions the search stage emitted, and on the push-level false alarms per 100 ordinary pushes after it, per family.
  3. The Learning Loop shall report the combined push-level result as recall, false alarms per 100 pushes and precision with 95% intervals, in the benchmark's names and no coined ones.
  4. The Learning Loop shall report the gate distance on every run: the recall reached at 10 false alarms per 100 pushes and the false alarms at 90% recall, read off the curve, as a report and not as a tuned operating point.
  5. The Learning Loop shall not retrain or recompile the classifier stage within this spec; a classifier change is a separate experiment.

Requirement 8: Measuring the gain on the pilot

Objective: As the maintainer, I want one number that says what the loop bought, measured on the data it never saw, so that the decision to put the hunter on pre-push rests on evidence.

Acceptance Criteria

  1. When a compiled hunter is accepted, the Learning Loop shall run it once over the held-out pilot's 252 changes with the same scorer and metrics as the pilot, and shall write the result next to the pilot's measurement.
  2. The Learning Loop shall report the gain as the before-and-after of search recall, suspicions per ordinary push, push-level recall, false alarms per 100 pushes and precision, per family, with intervals, against the pilot's recorded hunter numbers.
  3. The Learning Loop shall report, for the same run, the number of suspicions the proof arm would have to handle per 100 pushes, so that proof's workload is a measured count.
  4. The Learning Loop shall prove its instrument in every pilot run: for each change it shall record bytes read per changed file and the verified base and head, and shall mark a change with nothing readable as an instrument failure rather than a clean result.
  5. If a pilot run's instrument failures exceed 5% of changes, the Learning Loop shall report the run as invalid and shall not quote its numbers.
  6. The Learning Loop shall run the pilot at most once per accepted program, and shall record each run, so that the pilot is not used as a tuning surface.

Requirement 9: Cost, secrets and unattended runs

Objective: As the operator, I want ablation and compile runs to stay inside a budget, keep the model key out of every record, and finish without me, so that the loop can run overnight on the research host.

Acceptance Criteria

  1. The Learning Loop shall take a pre-registered budget in money and calls per run and shall stop at the first exceeded bound.
  2. The Learning Loop shall never write a model key, or an exception message that could carry one, into a record, a log or an artifact; an error is recorded by its type.
  3. When a run is interrupted, the Learning Loop shall resume from its recorded progress without repeating finished model calls.
  4. The Learning Loop shall write its outputs outside the repository checkout and shall keep each record once, so that an overnight run cannot fill the host's disk with duplicates.
  5. The Learning Loop shall report, at the end of every run, the spend, the calls, the replay hits and the wall time.