Critique/docs
Architecture

Event-Driven Pipeline

How Critique ingests GitHub webhooks, deduplicates deliveries, and choreographs async review pipelines via QStash.

Critique’s GitHub integration is built around an extremely resilient, asynchronous event-driven architecture. This ensures that the system handles spikes in GitHub webhook traffic without timing out, losing events, or double-processing PRs.

1. Webhook Ingestion & Deduplication

When a webhook hits the /api/github/webhooks endpoint, the immediate goal is to safely accept the payload and return a 202 Accepted to GitHub as fast as possible.

  • Deduplication: The system extracts the X-GitHub-Delivery header and checks the database for an existing DeliveryEvent with this ID. If it exists and its status is RECEIVED, VALIDATED, QUEUED, or ENQUEUED, Critique updates the status to DEDUPED and immediately stops processing.
  • Event Lifecycle Tracking: The lifecycle of a delivery is rigorously tracked via database statuses: RECEIVEDVALIDATEDQUEUED (when sent to QStash) → PROCESSING (when QStash hits the handler) → COMPLETED (or IGNORED / FAILED).

2. QStash Choreography

To prevent server timeouts and handle rate limits gracefully, Critique relies on Upstash QStash as its asynchronous task queue.

The lifecycle of a PR review webhook follows a strict choreography:

  1. Ingestion: GitHub sends a pull_request webhook. Critique verifies the payload signature, stores it as a DeliveryEvent, pushes a github/webhook.received message to QStash, and returns 202 Accepted.
  2. Routing: QStash calls the process-delivery endpoint. The processor looks up the saved delivery, extracts PR metadata (base SHA, head SHA, clone URL), and synchronously syncs the GitHub App installation record.
  3. Review Queueing: The delivery processor calls queuePullRequestReview(...) to create a new ReviewRun record in the database.
  4. Pipeline Triggering: The delivery processor immediately sends a second QStash message: review/run.requested containing the reviewRunId. The delivery is then marked as COMPLETED.
  5. Execution: QStash consumes the review/run.requested message, invoking the actual AI review pipeline (/api/qstash/review-run) to fetch code diffs, generate comments, and post them back to the GitHub PR.

3. Delivery Replay

Because it uses QStash, failed webhook deliveries (e.g., resulting in a FAILED state due to network errors) can be retried. The process-delivery handler explicitly tracks and increments an attemptCount field in the database every time a delivery is processed, safely logging error messages if processing throws an exception.

4. Lazy Syncing & Active Indexing

Installation and repository state is kept highly eventually-consistent using two key strategies:

  • Lazy Syncing: Every single processed webhook (pull_request, push, check_run, etc.) automatically calls syncInstallationRecord() before doing its primary work. This ensures the database installation record is never stale, even if a dedicated installation webhook was previously dropped.
  • Active Indexing: When an installation (created) or installation_repositories (repositories added) event occurs, the system doesn't just sync the record. It actively gathers the newly added repositories and calls enqueueAutoIndexesForInstallation. This pushes jobs to a background QStash worker to clone the repositories and build the vector indexes (embeddings) for the codebase. Deleted installations or removed repositories bypass this intensive indexing step.