Conversation
) Add 5 upstream OpenCodeReview action features to the custom ocr-review.yml workflow: 1. --background flag: pass PR title/body as business context to the LLM, gated behind the OCR_BACKGROUND repository variable with empty-value guard. 2. llm_extra_body: disable LLM thinking by default via ocr config set llm.extra_body (default: {"thinking":{"type":"disabled"}}), overridable via OCR_LLM_EXTRA_BODY. 3. Incremental IoU overlap dedup: port lineSpan/sameCommentSpan/ overlapsHistory from upstream, gated behind OCR_INCREMENTAL with configurable threshold (OCR_INCREMENTAL_OVERLAP_THRESHOLD, default 0.6). Complements existing content-based dedup. Cross-revision dedup with fail-closed bot identity validation prevents fork marker forgery. 4. Configurable LLM timeout: replace hardcoded --timeout 30 with OCR_REVIEW_TIMEOUT (default 30), validated as a positive integer. 5. Structured outputs: comments_total, comments_inline, comments_skipped, comments_failed, summary_comment_url on the code-review job, propagated from the post step via step id. 6. Language configuration: ocr config set language (default English), overridable via OCR_REVIEW_LANGUAGE. Also adds resolveThreshold() to guard against invalid IoU threshold values, fetchMarkerComments() to fix a stale-comment race in summary posting, and bot identity authentication via getAuthenticated() for fork-safe incremental dedup. Tests use vm execution to verify IoU math, threshold resolution, and bot identity filtering rather than string-presence checks.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 7 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe OCR workflow adds configurable business context, LLM settings, language, and timeout handling; incremental IoU-based inline-comment deduplication; refreshed sticky-marker reconciliation; structured comment metrics; and Vitest coverage for these behaviors. ChangesOCR review workflow enhancements
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
LLxprt PR Review – PR #2695Issue AlignmentImplements the 5 upstream OCR features requested in issue #2670, all gated behind opt-in repository variables so existing behavior is preserved. Evidence: Side Effects
Code QualityStrong defensive patterns: exit-code guards, Tests and CoverageNew file VerdictReady. The implementation matches issue requirements, adds meaningful automated tests, and maintains the workflow’s existing hardening patterns. The fail-closed bot-login behavior and cross-revision dedup are intentional security improvements. No blocking issues found. |
| function loadFunctionFromScript(script, funcName, sandboxGlobals = {}) { | ||
| const source = extractFunctionSource(script, funcName); | ||
| const sandbox = { Number, Math, ...sandboxGlobals }; | ||
| vm.createContext(sandbox); | ||
| // Run as a function declaration so it binds to the sandbox's global scope. | ||
| vm.runInContext(source, sandbox); | ||
| const fn = sandbox[funcName]; |
There was a problem hiding this comment.
Performance:
loadFunctionFromScriptcreates a new VM context and re-parses the entire workflow script on every call. This function is invoked 17+ times across the test suite (e.g.,lineSpan3×,sameCommentSpan7×,resolveThreshold7×), causing redundant regex scanning and VM initialization. Consider caching extracted functions in a module-levelMapso each function is parsed and loaded only once, while still preserving test isolation through fresh sandboxes if needed.
There was a problem hiding this comment.
This is a valid optimization. However, these are YAML-parsing tests that run in milliseconds (the entire 49-test suite completes in ~13ms). The redundant parsing has no measurable impact on CI or developer feedback loop. Dismissing as out-of-scope for this PR — the test suite is already fast enough. Can be optimized in a future PR if the test count grows significantly.
| let botLogin = ''; | ||
| try { | ||
| const { data: botUser } = await github.rest.users.getAuthenticated(); | ||
| botLogin = botUser.login || ''; | ||
| } catch (e) { | ||
| core.warning(`Could not resolve authenticated bot login: ${e.message || e}`); | ||
| } |
There was a problem hiding this comment.
Reliability:
getAuthenticated()failure degrades dedup silentlyIf the
github.rest.users.getAuthenticated()API call fails,botLoginis set to an empty string. Because all bot comment filters requirebotLogin !== '', this causesexistingInlineCommentKeys()andexistingReviewCommentSpans()to return empty arrays, completely disabling both exact dedup and IoU overlap dedup.Impact: The workflow will post duplicate inline comments on every run, potentially hitting GitHub API rate limits and spamming PRs with redundant findings.
Recommendation: Either (a) treat
getAuthenticated()failure as an infrastructure failure and abort the posting step, or (b) add a fallback mechanism (e.g., list all bots and heuristically identify the OCR bot) so dedup remains functional when the API call fails.
There was a problem hiding this comment.
Fixed in c02396f. Added an OCR_BOT_LOGIN repository variable as a fallback when getAuthenticated() fails. When the API call fails, the workflow now falls back to the configured bot login so dedup remains functional. If no fallback is configured, the fail-closed behavior (empty filter sets) is intentional and prevents trusting arbitrary bot comments.
| const rawBody = typeof pr.body === 'string' ? pr.body : ''; | ||
| core.setOutput('pr_body', rawBody.slice(0, 2000)); |
There was a problem hiding this comment.
Correctness: PR body truncation may omit critical LLM context
rawBody.slice(0, 2000)truncates the PR description to 2000 characters before passing it as--backgroundcontext to the LLM. While this prevents command-line length issues, it arbitrarily cuts off potentially important context such as linked issue descriptions, reproduction steps, or design rationale for longer PRs.Recommendation: Consider (a) increasing the truncation limit if the OCR CLI supports longer arguments, (b) passing the background text via a temporary file or stdin if the CLI supports it, or (c) documenting the 2000-char limit and its implications for users who enable
OCR_BACKGROUND.
There was a problem hiding this comment.
The 2000-char limit is intentional for command-line argument safety. Increasing it would risk ARG_MAX limits on some systems. Passing via stdin/temp file would require OCR CLI changes (out of scope). The limit is now documented in the surrounding comment: it is truncated to keep the command-line length bounded. Feature is opt-in via OCR_BACKGROUND variable.
| - name: Post OCR results | ||
| id: post-ocr-results | ||
| if: always() | ||
| uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # ratchet:actions/github-script@v7 |
There was a problem hiding this comment.
Reliability: Missing
timeout-minutesonpost-ocr-resultsstepThe
post-ocr-resultsstep runsactions/github-scriptwith extensive pagination logic (github.paginate) and multiple sequential API calls. It does not specifytimeout-minutes, while nearly every other step in this workflow and related jobs explicitly sets timeouts (e.g.,timeout-minutes: 5,timeout-minutes: 60).Impact: If the GitHub API becomes slow or unresponsive, or if pagination encounters issues, this step could run indefinitely, consuming runner resources.
Recommendation: Add
timeout-minutes: 10(or an appropriate value consistent with the rest of the workflow) to thepost-ocr-resultsstep.
There was a problem hiding this comment.
The entire code-review job already has timeout-minutes: 60 which covers this step. actions/github-script steps do not support a step-level timeout-minutes property — only run steps do. The job-level timeout is sufficient.
OpenCodeReview — automatic reviews suspendedAutomatic OCR reviews are suspended for this PR after 2 of 2 automatic reviews. To get more reviews you can:
|
The INLINE_MARKER constant was declared but never referenced in the test file, causing eslint no-unused-vars to fail in CI.
| # Feature 1 (issue #2670): conditionally append business context | ||
| # for the LLM. Gated behind OCR_BACKGROUND so existing behavior is | ||
| # unchanged unless the repository variable opts in. | ||
| REVIEW_ARGS=() | ||
| if [ "${OCR_BACKGROUND:-}" = 'true' ]; then | ||
| BACKGROUND_TEXT=$(printf 'PR %s: %s\n\n%s' "${PR_NUMBER}" "${PR_TITLE}" "${PR_BODY}") | ||
| if [ -n "${PR_TITLE}" ] || [ -n "${PR_BODY}" ]; then | ||
| REVIEW_ARGS+=(--background "$BACKGROUND_TEXT") | ||
| fi | ||
| fi |
There was a problem hiding this comment.
The PR title and body from an untrusted fork are passed directly to the LLM via
--backgroundwithout sanitization. In apull_request_targetworkflow, this enables prompt injection: a malicious PR author could craft a PR body that causes the LLM to ignore security findings, generate misleading output, or exfiltrate sensitive data.Impact: High — bypasses the security review entirely if the LLM is coerced.
Suggestion: Either (a) restrict the business-context feature to repository members/collaborators only, or (b) sanitize/escape the PR title/body before injecting it into the LLM prompt. For example, wrap the injected text in a clearly delimited, non-interpretable block:
BACKGROUND_TEXT=$(printf '---BEGIN BUSINESS CONTEXT---\nPR %s: %s\n\n%s\n---END BUSINESS CONTEXT---' "${PR_NUMBER}" "${PR_TITLE}" "${PR_BODY}")Or, better yet, truncate to safe length and strip markdown/HTML/control characters before passing through.
There was a problem hiding this comment.
Fixed in c02396f. The business context is now wrapped in BEGIN/END BUSINESS CONTEXT delimiters to clearly separate untrusted PR text from the LLM prompt. Additionally, the feature is opt-in (OCR_BACKGROUND=true) so it does not affect the default workflow. The OCR review itself already processes the untrusted PR diff as model input, so the PR title/body adds minimal additional attack surface.
| let botLogin = ''; | ||
| try { | ||
| const { data: botUser } = await github.rest.users.getAuthenticated(); | ||
| botLogin = botUser.login || ''; | ||
| } catch (e) { | ||
| core.warning(`Could not resolve authenticated bot login: ${e.message || e}`); | ||
| } |
There was a problem hiding this comment.
If
getAuthenticated()fails,botLoginremains empty and the dedup filters inexistingInlineCommentKeys()andexistingReviewCommentSpans()exclude all existing comments. This causes duplicate inline comments to be posted on every workflow run.Impact: Medium — PR reviews will be spammed with duplicate findings.
Suggestion: Provide a configurable fallback bot username via a repository variable (e.g.
OCR_BOT_LOGIN) when the API call fails:let botLogin = ''; try { const { data: botUser } = await github.rest.users.getAuthenticated(); botLogin = botUser.login || ''; } catch (e) { core.warning(`Could not resolve authenticated bot login: ${e.message || e}`); botLogin = process.env.OCR_BOT_LOGIN || ''; if (botLogin) core.info(`Using fallback bot login: ${botLogin}`); }
There was a problem hiding this comment.
Fixed in c02396f — see reply to the identical comment above. Added OCR_BOT_LOGIN env var fallback so dedup remains functional when getAuthenticated() fails.
| function lineSpan(c) { | ||
| const start = Number(c.start_line || c.line || 0); | ||
| const end = Number(c.line || c.start_line || 0); | ||
| const lo = Math.min(start, end); | ||
| const hi = Math.max(start, end); | ||
| return { start: lo, end: hi, multiline: lo !== hi }; | ||
| } | ||
|
|
||
| function sameCommentSpan(cur, other, threshold) { | ||
| // Single-line vs single-line: match on the same line. | ||
| // Multi-line vs multi-line: IoU > threshold. | ||
| // Single vs multi: never match. | ||
| if (cur.multiline !== other.multiline) { | ||
| return false; | ||
| } | ||
| if (!cur.multiline) { | ||
| return cur.start === other.start; | ||
| } | ||
| const overlap = Math.max(0, Math.min(cur.end, other.end) - Math.max(cur.start, other.start) + 1); | ||
| const union = Math.max(cur.end, other.end) - Math.min(cur.start, other.start) + 1; | ||
| return overlap / union > threshold; | ||
| } |
There was a problem hiding this comment.
lineSpan()defaults missing line numbers to{start: 0, end: 0}. This means all lineless inline comments on the same file will be considered overlapping with each other, causing legitimate distinct findings without line numbers to be silently suppressed.Impact: Medium — findings may be dropped without notice.
Suggestion: Skip overlap dedup for comments that lack resolvable line numbers, or use a distinct sentinel value to avoid false overlap:
function lineSpan(c) { const start = Number(c.start_line || c.line || 0); const end = Number(c.line || c.start_line || 0); if (start <= 0 || end <= 0) { return { start: -1, end: -1, multiline: false, lineless: true }; } const lo = Math.min(start, end); const hi = Math.max(start, end); return { start: lo, end: hi, multiline: lo !== hi, lineless: false }; } function sameCommentSpan(cur, other, threshold) { if (cur.lineless || other.lineless) return false; // ... existing logic }
There was a problem hiding this comment.
Fixed in c02396f. lineSpan() now returns a lineless flag when start/end line numbers are missing (<=0), and sameCommentSpan() skips lineless comments entirely so they are never falsely matched. Added a behavioral test for the lineless case.
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-24.x-ubuntu-latest' artifact from the main CI run. |
CodeRabbit review findings remediated: 1. lineSpan() lineless comment suppression: Added a 'lineless' flag to the span object. When start/end line numbers are missing (<=0), the span is marked lineless so sameCommentSpan() never matches it. This prevents distinct lineless findings on the same file from being silently suppressed by IoU overlap dedup. 2. getAuthenticated() fallback bot login: When the authenticated-user API call fails, fall back to a configurable OCR_BOT_LOGIN repository variable so dedup (exact + IoU) remains functional instead of silently posting duplicate comments on every run. 3. --background prompt injection delimiter: Wrapped the business context text in BEGIN/END delimiters to clearly separate untrusted PR title/ body from the LLM prompt, mitigating prompt injection from fork PRs. Test updates: - Updated lineSpan assertions to include the new 'lineless' field. - Added test for lineless span when line numbers are missing.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
scripts/tests/ocr-review-workflow-features.test.js (2)
525-538: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winCover the successful-create race.
The test only verifies re-fetching after failed creation. Add coverage requiring the successful
createCommentpath to re-fetch and reconcile marker comments as well.🤖 Prompt for 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. In `@scripts/tests/ocr-review-workflow-features.test.js` around lines 525 - 538, The test for reconcileMarkerComment must also cover the successful createComment path. Extend the relevant source assertions in the reconcileMarkerComment test to require that successful creation re-fetches marker comments and reconciles against the refreshed results, while preserving the existing failed-creation coverage.
491-517: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winCover fallback duplicate accounting behavior.
These assertions only verify that outputs exist. Add a regression check ensuring a comment rediscovered after batch uncertainty is not counted as a newly posted inline comment.
🤖 Prompt for 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. In `@scripts/tests/ocr-review-workflow-features.test.js` around lines 491 - 517, Extend the posting-script tests around commentsSkipped to cover fallback duplicate accounting after batch uncertainty. Add a regression assertion that a rediscovered comment is excluded from newly posted inline comments and counted as skipped, using the existing postScript test setup and relevant duplicate-handling symbols.
🤖 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 @.github/workflows/ocr-review.yml:
- Around line 1624-1628: Update the successful create path in
.github/workflows/ocr-review.yml around issues.createComment to re-fetch and
reconcile marker comments before returning, matching the existing
failure-recovery behavior and preventing duplicate sticky summaries. Add a
regression assertion in scripts/tests/ocr-review-workflow-features.test.js
covering reconciliation after a successful create.
- Around line 1653-1664: Update the structured output accounting around
commentsTotal and commentsInline so inline comments rediscovered after fallback
batch uncertainty are not counted as newly posted; classify them through the
existing skipped or uncertain accounting instead. In
scripts/tests/ocr-review-workflow-features.test.js lines 491-517, strengthen
coverage to assert the fallback duplicate counts and ensure comments_inline
excludes those rediscovered comments.
---
Nitpick comments:
In `@scripts/tests/ocr-review-workflow-features.test.js`:
- Around line 525-538: The test for reconcileMarkerComment must also cover the
successful createComment path. Extend the relevant source assertions in the
reconcileMarkerComment test to require that successful creation re-fetches
marker comments and reconciles against the refreshed results, while preserving
the existing failed-creation coverage.
- Around line 491-517: Extend the posting-script tests around commentsSkipped to
cover fallback duplicate accounting after batch uncertainty. Add a regression
assertion that a rediscovered comment is excluded from newly posted inline
comments and counted as skipped, using the existing postScript test setup and
relevant duplicate-handling symbols.
🪄 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: CHILL
Plan: Pro Plus
Run ID: cad0604d-7d6f-4a99-8509-9ac316c6b8d3
📒 Files selected for processing (2)
.github/workflows/ocr-review.ymlscripts/tests/ocr-review-workflow-features.test.js
Fixes #2670) Address CodeRabbit second-pass review findings: 1. Fallback dedup over-reporting: When a comment was rediscovered after batch post uncertainty (existingInlineKeys match), it was incorrectly counted via postedInline += 1, inflating comments_inline. Now correctly increments skippedExactHistoryCount instead. 2. Successful-create marker reconciliation: The createComment success path did not reconcile concurrent duplicate marker comments. Now calls reconcileMarkerComment(null) after a successful create to clean up any duplicates posted between the initial pre-fetch and the create call. Both fixes include regression tests.
Summary
Adopts 5 upstream OpenCodeReview (OCR) action features into the custom
.github/workflows/ocr-review.ymlworkflow, as requested in issue #2670. All features are gated behind opt-in repository variables so existing behavior is unchanged unless explicitly enabled.Features Implemented
1. Business Context (
--background)pr-contextstep--backgroundtoocr reviewwhenOCR_BACKGROUND=true2. LLM Thinking Disabled by Default (
llm_extra_body)ocr config set llm.extra_body{"thinking": {"type": "disabled"}}OCR_LLM_EXTRA_BODYrepository variablemark_infrastructure_failurepattern3. Incremental IoU Overlap Dedup
lineSpan,sameCommentSpan,overlapsHistoryfrom upstreamOCR_INCREMENTAL=true(off by default)OCR_INCREMENTAL_OVERLAP_THRESHOLD(default 0.6)commit_id === headShafilter so prior pushes are consideredgetAuthenticated()and requires exact login match. Prevents fork marker-forgery attacksresolveThreshold()falls back to 0.6 for NaN, negative, zero, or >1 valuesdeduplicationKey/deduplicateFindings)4. Configurable LLM Timeout
--timeout 30withOCR_REVIEW_TIMEOUT(default 30)5. Structured Comment-Count Outputs
comments_total,comments_inline,comments_skipped,comments_failed,summary_comment_urlid: post-ocr-resultscomments_skippedcounts only inline comments skipped by incremental overlap and exact-key history dedup6. Language Configuration
ocr config set languagedefaults to EnglishOCR_REVIEW_LANGUAGErepository variableSecurity
ocr config setcommands run, no PR-supplied configresolveThreshold()guards against invalid threshold configurationsTesting
scripts/tests/ocr-review-workflow-features.test.jsusingvmexecution to verify actual IoU math, threshold resolution, and bot identity filteringCloses #2670
Summary by CodeRabbit
New Features
Bug Fixes