Skip to content

feat(#294): PR creation throttle for CodeRabbit rate limit compliance#306

Merged
xsovad06 merged 1 commit into
mainfrom
feat/issue-294
Jul 9, 2026
Merged

feat(#294): PR creation throttle for CodeRabbit rate limit compliance#306
xsovad06 merged 1 commit into
mainfrom
feat/issue-294

Conversation

@xsovad06

@xsovad06 xsovad06 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Automated changes for: feat(supervisor): PR creation throttle for CodeRabbit rate limit compliance

Closes #294

Context

Problem

CreatePRStep creates PRs immediately, regardless of CodeRabbit quota availability. When multiple agents complete development simultaneously, they create 3-4 PRs within minutes, exhausting the 4/hour free-tier limit. Rate-limited PRs are often merged before a review slot opens, resulting in zero code review.

Solution

Queue PR creation and drip-feed them at intervals that respect the CodeRabbit rate limit. Fully opt-in -- zero behavior change when coderabbit.enabled = false...

Commits

20e0681 feat(core): PR creation throttle for CodeRabbit rate limit compliance
Closes #294

Files changed

sova/core/steps/create_pr.py        |  56 ++++
 sova/dashboard/app.py               |  24 ++
 sova/dashboard/routers/quota.py     |  53 ++-
 sova/dashboard/services/agent_db.py |   9 +
 sova/db/models.py                   |  40 +++
 sova/supervisor/pr_throttle.py      | 324 ++++++++++++++++++
 tests/test_pr_throttle.py           | 642 ++++++++++++++++++++++++++++++++++++
 7 files changed, 1147 insertions(+), 1 deletion(-)

@xsovad06 xsovad06 self-assigned this Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f6c2ca1a-58da-4045-949b-27a319ae7aa2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds a DB-backed PR creation queue for quota-enabled runs, routes CreatePRStep through throttled or immediate creation, starts queue workers in dashboard lifespan, exposes queue status in the API, and adds coverage for queue lifecycle and integration paths.

Changes

PR Creation Throttling

Layer / File(s) Summary
Queue schema and throttle service
sova/db/models.py, sova/supervisor/pr_throttle.py
Adds PRQueueStatus and PRCreationQueue, plus enqueue/dequeue, polling, queue processing, post-create side effects, recovery, and the background loop.
CreatePRStep throttling branch
sova/core/steps/create_pr.py
Routes PR creation by quota state, adds immediate creation fallback, and introduces throttled creation with queue polling and queued error handling.
Dashboard startup and cleanup wiring
sova/dashboard/app.py, sova/dashboard/services/agent_db.py
Starts and stops PR throttle workers in application lifespan, restores stuck queue entries on startup, and dequeues pending queue entries during task-run finalization.
PR queue status endpoint
sova/dashboard/routers/quota.py
Adds GET /quota/pr-queue and returns enabled state, pending count, recent non-cancelled entries, and error responses on failures.
Throttle and quota tests
tests/test_pr_throttle.py, tests/test_coderabbit_quota.py
Adds coverage for queue model operations, queue processing, recovery, status polling, CreatePRStep branching, dashboard queue status, dequeue cleanup, side effects, and loop lifecycle.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • xsovad06/sova#95: Both PRs modify sova/dashboard/services/agent_db.py’s _finalize_task_run, affecting cleanup behavior during task completion.
  • xsovad06/sova#183: Both PRs modify sova/core/steps/create_pr.py’s CreatePRStep, with this one adding quota-based throttling around creation.
  • xsovad06/sova#303: This PR depends on the same coderabbit_quota configuration and quota event behavior to decide when PR creation can proceed.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR covers queueing, processing, persistence, API visibility, and tests, but it does not show the required delayed-PR notification with ETA. Add the delayed-PR notification path with an ETA and cover it with tests, or document why that requirement is deferred.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately states the main change: adding a PR creation throttle for CodeRabbit quota compliance.
Description check ✅ Passed The description is mostly complete, but it omits the template's Type of Change and Checklist sections.
Out of Scope Changes check ✅ Passed The changes stay focused on PR throttling, queue management, API visibility, and related tests with no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jul 7, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sova/core/steps/create_pr.py`:
- Around line 117-118: The nested _session_factory in create_pr.py is missing a
return type annotation, which violates the type-hinting requirement and triggers
ANN202. Add an explicit async return annotation to _session_factory using
AsyncSession, and import AsyncSession from sqlalchemy.ext.asyncio if it is not
already available, while leaving the get_session(project_dir=ctx.project_dir)
call unchanged.
- Around line 64-67: The PR creation flow in create_pr.py is incorrectly
choosing the throttled path in multi-project deployments, which can leave
`poll_until_created()` waiting until timeout because `process_queue_loop()` is
only active for single-project apps. Update the `CreatePR` logic in `_create_pr`
to skip `_create_pr_throttled()` when running in multi-project mode, or ensure
the queue processor is started for that deployment type, while keeping
`_create_pr_immediate()` as the fallback path.

In `@sova/dashboard/app.py`:
- Around line 229-230: The async helper _pr_session_factory in app.py is missing
a return type annotation, so update its function signature to be fully
type-hinted as required by the coding guidelines and ANN202. Add the appropriate
return annotation for the session object returned by
get_session(project_dir=resolved), and keep the change localized to
_pr_session_factory so the signature is explicit and consistent with the rest of
the typed code.
- Around line 219-238: The PR throttle worker is only started in the
single-project path, so throttled PRs in multi-project runs never get consumed.
Update the startup logic in app.py around the process_queue_loop and
recover_creating_entries flow to also launch a per-project worker when is_multi
is true, or otherwise bypass throttling for multi-project mode. Use the existing
_pr_session_factory, cfg.coderabbit_quota, and cfg.github_repo setup as the
place to wire in the additional worker.

In `@sova/dashboard/routers/quota.py`:
- Around line 67-115: Add endpoint coverage for pr_queue_status / GET
/quota/pr-queue in tests/test_coderabbit_quota.py. Create one test for the
disabled path that asserts the response is {"enabled": False, "pending": 0,
"entries": []}, and another for the enabled path that seeds PRCreationQueue data
and verifies the returned pending count plus populated entries fields. Use the
same setup patterns already used for the other quota endpoint tests so the new
route is exercised through the router.

In `@sova/db/models.py`:
- Around line 442-446: The PR queue indexes in the model’s __table_args__ only
cover status, task_run_id, and enqueued_at, so the hot queries in process_queue
and the /quota/pr-queue path still miss project_slug and can’t use a single
efficient index. Update the model’s index set on the PR queue table to add a
composite index for the shared filter/order pattern using project_slug, status,
and enqueued_at, and keep the existing indexes only if they still serve other
query paths.

In `@sova/supervisor/pr_throttle.py`:
- Around line 99-104: The function signatures for poll_until_created and
process_queue_loop are missing type annotations for session_factory, which
violates the project’s typing guideline. Add an explicit callable/awaitable
session factory type to both signatures, and import the needed typing symbols
(such as Callable and Awaitable) so the parameter is fully annotated wherever it
is used.
- Around line 180-241: Persist the PRQueueStatus.CREATING state before calling
git_ops.create_pr inside process_queue so a crash cannot roll it back to PENDING
and re-create the PR on restart. Update the flow around entry.status,
session.flush/session.commit, and the create_pr call in process_queue to make
the CREATING transition durable before any GitHub/network work, while keeping
run_post_create_side_effects and the PR CREATED/task_run updates after the PR
exists. Also ensure the existing error handling still marks failures correctly
if create_pr raises.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 601d7142-1da4-4de2-9f49-66daf38d7627

📥 Commits

Reviewing files that changed from the base of the PR and between cfb9fd2 and 20e0681.

📒 Files selected for processing (7)
  • sova/core/steps/create_pr.py
  • sova/dashboard/app.py
  • sova/dashboard/routers/quota.py
  • sova/dashboard/services/agent_db.py
  • sova/db/models.py
  • sova/supervisor/pr_throttle.py
  • tests/test_pr_throttle.py

Comment thread sova/core/steps/create_pr.py
Comment thread sova/core/steps/create_pr.py Outdated
Comment thread sova/dashboard/app.py Outdated
Comment thread sova/dashboard/app.py Outdated
Comment thread sova/dashboard/routers/quota.py Outdated
Comment thread sova/db/models.py
Comment thread sova/supervisor/pr_throttle.py
Comment thread sova/supervisor/pr_throttle.py Outdated
@dsova06

dsova06 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@xsovad06

xsovad06 commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@xsovad06 xsovad06 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

PR Review: feat(#294): PR creation throttle for CodeRabbit rate limit compliance

Summary

PR #306 adds a DB-backed PR creation queue for CodeRabbit rate limit compliance. When coderabbit_quota.enabled = true, CreatePRStep enqueues PR creation data instead of calling GitHub immediately. A background process_queue_loop drains entries one at a time, respecting the quota window. 1 commit, 8 files, 1552 additions. CI fully green.

Findings

[HIGH] Correctness -- Missing Alembic migration for PRCreationQueue table
Location: sova/db/models.py:420-447
Problem: The new PRCreationQueue model has no Alembic migration. Last migration is 015_add_coderabbit_events.py. In PostgreSQL deployments using Alembic, the table will not be created. The create_all self-healing fallback handles SQLite only.
Suggestion: Generate a migration: alembic revision --autogenerate -m "add_pr_creation_queue".

[HIGH] Correctness -- run_post_create_side_effects uses get_project_dir() without guaranteed context
Location: sova/supervisor/pr_throttle.py:292-296
Problem: run_post_create_side_effects() calls get_project_dir() to load config and create an adapter. This relies on per-request context set by dashboard middleware. But this function is called from process_queue() in a background task -- not in a request context. get_project_dir() may return None, causing load_config(None) to use CWD instead of the correct project directory.
Suggestion: Pass project_dir as a parameter instead of relying on the context variable. The queue entry already has project_slug and repo.

[MEDIUM] Consistency -- Non-standard __import__("typing").TYPE_CHECKING pattern
Location: sova/core/steps/create_pr.py:18
Problem: Uses if __import__("typing").TYPE_CHECKING: instead of the standard from typing import TYPE_CHECKING; if TYPE_CHECKING: used in 16+ other files.
Suggestion: Use the standard pattern for consistency.

[MEDIUM] Correctness -- _finalize_task_run dequeues only on non-done status
Location: sova/dashboard/services/agent_db.py:161
Problem: Dequeue is guarded by if status != "done". A run marked "done" without its queue entry being processed leaves a PENDING entry that the processor will attempt to create a duplicate PR from. process_queue calls git_ops.create_pr directly without the _try_adopt_existing_pr dedup check.
Suggestion: Either always dequeue regardless of terminal status, or add PR dedup to process_queue.

[LOW] Code Quality -- Bare except Exception without chaining
Location: sova/dashboard/routers/quota.py:113-115
Problem: except Exception: re-raises as HTTPException without from exc, losing traceback chain (Ruff B904).
Suggestion: raise HTTPException(...) from exc

Confirmed Bot Findings

All 7 CodeRabbit findings from the initial review have been addressed in the current code:

  • _session_factory / _pr_session_factory return type annotations -- fixed
  • Composite index ix_pr_queue_project_status_enqueued -- added
  • SessionFactory type alias -- applied to all signatures
  • 3-phase transaction pattern for CREATING durability -- implemented
  • Multi-project worker startup -- added
  • PR queue endpoint tests -- added

Verdict

Request changes -- two HIGH findings should be resolved:

  1. Missing Alembic migration for PRCreationQueue
  2. run_post_create_side_effects context variable dependency in background task

What's Done Well

  1. 3-phase transaction architecture -- CREATING committed before network call, fields extracted to locals, failures handled in separate transactions. Prevents crash-recovery duplicates.
  2. Thorough test coverage -- 910 lines covering all code paths including edge cases (stale entries, quota exhaustion, fallback paths, loop lifecycle).
  3. Clean opt-in design -- gated behind coderabbit_quota.enabled, graceful fallback on enqueue failure, original code path unchanged.

@xsovad06

xsovad06 commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

All review findings addressed in e7595c7 (squashed into the feature commit):

[HIGH] Missing Alembic migration: Added 016_add_pr_creation_queue.py with table schema, FK constraint, and all 4 indexes.

[HIGH] run_post_create_side_effects context variable: Added explicit project_dir: Path | None parameter. Threaded through process_queue and process_queue_loop. Dashboard passes project_dir from both single-project and multi-project startup paths.

[MEDIUM] Non-standard __import__("typing").TYPE_CHECKING: Replaced with standard from typing import TYPE_CHECKING import, grouped with stdlib.

[MEDIUM] Dequeue only on non-done status: Removed the if status != "done" guard. Now dequeues on all terminal transitions, preventing duplicate PR creation from orphaned PENDING entries.

[LOW] Bare except Exception (B904): Chained with from exc in quota.py pr_queue_status endpoint.

CI: all checks green.

@xsovad06 xsovad06 dismissed coderabbitai[bot]’s stale review July 9, 2026 09:34

All findings addressed

@xsovad06

xsovad06 commented Jul 9, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

@xsovad06 xsovad06 merged commit caa5245 into main Jul 9, 2026
8 checks passed
@xsovad06 xsovad06 deleted the feat/issue-294 branch July 9, 2026 17:13
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.

feat(supervisor): PR creation throttle for CodeRabbit rate limit compliance

2 participants