Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions ymir/agents/triage_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,13 +593,39 @@ async def check_cve_eligibility(state):
f"Issue {state.jira_issue} not eligible for triage: {state.cve_eligibility_result.reason}"
)
if state.cve_eligibility_result.error:
state.triage_result = OutputSchema(
resolution=Resolution.ERROR,
data=ErrorData(
details=f"CVE eligibility check error: {state.cve_eligibility_result.error}",
jira_issue=state.jira_issue,
),
)
# Distinguish human-correctable errors from transient/operational failures:
# - Missing Fix Versions field → CLARIFICATION_NEEDED (non-retriable,
# maps to ymir_needs_attention)
# - Clone/dependency check failures → ERROR (retriable,
# maps to ymir_triage_errored)
error_msg = state.cve_eligibility_result.error
is_missing_fix_version = "Fix Versions field is empty" in error_msg

if is_missing_fix_version:
# Non-retriable: requires human intervention (e.g., setting Fix Versions field)
# Use CLARIFICATION_NEEDED to skip retry loop and post comment only once
# Maps to ymir_needs_attention label (issue data incomplete, needs human attention)
state.triage_result = OutputSchema(
resolution=Resolution.CLARIFICATION_NEEDED,
data=ClarificationNeededData(
findings=f"CVE eligibility check error: {error_msg}",
additional_info_needed=(
"Please fix the issue and retry manually (e.g., via ymir_todo label)."
),
jira_issue=state.jira_issue,
),
)
else:
# Retriable: operational/transient errors (network, API failures, etc.)
# Use ERROR resolution to trigger retry logic
# Maps to ymir_triage_errored label after max retries exhausted
state.triage_result = OutputSchema(
resolution=Resolution.ERROR,
data=ErrorData(
details=f"CVE eligibility check error: {error_msg}",
jira_issue=state.jira_issue,
),
)
elif dup_key:
state.triage_result = OutputSchema(
resolution=Resolution.OPEN_ENDED_ANALYSIS,
Expand Down
4 changes: 2 additions & 2 deletions ymir/tools/privileged/jira.py
Original file line number Diff line number Diff line change
Expand Up @@ -808,8 +808,8 @@ async def _run(
CVEEligibilityResult(
is_cve=True,
eligibility=TriageEligibility.NEVER,
reason="CVE has no target release specified",
error="CVE has no target release specified",
reason="CVE has no target release specified (Fix Versions field is empty)",
error="CVE has no target release specified (Fix Versions field is empty)",
).model_dump()
)

Expand Down
3 changes: 3 additions & 0 deletions ymir/tools/privileged/tests/unit/test_jira.py
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,9 @@ async def test_eligibility_no_fix_version():
result = (await CheckCveTriageEligibilityTool().run(input={"issue_key": "RHEL-12345"})).result
assert result["eligibility"] == TriageEligibility.NEVER
assert result["error"] is not None
# Verify the clarified error message that specifies which Jira field is missing
assert "Fix Versions field is empty" in result["error"]
assert "Fix Versions field is empty" in result["reason"]


@pytest.mark.asyncio
Expand Down
Loading