Skip to content

Fix: Include all terminal labels when checking sibling completion status - #785

Merged
majamassarini merged 7 commits into
packit:mainfrom
majamassarini:fix-sibling-consolidation-terminal-labels
Aug 31, 2026
Merged

Fix: Include all terminal labels when checking sibling completion status#785
majamassarini merged 7 commits into
packit:mainfrom
majamassarini:fix-sibling-consolidation-terminal-labels

Conversation

@majamassarini

@majamassarini majamassarini commented Aug 26, 2026

Copy link
Copy Markdown
Member

Problem

Primary issues stuck waiting for siblings that finished with ymir_backported, ymir_backport_errored, etc. These weren't recognized as terminal states.

Example: RHEL-248139 - all 7 siblings finished but primary remained stuck with ymir_rebase_waiting_for_siblings.

Root Causes Fixed

Missing terminal labels - Only checked ymir_triaged_*, not completion/error labels

Fixes: https://redhat.atlassian.net/browse/RHEL-248139

@qodo-for-packit

Copy link
Copy Markdown

PR Summary by Qodo

Recognize all terminal labels during sibling consolidation

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Treat completion, error, and failure labels as terminal during sibling consolidation.
• Prevent completed siblings from blocking primaries or being queued for triage again.
• Document the full terminal-label contract with a regression test.
Diagram

graph TD
  A["Sibling candidate"] --> B{"Terminal label?"}
  B -->|Yes| C["Skip triage"]
  B -->|No| D["Queue triage"] --> E["Completion check"] --> F{"Pending siblings?"}
  C --> E
  F -->|Yes| G["Keep waiting"]
  F -->|No| H["Queue primary"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize terminal labels
  • ➕ Prevents the two workflows from drifting apart
  • ➕ Allows tests to validate the exact production label set
  • ➕ Simplifies future terminal-state additions
  • ➖ Requires a small shared API or constant
  • ➖ Broadens the patch beyond the minimal fix

Recommendation: The current change is a low-risk hotfix and correctly addresses both affected workflows. As a follow-up, centralize the terminal-label set and add behavioral tests around queue suppression and pending-sibling JQL; the added test currently verifies enum membership rather than proving either production list uses every expected label.

Files changed (2) +69 / -0

Bug fix (1) +21 / -0
rebase_consolidation.pyRecognize completion, error, and failure labels as terminal +21/-0

Recognize completion, error, and failure labels as terminal

• Extends sibling queue filtering to avoid re-triaging issues whose work has completed, errored, or failed. The pending-sibling JQL now excludes the same terminal states so primaries can proceed once no active sibling remains.

ymir/agents/rebase_consolidation.py

Tests (1) +48 / -0
test_rebase_consolidation.pyDocument the complete sibling terminal-label contract +48/-0

Document the complete sibling terminal-label contract

• Adds a regression-oriented test enumerating triage, completion, error, and failure labels and verifies that each value exists in the Jira label enum. The test records the RHEL-248139 scenario, though it does not directly exercise the production filters.

ymir/agents/tests/unit/test_rebase_consolidation.py

@qodo-for-packit

qodo-for-packit Bot commented Aug 26, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Terminal outcomes get requeued ✓ Resolved 🐞 Bug ≡ Correctness ⭐ New
Description
The expanded triage-decision exclusions omit JiraLabels.TRIAGED and JiraLabels.NEEDS_ATTENTION,
which are terminal outputs of open-ended analysis and clarification-needed triage. Such issues can
remain New/Planning, pass both the JQL and defensive terminal checks, and be relabeled and queued
for triage again by a later primary.
Code

ymir/agents/rebase_consolidation.py[99]

+            # Triage decisions (non-retriable - sibling has been triaged and decided)
Relevance

●●● Strong

Accepted precedent treats omitted terminal triage labels causing requeue/dedup errors as actionable
correctness bugs.

PR-#540

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The triage resolution map proves both omitted labels are written as terminal outcomes, while sibling
completion removes the queue/in-progress markers. The candidate query only limits workflow status to
New/Planning, and the queueing path then accepts any candidate not present in the incomplete
terminal set.

ymir/agents/triage_agent.py[116-125]
ymir/agents/triage_agent.py[1493-1514]
ymir/agents/rebase_consolidation.py[51-64]
ymir/agents/rebase_consolidation.py[217-250]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The terminal-label enumeration omits `JiraLabels.TRIAGED` and `JiraLabels.NEEDS_ATTENTION`, allowing completed open-ended-analysis and clarification-needed issues to be selected and queued again as siblings.

## Issue Context
`triage_agent.py` maps `OPEN_ENDED_ANALYSIS` to `TRIAGED` and `CLARIFICATION_NEEDED` to `NEEDS_ATTENTION`. Add both labels consistently to the server-side JQL exclusions and the defensive terminal-label set, and extend the regression tests.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[99-113]
- ymir/agents/rebase_consolidation.py[221-235]
- ymir/agents/tests/unit/test_rebase_consolidation.py[222-236]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Errored triage gets requeued ✓ Resolved 🐞 Bug ≡ Correctness
Description
The expanded error-label list still omits TRIAGE_ERRORED, so queue_siblings_for_triage() can
mark an exhausted triage failure as a sibling and enqueue it; the triage worker then skips it as
already terminal, leaving ymir_rebase_sibling on the issue and the primary waiting indefinitely.
This is the same terminal-state handling path this PR extends, but it does not cover the triage
agent's own terminal error state.
Code

ymir/agents/rebase_consolidation.py[R209-212]

+                # Error labels
+                JiraLabels.BACKPORT_ERRORED.value,
+                JiraLabels.REBASE_ERRORED.value,
+                JiraLabels.REBUILD_ERRORED.value,
Relevance

●●● Strong

Recent accepted precedent supports fixing terminal triage error handling to prevent retries and
deduplication failures.

PR-#540

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Final triage exhaustion writes TRIAGE_ERRORED and removes the in-progress marker. Sibling
discovery does not recognize that label, adds REBASE_SIBLING, and enqueues the issue, while the
triage worker classifies every Ymir label except a small non-terminal set as terminal and returns
without removing the newly added sibling marker.

ymir/agents/triage_agent.py[1307-1329]
ymir/agents/triage_agent.py[1350-1382]
ymir/agents/rebase_consolidation.py[195-239]
ymir/common/constants.py[175-182]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Prevent exhausted triage failures from being queued as fresh siblings and leaving primaries permanently blocked.

## Issue Context
`TRIAGE_ERRORED` is written after final triage retry exhaustion and is treated as terminal by the triage deduplication check, but sibling discovery does not exclude it.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[84-92]
- ymir/agents/rebase_consolidation.py[198-217]
- ymir/agents/triage_agent.py[1350-1382]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Queued siblings become invisible ✓ Resolved 🐞 Bug ≡ Correctness
Description
Adding REBASE_SIBLING to the builder's default exclusions makes
check_and_queue_primary_if_ready() generate a contradictory query that both excludes and requires
that label. A sibling still waiting in Redis is therefore invisible, so completion of another
sibling can prematurely queue the primary for rebase.
Code

ymir/agents/rebase_consolidation.py[R109-110]

+            # Sibling marker (already queued as sibling for a different primary)
+            JiraLabels.REBASE_SIBLING.value,
Relevance

●● Moderate

PR #726 has an exact contradictory JQL precedent, but its outcome is undetermined; no decisive
accepted/rejected conversion pattern exists.

PR-#726

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The builder defaults exclude_triaged to true and now puts REBASE_SIBLING in labels not in; the
readiness path invokes that default builder, then appends an OR condition requiring REBASE_SIBLING
or TRIAGE_IN_PROGRESS. Queueing applies REBASE_SIBLING before the Redis push, while an empty
readiness result causes the primary to proceed, proving queued-but-not-started siblings can be
missed.

ymir/agents/rebase_consolidation.py[68-72]
ymir/agents/rebase_consolidation.py[84-116]
ymir/agents/rebase_consolidation.py[243-250]
ymir/agents/rebase_consolidation.py[286-294]
ymir/agents/rebase_consolidation.py[421-457]
ymir/agents/rebase_consolidation.py[487-500]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`check_and_queue_primary_if_ready()` uses `build_rebase_siblings_jql()` with its default exclusions, which now exclude `ymir_rebase_sibling`, and then requires that same label in its pending-sibling predicate. Queued siblings that have not started triage are omitted and the primary can be released early.

## Issue Context
Build the readiness query without the queueing-only exclusions (for example, pass `exclude_triaged=False`) and retain the readiness function's explicit terminal-label exclusion. Add a regression test proving a queued `ymir_rebase_sibling` remains selectable by the pending query.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[109-110]
- ymir/agents/rebase_consolidation.py[421-457]
- ymir/agents/tests/unit/test_rebase_consolidation.py[280-315]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Regression test is tautological ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
test_all_terminal_states_are_recognized() never exercises either changed function or reads either
production list; it only verifies that values obtained from JiraLabels are returned by
JiraLabels.all_labels(). Removing any newly added label from production would therefore leave this
claimed regression test green.
Code

ymir/agents/tests/unit/test_rebase_consolidation.py[R228-230]

+        # Verify all expected labels exist in JiraLabels enum
+        for label in expected_terminal_labels:
+            assert label in JiraLabels.all_labels(), f"Expected terminal label {label} not in JiraLabels enum"
Relevance

●● Moderate

The test is demonstrably tautological, but historical test-quality outcomes are mixed and not
closely matching.

PR-#367
PR-#510

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The expected values are all read directly from JiraLabels, and all_labels() simply returns every
value from that same enum. The actual behavior depends on two independent inline lists that the test
explicitly acknowledges it does not access.

ymir/agents/tests/unit/test_rebase_consolidation.py[197-230]
ymir/common/constants.py[214-217]
ymir/agents/rebase_consolidation.py[195-224]
ymir/agents/rebase_consolidation.py[417-448]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Replace the enum-membership assertion with behavioral tests that fail when either production terminal-label path omits a required label.

## Issue Context
`all_labels()` is generated from the same enum members used to construct the expected set, so the current assertion cannot validate the inline production lists.

## Fix Focus Areas
- ymir/agents/tests/unit/test_rebase_consolidation.py[185-230]
- ymir/agents/rebase_consolidation.py[195-224]
- ymir/agents/rebase_consolidation.py[417-448]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Terminal filtering happens too late ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new errored/failed labels are checked only after search_jira_issues has returned at most 50
candidates, because build_rebase_siblings_jql() still excludes only triaged labels. Matching
terminal issues can therefore consume the result limit and hide eligible unprocessed siblings,
causing the primary to proceed without queueing all of them.
Code

ymir/agents/rebase_consolidation.py[R210-213]

+                JiraLabels.BACKPORT_ERRORED.value,
+                JiraLabels.REBASE_ERRORED.value,
+                JiraLabels.REBUILD_ERRORED.value,
+                # Failed labels
Relevance

●● Moderate

The capped-search/JQL interaction is plausible, but no close accepted or rejected precedent was
found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The query builder's exclusion list contains only the five triaged labels, and sibling discovery caps
that query at 50. The newly added labels are consulted later in the per-candidate loop, so skipped
terminal results are never replaced with candidates beyond the first page.

ymir/agents/rebase_consolidation.py[68-98]
ymir/agents/rebase_consolidation.py[152-164]
ymir/agents/rebase_consolidation.py[195-224]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Apply every queue-side terminal exclusion in the Jira query before the result limit is imposed.

## Issue Context
Post-query metadata filtering is not equivalent to JQL filtering because sibling discovery requests only 50 results.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[68-98]
- ymir/agents/rebase_consolidation.py[153-164]
- ymir/agents/rebase_consolidation.py[195-218]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
⚠️ Tickets: not configured — ticket URL found in PR but could not be fetched — check ticket provider credentials
✅ Compliance rules (platform): 8 rules

Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous reviews

Review updated until commit 4f69dd7

Results up to commit d6a7719 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Errored triage gets requeued ✓ Resolved 🐞 Bug ≡ Correctness
Description
The expanded error-label list still omits TRIAGE_ERRORED, so queue_siblings_for_triage() can
mark an exhausted triage failure as a sibling and enqueue it; the triage worker then skips it as
already terminal, leaving ymir_rebase_sibling on the issue and the primary waiting indefinitely.
This is the same terminal-state handling path this PR extends, but it does not cover the triage
agent's own terminal error state.
Code

ymir/agents/rebase_consolidation.py[R209-212]

+                # Error labels
+                JiraLabels.BACKPORT_ERRORED.value,
+                JiraLabels.REBASE_ERRORED.value,
+                JiraLabels.REBUILD_ERRORED.value,
Relevance

●●● Strong

Recent accepted precedent supports fixing terminal triage error handling to prevent retries and
deduplication failures.

PR-#540

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Final triage exhaustion writes TRIAGE_ERRORED and removes the in-progress marker. Sibling
discovery does not recognize that label, adds REBASE_SIBLING, and enqueues the issue, while the
triage worker classifies every Ymir label except a small non-terminal set as terminal and returns
without removing the newly added sibling marker.

ymir/agents/triage_agent.py[1307-1329]
ymir/agents/triage_agent.py[1350-1382]
ymir/agents/rebase_consolidation.py[195-239]
ymir/common/constants.py[175-182]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Prevent exhausted triage failures from being queued as fresh siblings and leaving primaries permanently blocked.

## Issue Context
`TRIAGE_ERRORED` is written after final triage retry exhaustion and is treated as terminal by the triage deduplication check, but sibling discovery does not exclude it.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[84-92]
- ymir/agents/rebase_consolidation.py[198-217]
- ymir/agents/triage_agent.py[1350-1382]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
2. Terminal filtering happens too late ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new errored/failed labels are checked only after search_jira_issues has returned at most 50
candidates, because build_rebase_siblings_jql() still excludes only triaged labels. Matching
terminal issues can therefore consume the result limit and hide eligible unprocessed siblings,
causing the primary to proceed without queueing all of them.
Code

ymir/agents/rebase_consolidation.py[R210-213]

+                JiraLabels.BACKPORT_ERRORED.value,
+                JiraLabels.REBASE_ERRORED.value,
+                JiraLabels.REBUILD_ERRORED.value,
+                # Failed labels
Relevance

●● Moderate

The capped-search/JQL interaction is plausible, but no close accepted or rejected precedent was
found.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The query builder's exclusion list contains only the five triaged labels, and sibling discovery caps
that query at 50. The newly added labels are consulted later in the per-candidate loop, so skipped
terminal results are never replaced with candidates beyond the first page.

ymir/agents/rebase_consolidation.py[68-98]
ymir/agents/rebase_consolidation.py[152-164]
ymir/agents/rebase_consolidation.py[195-224]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Apply every queue-side terminal exclusion in the Jira query before the result limit is imposed.

## Issue Context
Post-query metadata filtering is not equivalent to JQL filtering because sibling discovery requests only 50 results.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[68-98]
- ymir/agents/rebase_consolidation.py[153-164]
- ymir/agents/rebase_consolidation.py[195-218]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Regression test is tautological ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
test_all_terminal_states_are_recognized() never exercises either changed function or reads either
production list; it only verifies that values obtained from JiraLabels are returned by
JiraLabels.all_labels(). Removing any newly added label from production would therefore leave this
claimed regression test green.
Code

ymir/agents/tests/unit/test_rebase_consolidation.py[R228-230]

+        # Verify all expected labels exist in JiraLabels enum
+        for label in expected_terminal_labels:
+            assert label in JiraLabels.all_labels(), f"Expected terminal label {label} not in JiraLabels enum"
Relevance

●● Moderate

The test is demonstrably tautological, but historical test-quality outcomes are mixed and not
closely matching.

PR-#367
PR-#510

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The expected values are all read directly from JiraLabels, and all_labels() simply returns every
value from that same enum. The actual behavior depends on two independent inline lists that the test
explicitly acknowledges it does not access.

ymir/agents/tests/unit/test_rebase_consolidation.py[197-230]
ymir/common/constants.py[214-217]
ymir/agents/rebase_consolidation.py[195-224]
ymir/agents/rebase_consolidation.py[417-448]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Replace the enum-membership assertion with behavioral tests that fail when either production terminal-label path omits a required label.

## Issue Context
`all_labels()` is generated from the same enum members used to construct the expected set, so the current assertion cannot validate the inline production lists.

## Fix Focus Areas
- ymir/agents/tests/unit/test_rebase_consolidation.py[185-230]
- ymir/agents/rebase_consolidation.py[195-224]
- ymir/agents/rebase_consolidation.py[417-448]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit 122cef2 ⚖️ Balanced


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Queued siblings become invisible ✓ Resolved 🐞 Bug ≡ Correctness
Description
Adding REBASE_SIBLING to the builder's default exclusions makes
check_and_queue_primary_if_ready() generate a contradictory query that both excludes and requires
that label. A sibling still waiting in Redis is therefore invisible, so completion of another
sibling can prematurely queue the primary for rebase.
Code

ymir/agents/rebase_consolidation.py[R109-110]

+            # Sibling marker (already queued as sibling for a different primary)
+            JiraLabels.REBASE_SIBLING.value,
Relevance

●● Moderate

PR #726 has an exact contradictory JQL precedent, but its outcome is undetermined; no decisive
accepted/rejected conversion pattern exists.

PR-#726

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The builder defaults exclude_triaged to true and now puts REBASE_SIBLING in labels not in; the
readiness path invokes that default builder, then appends an OR condition requiring REBASE_SIBLING
or TRIAGE_IN_PROGRESS. Queueing applies REBASE_SIBLING before the Redis push, while an empty
readiness result causes the primary to proceed, proving queued-but-not-started siblings can be
missed.

ymir/agents/rebase_consolidation.py[68-72]
ymir/agents/rebase_consolidation.py[84-116]
ymir/agents/rebase_consolidation.py[243-250]
ymir/agents/rebase_consolidation.py[286-294]
ymir/agents/rebase_consolidation.py[421-457]
ymir/agents/rebase_consolidation.py[487-500]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`check_and_queue_primary_if_ready()` uses `build_rebase_siblings_jql()` with its default exclusions, which now exclude `ymir_rebase_sibling`, and then requires that same label in its pending-sibling predicate. Queued siblings that have not started triage are omitted and the primary can be released early.

## Issue Context
Build the readiness query without the queueing-only exclusions (for example, pass `exclude_triaged=False`) and retain the readiness function's explicit terminal-label exclusion. Add a regression test proving a queued `ymir_rebase_sibling` remains selectable by the pending query.

## Fix Focus Areas
- ymir/agents/rebase_consolidation.py[109-110]
- ymir/agents/rebase_consolidation.py[421-457]
- ymir/agents/tests/unit/test_rebase_consolidation.py[280-315]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread ymir/agents/rebase_consolidation.py Outdated
Comment thread ymir/agents/rebase_consolidation.py Outdated
Comment thread ymir/agents/tests/unit/test_rebase_consolidation.py Outdated
@majamassarini

Copy link
Copy Markdown
Member Author

/agentic_review

Comment thread ymir/agents/rebase_consolidation.py Outdated
@qodo-for-packit

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 122cef2

Previously, when checking if all siblings had finished triaging in
check_and_queue_primary_if_ready(), we only excluded issues with
"triaged" labels (ymir_triaged_*), but not those with completion
labels (ymir_backported, ymir_rebased, ymir_rebuilt) or error labels
(ymir_backport_errored, ymir_rebase_errored, etc.).

This caused primary issues to remain stuck waiting for siblings that
had already completed their work, as seen in RHEL-248139 where siblings
finished with ymir_backported and ymir_backport_errored labels.

The fix adds all terminal state labels to both:
1. check_and_queue_primary_if_ready() - so primary can proceed when all siblings are done
2. queue_siblings_for_triage() - for consistency and to avoid re-queueing completed siblings

Terminal states now include:
- Triage decisions: ymir_triaged_{rebase,backport,rebuild,not_affected,postponed}
- Completions: ymir_{backported,rebased,rebuilt}
- Errors: ymir_{backport,rebase,rebuild}_errored
- Failures: ymir_{backport,rebase,rebuild}_failed

Also adds test documentation for expected terminal label behavior.

Fixes: https://redhat.atlassian.net/browse/RHEL-248139

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
After triage retry exhaustion, issues get TRIAGE_ERRORED label which is
treated as terminal by triage deduplication. However, sibling discovery
did not exclude it, causing siblings that exhausted triage retries to be
counted as "pending", leaving primaries permanently blocked.

Add TRIAGE_ERRORED to terminal_labels in both:
- queue_siblings_for_triage() - avoid re-queueing exhausted siblings
- check_and_queue_primary_if_ready() - unblock primary when siblings exhaust retries

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
…issue

Previously, terminal label filtering happened in Python after fetching up to
50 sibling candidates from Jira. This created a critical bug: if there were
more than 50 total candidates and many of them had terminal labels, the JQL
would return 50 results that included already-processed siblings, causing us
to miss actual pending siblings and potentially fail to queue them for triage.

For example, if there were 60 sibling candidates where 40 had terminal labels
and 20 were still pending:
- Old behavior: JQL returns first 50 (say 35 terminal + 15 pending), then
  Python filters to 15 pending → we missed 5 real pending siblings
- New behavior: JQL excludes the 40 terminal ones and returns the 20 pending

The fix moves ALL terminal label exclusions from post-query Python filtering
into the JQL query itself via build_rebase_siblings_jql():

Terminal labels now excluded in JQL:
- Triage decisions: ymir_triaged_{rebase,backport,rebuild,not_affected,postponed}
- Completions: ymir_{backported,rebased,rebuilt}
- Errors: ymir_{triage,backport,rebase,rebuild}_errored
- Failures: ymir_{backport,rebase,rebuild}_failed
- Sibling marker: ymir_rebase_sibling

Kept defensive post-query check for race conditions (Jira indexing delays).

Updated test to verify all terminal labels appear in generated JQL.

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
…sions

Previous test checked if labels existed in JiraLabels.all_labels(), which is
circular - it doesn't verify the actual production code in build_rebase_siblings_jql()
or the inline terminal_labels lists in queue_siblings_for_triage() and
check_and_queue_primary_if_ready().

New behavioral tests verify:
1. JQL query actually excludes each category of terminal labels:
   - Triage decisions (triaged_*)
   - Completion labels (backported, rebased, rebuilt)
   - Error labels (triage_errored, backport_errored, etc.)
   - Failed labels (backport_failed, etc.)
   - Sibling marker (rebase_sibling)

2. Exclusions are in the JQL query itself (server-side), not post-query
   filtering, which is critical to avoid missing pending siblings when
   there are >50 total candidates

Each test method verifies a specific category and will fail if someone
removes a terminal label from the production code, preventing regressions
like RHEL-248139.

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Code review identified critical bugs:

1. **Contradictory JQL in check_and_queue_primary_if_ready**:
   - Was calling build_rebase_siblings_jql() which excludes ymir_rebase_sibling,
     then adding AND labels = "ymir_rebase_sibling" → zero results
   - Fix: Call with exclude_triaged=False, filter pending vs terminal separately

2. **Broke auto-retry for FAILED labels**:
   - FAILED labels (backport/rebase_failed) are documented as "May auto-retry"
   - Excluding them from sibling search broke the retry mechanism
   - Fix: Only exclude ERRORED labels (which block retry), not FAILED

Per jira_label_workflow_routing.md:
- ERRORED labels (triage/backport/rebase_errored): Block retry, need human → terminal
- FAILED labels (backport/rebase_failed): May auto-retry → retriable

Changes:
- build_rebase_siblings_jql: Exclude ERRORED, include FAILED
- queue_siblings_for_triage: Defensive check excludes ERRORED, includes FAILED
- check_and_queue_primary_if_ready: Call with exclude_triaged=False, both
  ERRORED and FAILED are terminal (won't proceed/block primary)
- Tests: Verify ERRORED excluded, FAILED included

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
…elease

The ymir_rebase_sibling label is a queueing marker, not a terminal triage state.
Excluding it in build_rebase_siblings_jql() broke check_and_queue_primary_if_ready()
because queued-but-not-started siblings were invisible to the readiness check.

Before fix:
- build_rebase_siblings_jql() excluded ymir_rebase_sibling in JQL
- check_and_queue_primary_if_ready() added AND labels = "ymir_rebase_sibling"
- Contradictory query (exclude X AND require X) returned zero results
- Primary was released early while queued siblings were still pending

After fix:
- build_rebase_siblings_jql() does NOT exclude ymir_rebase_sibling
- Queued siblings are correctly found by the pending query
- Primary waits until all siblings (including queued ones) finish
- queue_siblings_for_triage() still has defensive check to avoid re-queueing

Changes:
- Removed ymir_rebase_sibling from excluded list in build_rebase_siblings_jql()
- Simplified check_and_queue_primary_if_ready() call (default params work now)
- Updated test: ymir_rebase_sibling must NOT be in JQL exclusions
- Added regression test proving queued siblings are found as pending

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
@majamassarini
majamassarini force-pushed the fix-sibling-consolidation-terminal-labels branch from 331ff07 to 52d5662 Compare August 27, 2026 08:51
@majamassarini

Copy link
Copy Markdown
Member Author

/agentic_review

Comment thread ymir/agents/rebase_consolidation.py
@qodo-for-packit

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 52d5662

Per triage_agent.py:
- Resolution.OPEN_ENDED_ANALYSIS maps to ymir_triaged (terminal, no automated follow-up)
- Resolution.CLARIFICATION_NEEDED maps to ymir_needs_attention (blocked, needs human)

These were missing from terminal label exclusions, allowing completed open-ended-analysis
and clarification-needed issues to be re-queued as siblings.

Changes:
- Added JiraLabels.TRIAGED to JQL exclusions in build_rebase_siblings_jql()
- Added JiraLabels.NEEDS_ATTENTION to JQL exclusions
- Added both to defensive terminal check in queue_siblings_for_triage()
- Extended test to verify both labels are excluded in JQL

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
@majamassarini

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-for-packit

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 4f69dd7

@lbarcziova lbarcziova left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@majamassarini
majamassarini merged commit 83aca5b into packit:main Aug 31, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants