fix(eval): treat missing/null alert trigger as ALWAYS default#1683
Conversation
agent_alert_skill scored trigger_correct=False for "Every time" cases when the
agent omitted the trigger argument. create_metric_alert serialises an unset
trigger as `trigger: null`, so `dict.get("trigger", "ALWAYS")` returned None
instead of the ALWAYS product default. Default a missing OR null trigger to
ALWAYS in both the agentic runner (_check_trigger) and AlertSkillEvaluator, and
add regression tests. A genuinely wrong trigger (e.g. ONCE_PER_INTERVAL when
ONCE is expected) still fails.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR updates trigger-value defaulting logic in the alert skill agentic checker and evaluator so that a missing or explicit ChangesTrigger default handling for alert skill evaluation
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1683 +/- ##
==========================================
+ Coverage 77.80% 77.85% +0.04%
==========================================
Files 271 271
Lines 18602 18603 +1
==========================================
+ Hits 14474 14483 +9
+ Misses 4128 4120 -8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| expected_trigger = _TRIGGER_MAP.get(expected["Trigger"], expected["Trigger"]) | ||
| trigger_correct = args.get("trigger") == expected_trigger | ||
| # Omitted/null trigger persists as the product default ALWAYS ("Every time"). | ||
| actual_trigger = args.get("trigger") or "ALWAYS" |
There was a problem hiding this comment.
| actual_trigger = args.get("trigger") or "ALWAYS" | |
| actual_trigger = args.get("trigger","ALWAYS") |
There was a problem hiding this comment.
Thanks @hkad98! I used or "ALWAYS" deliberately instead of .get("trigger", "ALWAYS"). .get(key, default) only falls back when the key is absent, but gpt-5.2 calls create_metric_alert with "trigger": null — the key is present with a null value (parsed_arguments() is a raw json.loads, no schema merge). So args.get("trigger", "ALWAYS") returns None, and None == "ALWAYS" → trigger_correct=False, i.e. the exact false-negative this PR fixes would come back.
For the real failing args {"trigger": None, ...}:
args.get("trigger", "ALWAYS")→None→ failsargs.get("trigger") or "ALWAYS"→"ALWAYS"→ passes
(The original agentic _check_trigger already used .get("trigger", …default…) and still produced the CI false-negatives for the same reason.) Since no valid trigger value is falsy (ALWAYS/ONCE/ONCE_PER_INTERVAL), or safely covers both the null and absent cases. Happy to make it more explicit if you prefer: raw = args.get("trigger"); actual_trigger = raw if raw is not None else "ALWAYS".
Summary
agent_alert_skillintermittently failed ontrigger_correct=Falsefor "Every time" alert cases whenever the agent created the alert without an explicit trigger.create_metric_alertserialises an unset trigger astrigger: null, soactual_args.get("trigger", "ALWAYS")returnedNone— the intended ALWAYS fallback only applies when the key is absent, not when it is present-but-null. Since the product default for an unset trigger isALWAYS("Every time"), this was a false-negative.Fix: default a missing or null trigger to
ALWAYSin both scoring paths:core/agentic/alert_skill.py::_check_trigger(used by the agentic runner that CI runs)core/evaluators/alert_skill.py::AlertSkillEvaluator(registered evaluator)A genuinely wrong trigger (e.g.
ONCE_PER_INTERVALwhenONCEis expected) still fails — the fix does not mask real model errors.Evidence — replayed the exact
actual_argsfrom failing CI runsmaster)trigger=Nonetrigger=NoneONCE_PER_INTERVALBoth scoring paths (
_check_triggerandAlertSkillEvaluator) agree. The first two rows reproduce the exact CI false-negatives and flip to pass; the third (a real model error) correctly stays failing.Test plan
tests/test_agentic_alert_skill.py—_check_trigger: missing/null trigger → ALWAYS passes; a "One time" expectation still requires an explicitONCE.tests/test_alert_skill_evaluator.py— evaluator defaults missing/null trigger to ALWAYS.pytest packages/gooddata-eval/tests/test_agentic_alert_skill.py packages/gooddata-eval/tests/test_alert_skill_evaluator.py→ 17 passed.Downstream
gdc-nas
tests/tavern-e2e/pinsgooddata-eval[llm-judge]. After this is released, a follow-up bumps the pin + re-locksuv.lockso the fix reaches the nightly agent-evaluation.References
28479836676(2026-06-30), run28902805843(2026-07-07)🤖 Generated with Claude Code
Summary by CodeRabbit