pytest-triage

A shadow-mode triage assistant for pytest-dev/pytest issues, measured against what maintainers actually did. It never posts to GitHub.

Labels

11 labels, scored on issues created after 2025-01-01 that maintainers triaged. Anything that costs money must beat the free kNN vote.

Predictormacro-F1micro-F1n
llm:gemini-3.5-flash-lite:v40.580.55237
ensemble gate:0.30.570.54237
ensemble route0.560.52237
llm:gemini-3.5-flash-lite:v3s0.510.51237
llm:gemini-3.5-flash-lite:v20.500.51237
llm:gemini-3.5-flash-lite:v10.470.49237
logreg0.460.42237
knn0.380.38237
keywords0.350.38237
everything0.180.18237
majority0.030.18237

Needs more information

PredictorPRF1
always0.141.000.24
llm:gemini-3.5-flash-lite:v10.380.340.36
llm:gemini-3.5-flash-lite:v20.480.410.44
llm:gemini-3.5-flash-lite:v3s0.480.380.42
llm:gemini-3.5-flash-lite:v40.520.340.42

Duplicates

15 known duplicate pairs (silver labels from maintainer comments) plus non-duplicates to measure false alarms.

MethodFoundFalse alarms95% CI
search: bm25hit@5 5/15-15%-58%
search: densehit@5 4/15-11%-52%
search: hybridhit@5 5/15-15%-58%
LLM verifier: gemini-3.5-flash-lite+expand5/155/3015%-58%
LLM verifier: gemini-3.5-flash-lite+expand+union7/153/3025%-70%
LLM verifier: gemini-3.8-flash+expand5/154/3015%-58%

High-precision mode

Show an LLM label only when the trained classifier also gives it high probability. The threshold was chosen on 2024 issues (lowest one reaching 70% precision) and then applied once to the test set.

SplitConfidenceThresholdPrecision (95% CI)RecallIssues
devllm gated by logreg p0.900.76 (0.65-0.85)0.1924%
devlogreg p alone0.950.78 (0.62-0.88)0.1115%
testllm gated by logreg p0.900.82 (0.69-0.91)0.1418%
testlogreg p alone0.950.89 (0.67-0.97)0.067%

Where it fails

Micro-F1 on the test set by issue shape, with bootstrap 95% intervals. Slices overlap.

Slicenknnllm v4logreg
all2370.38 (0.33-0.42)0.55 (0.50-0.60)0.42 (0.38-0.47)
body 400-2000 chars1370.36 (0.30-0.42)0.56 (0.49-0.62)0.44 (0.38-0.49)
body < 400 chars180.48 (0.28-0.63)0.43 (0.18-0.65)0.27 (0.11-0.41)
body > 2000 chars820.38 (0.30-0.46)0.55 (0.46-0.63)0.43 (0.35-0.50)
has a code block1740.38 (0.33-0.44)0.56 (0.51-0.61)0.44 (0.39-0.49)
has a traceback590.34 (0.23-0.43)0.55 (0.46-0.64)0.40 (0.30-0.50)
maintainers gave no type: label990.20 (0.14-0.26)0.30 (0.23-0.38)0.23 (0.17-0.29)
no code block630.36 (0.27-0.44)0.50 (0.39-0.59)0.37 (0.26-0.47)
no traceback1780.39 (0.34-0.44)0.55 (0.49-0.61)0.43 (0.38-0.48)
title is a question90.27 (0.00-0.50)0.36 (0.00-0.62)0.36 (0.00-0.57)
used the bug template270.44 (0.29-0.62)0.60 (0.44-0.72)0.35 (0.20-0.49)

Prompt injection

Each attack in 6 variants (verbatim, moved, quoted, in a code block, zero-width spaces, look-alike letters). Landed means a maintainer would see the attacker's outcome; fooled the model counts the model's raw output, before the policy layer routes flagged issues to a human.

RunLandedFooled the modelFlagged
pipeline + mutations0/1043/10462/104
pipeline + mutations (before the fixes)1/1042/10434/104

Shadow mode (prospective)

Since 2026-10-14, a daily job triages each new issue within about a day of it opening. 5 predicted so far; maintainers have since triaged 0, 5 remain untriaged. Label macro-F1 on those triaged: 0.00 (small n while the run is young). Median latency 2.97s; total cost $0.0107.

IssueSuggested labelsNeeds info?Possible duplicate of
#15201-
#15200-
#15190type: docs
#15187topic: collection
#15180-

Earlier backtest (predicted after the fact, older pipeline): 37 issues from 2026-09-01 to 2026-10-07, of which 30 were still untriaged by maintainers when scored.