Skip to content

feat(poller): CI-gate review readiness (red CI resumes to fix)#141

Merged
thejustinwalsh merged 2 commits into
mainfrom
feat/ci-gated-review
May 25, 2026
Merged

feat(poller): CI-gate review readiness (red CI resumes to fix)#141
thejustinwalsh merged 2 commits into
mainfrom
feat/ci-gated-review

Conversation

@thejustinwalsh

@thejustinwalsh thejustinwalsh commented May 25, 2026

Copy link
Copy Markdown
Owner

Replaces #140 (auto-closed when its base #139 merged; GitHub won't reopen/retarget a closed PR). Now a clean single-commit diff against main.

What

Make red CI a resume trigger and gate review-resolution on green CI — a PR can't be reviewed until it builds. Implements the spec note from #139.

How

  • PrSnapshot.ci — a collapsed CiStatus (passing/failing/pending/none) from statusCheckRollup, via the pure, unit-tested deriveCiStatus (any failure → failing; else any unfinished check → pending; else passing; no checks → none; handles CheckRun + legacy StatusContext). findPrForEpic now fetches it.
  • classifyReviewOutcome is CI-gated: explicit review feedback still wins; else failing CI resumes to fix it (CI_FAILED decision); else an APPROVED/0-actionable verdict while CI is pending is held (null) so the loop never ends on an un-built PR; passing/none resolves. Absent CI is non-blocking — the pre-CI loop is unchanged.
  • Resume brief branches on CI_FAILED — a fix-CI brief (gh pr checks / gh run view --log-failed, fix the cause, push once), distinct from the address-review brief.

What to verify

  • deriveCiStatus across CheckRun + StatusContext; failure outranks pending — poller-gateway.test.ts.
  • CI gate: failing→CI_FAILED; APPROVED+pending→held; APPROVED+passing→resolved; review feedback wins; absent CI unchanged — poller.test.ts.
  • CI_FAILED resumes with the fix-CI brief, not the address-review one — implementation-workflow.test.ts.
  • Full suite 587 pass, lint/typecheck/format clean.

Deferred (noted in spec)

Dead/stuck CI → waiting-human needs a pending-past-timeout detector; v1 re-polls a pending PR (cheap — no resume fired) until it reports.

Summary by CodeRabbit

  • New Features

    • PR review decisions now incorporate GitHub CI check status alongside reviewer feedback.
    • Failing CI produces a dedicated "CI failed" resume/decision and tailored guidance; missing CI is treated as non-blocking.
    • Pending CI holds otherwise-resolved reviews until checks complete.
  • Tests

    • Added tests for CI status derivation, gating behavior, and workflow resume integration.

Review Change Stack

A PR isn't reviewable until it builds, so CI standing now participates in the
review verdict (the spec note from the reconcile PR, implemented):

- PrSnapshot carries a collapsed `ci` (deriveCiStatus over statusCheckRollup:
  any failure → failing, else any unfinished → pending, else passing; no checks
  → none). findPrForEpic fetches it.
- classifyReviewOutcome is CI-gated: explicit review feedback still wins; else
  failing CI resumes to fix it (CI_FAILED decision); an APPROVED/0-actionable
  verdict while CI is pending is held (null) so the loop never ends on an
  un-built PR; passing/none resolves. Absent CI is non-blocking — the pre-CI
  review loop is unchanged.
- The resume brief branches on CI_FAILED: a fix-CI brief (pull failing checks
  via gh, fix the cause, push once) distinct from the address-review brief.

Deferred (noted in spec): dead/stuck-CI → waiting-human needs a pending timeout.
@thejustinwalsh

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e4488cd-e582-444b-94c1-cf28ef56f89e

📥 Commits

Reviewing files that changed from the base of the PR and between f01a7c8 and d2466cc.

📒 Files selected for processing (2)
  • packages/dispatcher/src/poller-gateway.ts
  • packages/dispatcher/test/poller-gateway.test.ts

📝 Walkthrough

Walkthrough

Integrates GitHub CI check status into the dispatcher's PR polling and review resume loop: adds deriveCiStatus() to normalize statusCheckRollup, embeds ci in PR snapshots, gates classifyReviewOutcome on CI (failing → CI_FAILED changes-requested; pending → hold), and adds CI-failure resume briefs in the workflow.

Changes

CI Status Gating for PR Review Loop

Layer / File(s) Summary
CI Status Extraction from GitHub
packages/dispatcher/src/poller-gateway.ts, packages/dispatcher/test/poller-gateway.test.ts
Adds CheckRollupEntry and deriveCiStatus() to normalize GitHub statusCheckRollup into `"none"
CI-Gated Review Classification
packages/dispatcher/src/poller.ts, packages/dispatcher/test/poller.test.ts
Adds CiStatus and ci?: CiStatus to PrSnapshot, defines CI_FAILED_DECISION, and refactors classifyReviewOutcome() to apply CI gating: explicit CHANGES_REQUESTED still wins; failing CI yields a synthetic changes-requested with CI_FAILED_DECISION; pending CI holds otherwise-resolved outcomes. Tests cover all CI scenarios and precedence.
Workflow Resumption on CI Failure
packages/dispatcher/src/workflows/implementation.ts, packages/dispatcher/test/implementation-workflow.test.ts
Imports CI_FAILED_DECISION and adds a CI_FAILED_DECISION branch in writeResumeBrief() to emit a CI-fix resume prompt (round/cap and steps) and skip the address-review brief. E2E test verifies the CI-failure resume path and subsequent approval completion.

Sequence Diagram(s)

sequenceDiagram
  participant Poller
  participant Gateway as gh_pr_view
  participant GitHub
  Poller->>Gateway: request PR view with statusCheckRollup
  Gateway->>GitHub: fetch PR checks
  GitHub-->>Gateway: statusCheckRollup array
  Gateway->>Gateway: deriveCiStatus(rollup)
  Gateway-->>Poller: PrSnapshot { ..., ci }
Loading
sequenceDiagram
  participant Poller
  participant Classifier as classifyReviewOutcome
  participant Snapshot
  Poller->>Classifier: classifyReviewOutcome(snapshot)
  Classifier->>Snapshot: read review verdicts
  Classifier->>Snapshot: read ci
  Note over Classifier,Snapshot: CHANGES_REQUESTED -> return review verdict
  Note over Classifier,Snapshot: ci == failing -> return changes-requested with CI_FAILED_DECISION
  Note over Classifier,Snapshot: ci == pending -> return null (hold)
  Note over Classifier,Snapshot: else -> apply review-only classification
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

dogfood

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main change: CI status now gates review readiness, and failing CI resumes the PR for a fix.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

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.

@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: 1

🤖 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 `@packages/dispatcher/src/poller-gateway.ts`:
- Around line 23-24: STATE_OK currently includes "EXPECTED", causing
deriveCiStatus to treat StatusState.EXPECTED as passing; remove "EXPECTED" from
the STATE_OK set (or only include "SUCCESS" and "EXPECTED" must not be
considered OK) and update deriveCiStatus so that it treats entries with state
=== "EXPECTED" as pending (similar to how "PENDING" is handled). Then add a unit
assertion to the existing test "legacy StatusContext entries (state) are read
too" that calls deriveCiStatus([{ state: "EXPECTED" }]) and expects "pending" to
ensure the behavior. Reference: STATE_OK constant and deriveCiStatus function
and the existing test name to locate where to change and add the assertion.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 846eb745-6b16-4b1e-b442-2ec51f16fa10

📥 Commits

Reviewing files that changed from the base of the PR and between 4b36e81 and f01a7c8.

📒 Files selected for processing (6)
  • packages/dispatcher/src/poller-gateway.ts
  • packages/dispatcher/src/poller.ts
  • packages/dispatcher/src/workflows/implementation.ts
  • packages/dispatcher/test/implementation-workflow.test.ts
  • packages/dispatcher/test/poller-gateway.test.ts
  • packages/dispatcher/test/poller.test.ts

Comment thread packages/dispatcher/src/poller-gateway.ts Outdated
CodeRabbit on #141: deriveCiStatus put EXPECTED in STATE_OK, so an expected-but-
not-yet-reported status read as a green gate. EXPECTED means a status is awaited
and not final — treat it as pending (like PENDING); only an actual SUCCESS is
passing.
@thejustinwalsh

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

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.

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.

1 participant