feat(classification): add classify_risk utility for multi-run results (#349) - #388
feat(classification): add classify_risk utility for multi-run results (#349)#388lifelmy wants to merge 1 commit into
Conversation
JackYPCOnline
left a comment
There was a problem hiding this comment.
Overall, the purpose and intension of this PR is clear. On the other side, the naming and DEVX remain unclear to me, I would suggest give this more thought and how can we make it more explicit, what apis we want to expose. With said, the purposed in the issue ticket need refinement.
|
Thanks for the review. I agree that Before changing the public API, I propose making the concepts explicit:
I would also revise issue #349 to define the input grouping contract, the handling of |
Summary
Adds a standalone, post-hoc risk classification utility that turns repeated
(case, evaluator)runs into a single stability label, addressing #349.When the same case is evaluated N times, the raw pass/fail counts don't say what kind of
problem a failure is. A case that fails every run is a deterministic bug; one that fails
intermittently is flaky. These need different responses, but today both surface as "some
failures". This adds a pure utility that names the difference.
What's added
src/strands_evals/classification.pyRiskLabel(str, Enum)—BUG/FLAKY/CNE/PASSclassify_risk(results)— classifies one(case, evaluator)pair's repeated runsclassify_task_risk(evaluator_risks)— worst-of rollup across evaluators for one casestrands_evalstests/strands_evals/test_classification.py— 20 unit testsDesign notes (matching the issue and repo conventions)
EvaluationOutput/EvaluationReport/Experiment.Classification is invoked only when a caller already holds multi-run results, exactly as the
issue proposes. Nothing forces multi-run onto existing single-run callers.
statusfield, gradable rows are selected via the shipped
EvaluationOutput.not_applicableproperty(the
NOT_APPLICABLElabel). This is the same "drop non-verdict rows" ruleEvaluationReportalready applies, so a case can't be tipped toward pass/fail by rows thathad nothing to judge.
CNEis returned when there are no gradable rows.BUG > FLAKY > PASS > CNE. A case with one deterministic failure andsome flaky evaluators is a bug — the deterministic signal is the actionable one.
The issue's example sketched a
status-based gradable filter with agetattrfallback; sinceEvaluationOutputalready shipsnot_applicable, this implementation keys off that instead,which is the current source of truth for "nothing to judge" and needs no new field.
Testing
Run in a fresh worktree venv against
origin/main(baseabf7b91):hatch test tests/strands_evals/test_classification.py-> 20 passedhatch test tests/strands_evals/types/ tests/strands_evals/test_classification.py-> 124 passed (no regressions)hatch fmt --formatter --check-> 362 files already formattedhatch fmt --linter-> all checks passedmypy -p src(hatch-static-analysis env) -> Success, no issues in 236 source filesNote on authorship
I use a coding assistant to help implement, and I review and take responsibility for the final change.