Skip to content

fix(claim): skip only renovate bot issues, log filtered candidates - #219

Merged
joryirving merged 3 commits into
mainfrom
fix/renovate-claim-filter-216
Aug 23, 2026
Merged

fix(claim): skip only renovate bot issues, log filtered candidates#219
joryirving merged 3 commits into
mainfrom
fix/renovate-claim-filter-216

Conversation

@joryirving

Copy link
Copy Markdown
Contributor

Summary

select_candidates dropped every queue item whose title merely contained
"renovate" (a bare IGNORECASE substring), so issues about Renovate were never
claimable — both lanes logged empty on 2026-08-23 while get_queue returned
two claimable: true, status/ready, lane: local items:

  • misospace/foreman-dispatch-bridge#55 — "[P3] No requirements-dev.txt pin management — dev-only deps not managed by Renovate"
  • misospace/llmkube-images#199 — "[P3] Renovate config still groups coder apps that were consolidated into apps/llmkube-coder"

Changes

  • bridge/claim.py
    • Replaced the bare renovate substring with the same narrow criteria dispatch uses in isRenovateIssue (src/lib/issue-filters.ts): dependency dashboard / renovate dashboard title substrings, update dep / update image title prefixes, and the renovate / dependencies / automated labels. The queue already omits bot issues by default (includeRenovate=false); this guard only covers the gap where a dispatch version or config serves them.
    • Every item skipped by a bridge-side filter now logs candidate-skipped with the issue number and reason (also for lane/status/claimable skips), so an empty lane is distinguishable from a filtered one.
    • status/ready, lane match, and the claimable/agentMatch checks are unchanged — nothing else is claimed that wasn't before.
  • tests/fixtures/dispatch_claim_sample.json — item Renovate Dashboard 🤖 #7 is now a real bot title (Update dependency pytest from 8.0.0 to 8.1.0), since the old "update renovate bot config" title correctly becomes claimable under the new criteria.
  • tests/test_claim.py — new coverage: a "renovate" mid-sentence title is yielded (both starved issue titles from the incident); a "Renovate Dashboard" / "Dependency Dashboard" title is not; an "Update dependency …" / "update image …" title is not; a renovate label is not; a skip emits a log record with number and reason.

Verification

  • python -m pytest tests/ -q → 503 passed
  • python -m mypy bridge/ → clean

Fixes #216

select_candidates dropped every queue item whose title merely contained
"renovate" (bare IGNORECASE substring), so issues *about* Renovate — a
standing category of work in this repo — were never claimable. Both lanes
went empty on 2026-08-23 with a non-empty queue because of this.

Replace the substring with the same narrow criteria dispatch uses in
isRenovateIssue (src/lib/issue-filters.ts): "dependency dashboard" /
"renovate dashboard" title substrings, "update dep" / "update image"
title prefixes, and the renovate/dependencies/automated labels. The
queue already omits bot issues by default (includeRenovate=false); this
guard only covers the gap where a dispatch version or config serves
them.

Every item skipped by a bridge-side filter now logs "candidate-skipped"
with the issue number and reason, so an empty lane is distinguishable
from a filtered one. status/ready, lane match, and the
claimable/agentMatch check are unchanged.

Fixes #216
its-saffron[bot]

This comment was marked as outdated.

@joryirving

Copy link
Copy Markdown
Contributor Author

Reviewed and this is good — approach is right and I'd merge it. Two nits, neither blocking, plus one thing worth recording because it looked like a risk and isn't.

The candidate-skipped line is INFO and now fires for lane-mismatch and not-claimable as well as the bot filter. Volume should stay low because claim_one passes the lane to queue() and dispatch filters server-side, so the mechanical skips are rare in practice. But if select_candidates ever runs over an unfiltered queue that becomes one INFO line per non-matching item, per lane, per tick. Debug for lane-mismatch and not-claimable, info for the bot-filter reasons, would keep the signal that #216 actually asked for without the rest.

The dependencies label is now a filter criterion. That is faithful to dispatch's isRenovateIssue, so it is the right call, but it does mean a legitimate hand-written issue labelled dependencies is unclaimable — which is the same class of false positive #216 was about, just moved from the title to a label. Nothing regresses today (#55 carries type/chore, audit, priority/p3 and no dependencies), and I would rather stay consistent with dispatch than diverge, so this is a note for whoever hits it rather than a change request.

On the fixture: swapping item 7 from chore(deps): update renovate bot config to Update dependency pytest from 8.0.0 to 8.1.0 is necessary, not a weakened test. Three existing assertions depend on item 7 being filtered — test_select_item_picks_first_ready_claimable_non_renovate, test_select_item_skips_renovate_and_non_ready, and the == [42] check in select_candidates — and the old title becomes claimable under the new criteria, correctly, since it is an issue about bot config. Leaving it would have broken all three.

Two things I checked that could have bitten and did not. re is still used by _TOKEN_RE, so dropping _RENOVATE_RE leaves no unused import, and ruff check is clean even though the PR body only reports pytest and mypy. And the extra={"number", "reason", "lane"} keys avoid the reserved LogRecord attributes — name would have raised KeyError in makeRecord, which is what broke #200.

Structured skip reasons like renovate-title-prefix:update dep were a good call: the log says which criterion fired rather than just that something did, which is the part that made the original starvation take so long to spot.

Note for sequencing: this needs a release and a home-ops digest bump before the queue actually unblocks, since the deployed image still carries the old filter. #208 (0.7.1) is green and ahead of it.

…at INFO

Per review: lane-mismatch / not-ready / not-claimable skips are expected
noise (dispatch filters lane/status server-side before the queue reaches
the bridge) and would spam one INFO line per item per tick if
select_candidates ever ran over an unfiltered queue. The bot-filter skips
stay at INFO — that is the #216 failure mode a lane silently starved by a
bridge-side filter.

Adds coverage: the mechanical skip reasons log at DEBUG and are silent at
the default INFO level.
@joryirving

Copy link
Copy Markdown
Contributor Author

Applied the log-level nit in e4b08f4: bot-filter skips stay at INFO (that's the #216 failure mode — a lane silently starved by a bridge-side filter), while lane-mismatch / not-ready / not-claimable now log at DEBUG, since dispatch filters lane/status server-side and those skips are expected noise. Added test_mechanical_skips_log_at_debug_not_info, which asserts the three mechanical reasons come out at DEBUG and are completely silent at INFO. 504 tests green, mypy + ruff clean.

On the dependencies label: agreed that staying consistent with dispatch beats diverging, so no change — I recorded the trade-off in the guard's comment block (bridge/claim.py) so whoever hits a hand-written issue carrying that label sees immediately why it was skipped and that both sides need to change together.

Confirmed the two non-bites independently: re is still used by _TOKEN_RE (no unused import), and the extra keys are number/reason/lane — all safe against makeRecord's reserved attributes.

On sequencing: noted. #208 (0.7.1) is green and ahead in the queue, and release-please will pick this up in the next release; the home-ops digest bump comes after that lands.

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

AI Automated Review (incremental)

Incremental review: reviewed the changes since the last managed review; unresolved findings from that review are carried forward.

Analysis engine: MiniMax-M2.7@https://litellm.jory.dev/v1 (anthropic) — primary route

Recommendation: Approve

This PR correctly fixes the Renovate filter regression (issue PR 216) by replacing a bare renovate substring match with the same narrow criteria dispatch uses in isRenovateIssue — dashboard substrings, update prefixes, and bot labels — so issues about Renovate are no longer starved from the claim queue.

Change-by-Change Findings

bridge/claim.py

  • Renovate filter precision: The fix replaces the overly-broad substring check with narrowly-scoped criteria (dependency dashboard/renovate dashboard substrings, update dep/update image prefixes, renovate/dependencies/automated labels). This aligns exactly with dispatch's isRenovateIssue and fixes the incident where two real issues (PR 55 and PR 199) were silently dropped on 2026-08-23.
  • Logging level separation (incremental delta): Bot-filter skips (the PR 216 failure mode) now log at INFO, making them visible in operational logs. Mechanical skips (lane-mismatch, not-ready, not-claimable) log at DEBUG to avoid spamming INFO when select_candidates receives an unfiltered queue. The logic logger.info if skip.startswith("renovate-") else logger.debug correctly routes each skip type.
  • Trade-off documentation: The comment acknowledging that the dependencies label also filters hand-written issues is a good disclosure; if this becomes problematic, both dispatch and bridge would need coordinated changes.

tests/test_claim.py

  • test_mechanical_skips_log_at_debug_not_info (new): Correctly verifies that lane/status/claimable skips emit at DEBUG, not INFO, and that at INFO level they are silent. The test creates three items with distinct failure modes and asserts the correct (number, reason, levelno) tuples.
  • test_skipped_candidate_is_logged_with_number_and_reason: Updated to assert records[0].levelno == logging.INFO for the bot-filter skip, confirming the fix from the incremental delta.

tests/fixtures/dispatch_claim_sample.json

  • Item PR 7 title changed from "Update renovate bot config" (which should now be claimable) to "Update dependency pytest from 8.0.0 to 8.1.0" (a real bot title that should be filtered). This correctly reflects the new narrow criteria.

CI

  • test: success
  • docker: success

Verification

  • The PR body correctly identifies the two starved issues (PR 55 and PR 199) from 2026-08-23 that motivated the fix.
  • Repository history confirms commits 506b538 (skip only renovate bot issues) and e4b08f4 (log mechanical skips at DEBUG) as the two-fix sequence.
  • The dependencies label trade-off is explicitly documented in code comments, meeting the requirement to name concrete files the fix touches.

@joryirving
joryirving merged commit 32cd164 into main Aug 23, 2026
3 checks passed
@joryirving
joryirving deleted the fix/renovate-claim-filter-216 branch August 23, 2026 20:34
@its-miso its-miso Bot mentioned this pull request Aug 23, 2026
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.

Bridge drops any queue item whose title contains "renovate", starving both lanes

1 participant