AI Accuracy Evaluation¶
MethodAtlas constrains the AI to a closed, versioned taxonomy, so every answer is well-formed. That does not make it correct. -eval-accuracy measures correctness: it scores the AI's classifications against a set of human-reviewed labels and reports precision, recall, F1 and support.
The command is offline and deterministic. It reads two files and calls no AI provider.
Ground truth: the override file¶
The recommended ground-truth source is the same YAML you already maintain for classification overrides. Each entry is a decision a human has reviewed, so it is already a vetted label — there is no separate labelling format to learn or keep in sync.
| Override entry | Label it provides |
|---|---|
securityRelevant: true / false |
the relevance label |
tags: [...] |
the tag label |
securityRelevant: false without tags |
relevance and "no security tag applies" |
securityRelevant: true without tags |
relevance only; tags are not scored for that method |
only note, reason, displayName |
not a label; ignored |
Resolution follows the override rules: a method-level entry wins over a class-level entry for the same class, and the last duplicate wins. Tag names are trimmed and lower-cased before comparison.
Predictions must be genuine AI output
Produce the predictions CSV without -override-file. Overrides replace the AI values, so scoring a scan that had them applied compares the human labels with themselves and reports a meaningless 100 %.
Workflow¶
# 1. Scan with AI, no overrides applied.
methodatlas -ai -ai-provider ollama src/test/java > predictions.csv
# 2. Score the predictions against the reviewed labels.
methodatlas -eval-accuracy overrides.yaml predictions.csv
| Argument | Meaning | Default |
|---|---|---|
-eval-accuracy <labels.yaml> <predictions.csv> |
Run the evaluation and exit. All other scan flags are ignored | — |
-eval-format markdown\|json |
Report format | markdown |
-eval-min-f1 <0..1> |
Exit 1 when the securityRelevant F1 or the micro-averaged tag F1 is below the threshold, or when neither can be computed. The macro-average is reported but is not what the gate uses |
no gate |
Metrics¶
Two decisions are evaluated, each only over the methods whose label decides it.
securityRelevant is a binary decision, reported as a confusion matrix where positive means security-relevant.
| Truth: relevant | Truth: not relevant | |
|---|---|---|
| Predicted: relevant | TP | FP |
| Predicted: not relevant | FN | TN |
Taxonomy tags are a multi-label decision, scored one-vs-rest for every tag: a tag is a TP when predicted and labelled, an FP when predicted only, an FN when labelled only. The report adds a micro-average (counts summed over tags) and a macro-average F1: the unweighted mean of the per-tag F1 over every tag that appears in any prediction or any label (the scikit-learn convention). A tag the AI invented has zero support and F1 0, so hallucinated tags lower the macro average instead of being silently dropped.
| Metric | Definition |
|---|---|
| Precision | TP / (TP + FP) |
| Recall | TP / (TP + FN) |
| F1 | 2·TP / (2·TP + FP + FN) |
| Accuracy (relevance only) | (TP + TN) / total |
| Support | TP + FN — the number of labelled positives |
A metric whose denominator is zero is undefined and is shown as n/a (JSON null), never as 0 or 1: "no evidence" must not read as "perfect" or "terrible". A tag the AI predicted but no label contains has zero support and an undefined recall (its F1 is 0 and it counts in the macro average).
Coverage counters¶
Missing and extra entries never fail the run. They are counted so you can judge how representative the numbers are:
| Counter | Meaning |
|---|---|
| Prediction rows read | rows in the predictions CSV |
| Evaluated | methods that were both labelled and predicted |
| Predictions without a label | AI predictions with no usable label (not scored) |
| Labelled methods without an AI prediction | the row has no ai_security_relevant value, for example the scan ran without -ai |
| Label entries matching no scanned method | stale entries after a rename or deletion, or a different scan scope |
Try it¶
A tiny demonstrator ships in docs/examples/accuracy/:
methodatlas -eval-accuracy docs/examples/accuracy/labels.yaml docs/examples/accuracy/predictions.csv
It scores seven predicted methods against six labels (one of them stale): the relevance matrix is TP 3, FP 1, FN 1, TN 1 (F1 0.7500), and the tag micro-average F1 is 0.6250 (macro-average 0.4167: the two invented tags logging and input-validation count as F1 0). The same files back the automated tests, so the numbers above are asserted in CI.
Output determinism¶
The report has no timestamp, path or host field. Lines end with \n on every operating system, numbers use four decimals with a . separator regardless of the JVM locale, and tags are sorted. Two runs over the same inputs are byte-identical on Linux, Windows and macOS, so a report can be committed or hashed into an evidence pack.
JSON reports carry "schemaVersion": 1; field renames or retyping will bump it.
What the numbers mean — and what they do not¶
Ongoing accuracy requires a maintained labelled set
The command is a measuring instrument; the figure it reports is only as good as the labels behind it. A one-off run on a handful of methods says little. To track accuracy over time, keep a labelled set that is large enough to give every tag meaningful support, representative of the code you scan, and re-scored whenever the model, the prompt templates or the taxonomy change (the reproducibility receipt records the inputs that influenced a scan).
Choosing the acceptable precision and recall — and therefore the -eval-min-f1 value for CI — is a risk-owner decision. MethodAtlas ships no default target.
The bias of an override-derived label set can run in both directions. Reviewed methods are often the ones the AI got wrong, so overrides over-represent errors and understate accuracy. But a reviewer who accepts AI suggestions in bulk (for example a GUI session that saves every suggestion unchanged) produces labels that merely echo the AI, which overstates accuracy. Where an unbiased estimate matters, add labels for a random sample of methods the reviewer agreed with, recorded as override entries that restate the decision, and label a random sample of methods the AI was never asked to flag.
A GUI-generated overrides.yaml is not an independent label set
The GUI writes .methodatlas/overrides.yaml from the reviewer's saved decisions, which start from the AI suggestion. Unless the reviewer authored or consciously confirmed each entry, scoring the AI against that file measures agreement with itself, not correctness. Use it as ground truth only when the entries were independently authored by the reviewer.
See also¶
- Classification Overrides — the label format
- Security Taxonomy — the closed tag set being scored
- Confidence Scoring