feat(code-review): surface code review as PR/MR gate check#885
Merged
alex-alecu merged 42 commits intomainfrom Mar 9, 2026
Merged
feat(code-review): surface code review as PR/MR gate check#885alex-alecu merged 42 commits intomainfrom
alex-alecu merged 42 commits intomainfrom
Conversation
Track GitHub Check Run IDs on code review records so we can update the check status as the review progresses through its lifecycle.
Add createCheckRun() and updateCheckRun() to the GitHub adapter. These use the GitHub Checks API to create rich status checks that appear in the PR Checks tab and can be set as required checks in branch protection rules.
Add setCommitStatus() to the GitLab adapter. GitLab commit statuses are idempotent by (sha, name), so we upsert a 'kilo/code-review' status on each commit. Users can configure this as a required external approval in merge request approval rules.
When a PR triggers a code review, create a GitHub Check Run in 'queued' state so the PR immediately shows a pending Kilo Code Review check. Skipped for lite (read-only) app installations. Non-blocking — review still proceeds if check creation fails.
When an MR triggers a code review, set a 'pending' commit status so the MR immediately shows a kilo/code-review check. Uses the existing Project Access Token flow. Non-blocking — review proceeds if status creation fails.
When the code review status changes (running, completed, failed, cancelled), update the corresponding GitHub Check Run or GitLab commit status. Maps review states to platform-specific statuses with descriptive output. Non-blocking — status callback succeeds even if the gate check update fails.
When enabled, the PR gate check will fail if the review finds blocking issues. Defaults to false (system-failure-only mode). The strict_gate behavior requires the cloud agent to report a gate_result in its completion callback (future enhancement).
- Remove unnecessary 'as GitHubAppType' cast in PR handler - Clear check_run_id on review retry so a fresh check run is created - Use numeric platform_project_id for GitLab commit status updates - Deduplicate getIntegrationById call in status callback (was called twice for terminal states — once for gate check, once for reactions) - Fix indentation from removed inner if-block
# Conflicts: # packages/db/src/migrations/meta/0045_snapshot.json # packages/db/src/migrations/meta/_journal.json
Contributor
Code Review SummaryStatus: 1 Issues Found | Recommendation: Address before merge Overview
Fix these issues in Kilo Cloud Issue Details (click to expand)WARNING
Other Observations (not in diff)Issues found in unchanged code that cannot receive inline comments: None. Files Reviewed (37 files)
|
- Guard mapStatusToCheckRun against unsupported statuses by returning null instead of silently mapping to 'completed' without a conclusion - Resolve GitLab access token once and share it between the gate check update and the reaction/footer block to avoid duplicate token refreshes - Extract getGitLabInstanceUrl and resolveGitLabAccessToken helpers to reduce duplication - Add Number.isSafeInteger guard in updateCheckRun to fail loudly if a check run ID ever exceeds JS safe integer range - Use BigInt.toString() explicitly in PR handler log for consistency
src/lib/integrations/platforms/github/webhook-handlers/pull-request-handler.ts
Show resolved
Hide resolved
Move the gate check update (GitHub Check Run / GitLab commit status) before writing the terminal status to the database. This prevents a race where a flaky GitHub/GitLab API call leaves the gate stale with no retry path, since subsequent callbacks hit the terminal-state early-return. Also report terminal gate failures to Sentry.
After resetCodeReviewForRetry() clears check_run_id, the retrigger flow now creates a fresh GitHub Check Run (or GitLab commit status) so that subsequent status callbacks can update the gate. Without this, the stale failed/cancelled check would permanently block merging on repos with required status checks.
If createCheckRun() succeeds on GitHub but updateCheckRunId() fails to persist the ID in Postgres, the check run becomes orphaned — no subsequent status callback can update it. On repos with Kilo Code Review as a required check, this permanently blocks merging. Now we detect this partial failure and cancel the orphaned check run.
If recreatePRGateCheck() creates a check run on GitHub but fails to persist the ID via updateCheckRunId(), cancel the orphaned check run so it doesn't permanently block merging on repos with required checks. Re-throws the DB error so the outer catch logs it.
…ings
Accept an optional gateResult ('pass' | 'fail') field in the status
callback payload from the orchestrator or cloud-agent-next. When the
review completes but gateResult is 'fail' (agent found blocking
issues with strict_gate enabled), the GitHub Check Run conclusion is
set to 'failure' and GitLab commit status to 'failed' instead of
'success'. This lets repos with required checks block merging when
the review finds problems.
…fig schema The new gate_threshold field supports 'off', 'all', 'warning', and 'critical' levels, giving users granular control over when the PR gate check fails based on review findings.
Wire gate_threshold through SaveReviewConfigInputSchema, getReviewConfig response (defaulting to 'off'), and the saveReviewConfig mutation.
Mirror the personal router changes: add gateThreshold to the org SaveReviewConfigInputSchema, getReviewConfig, and saveReviewConfig.
Add a Select control with four options (off, all, warning, critical), local state, hydration from server config, and wiring to both org and personal save mutations.
Unexpected gateResult values are logged and normalized to undefined so only 'pass' or 'fail' reach the gate check update logic.
The setting has no effect on the legacy v1 agent, so hide it when cloud-agent-next is not available to avoid user confusion.
src/lib/integrations/platforms/github/webhook-handlers/pull-request-handler.ts
Show resolved
Hide resolved
src/lib/integrations/platforms/gitlab/webhook-handlers/merge-request-handler.ts
Outdated
Show resolved
Hide resolved
jeanduplessis
approved these changes
Mar 6, 2026
Contributor
jeanduplessis
left a comment
There was a problem hiding this comment.
I'm provisionally approving, but highly recommend updating the "Off" label.
Though (non-blocking): Do we maybe want to put this feature behind a feature flag and test it our ourselves first before rolling it out to everyone?
…outer Add isPrGateFlagEnabled to the existing Promise.all that fetches the agent config and cloud-agent-next flag. Include isPrGateEnabled in both the default and loaded config response paths so the frontend can read it.
Parallelize both flag checks via Promise.all (replacing the sequential await for cloud-agent-next). Include isPrGateEnabled in both the default and loaded config response paths. Uses the same botUserId ?? ctx.user.id distinctId as the existing flag.
Extract isPrGateEnabled from configData (propagated from the router changes) and use it instead of isCloudAgentNextEnabled to control visibility of the PR Gate Threshold dropdown. When hidden, the gateThreshold stays at its default 'off'.
Skip createCheckRun() when the code-review-pr-gate flag is disabled for the owner. Uses owner.userId as the PostHog distinctId, matching the pattern used in config routers.
Wrap the setCommitStatus('pending') call inside the PrAT block with
an isPrGateEnabled check. The eyes reaction remains ungated since
it is unrelated to the PR gate feature.
Defense-in-depth: force gateThreshold to 'off' in the session input when the flag is disabled. Prevents a stale non-'off' config value from activating gating after the flag is turned off.
Move owner construction above the recreatePRGateCheck call and gate it behind the code-review-pr-gate flag. Without this, retriggering a review when the flag is off would create orphaned pending check runs that permanently block merges on repos with required checks.
…to callback enqueueCallbackNotification never included gateResult in the callback payload, making gate failures impossible on the v2 backend. Thread gateResult from the complete event through the execution lifecycle chain (ingest → handleExecutionComplete → updateExecutionStatus → enqueueCallbackNotification → callback payload) so the code-review- status endpoint can receive it.
invokeCallback call sites in session-init.ts only passed sessionId, status, and errorMessage — gateResult was never included. Thread gateResult through both the queue-based callback path (enqueueCallbackNotification) and the direct SSE streaming path (invokeCallback in session-init.ts) so gate failures can be reported on the v1 backend.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
strict_gateoption to the code review agent config — when enabled, the check will fail if the review finds blocking issues (requires future cloud agent callback extension). Defaults to system-failure-only mode.checks:writepermission.code-review-pr-gate), evaluated per-user. When disabled or missing, no check runs are created,gateThresholdis forced tooff, and the UI hides the gate config. In dev environments the flag is overridden totrueviaprocess.env.NODE_ENV === 'development'.Note: The KiloConnect GitHub App needs
checks:writepermission added in its settings. Existing installations will be prompted to accept the new permission. Until then, check creation silently fails and reviews proceed normally.Verification
pnpm typecheck— passes across all 28 workspace projectsVisual Changes
Demo alex-alecu/stories-canvas#16
Reviewer Notes
checks:write) is a manual admin step. Until it's done, the new check run creation calls will fail non-blocking — reviews still work exactly as before.strict_gateconfig option is added but not yet active at the cloud agent level. It's wired into the schema so the UI and backend are ready when the agent starts reporting agate_resultin its completion callback.code-review-pr-gate— evaluated per-user via PostHog. When the flag is off, undefined, or PostHog errors, the system defaults to disabled (no check runs,gateThresholdforced tooff, UI dropdown hidden). The flag is checked at 6 callsites: GitHub/GitLab webhook handlers (check run creation), review payload preparation (gateThreshold), retrigger (gate recreation), and config routers (UI visibility). Cancel and status-update paths are naturally gated by the absence of acheck_run_id.