Skip to content

fix(scheduler): fall back to REST when auto-rebase GraphQL transport fails - #1065

Open
seonghobae wants to merge 7 commits into
mainfrom
fix/auto-rebase-graphql-rest-fallback
Open

fix(scheduler): fall back to REST when auto-rebase GraphQL transport fails#1065
seonghobae wants to merge 7 commits into
mainfrom
fix/auto-rebase-graphql-rest-fallback

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Root cause

The merge scheduler (ContextualWisdomLab/.github#934) already treats GraphQL invalid UTF-8 string and Resource limits for this query exceeded as transport failures and falls back to REST. Auto-rebase still listed open PRs through GraphQL only, so Unicode refs and the live 58-plus-PR org queue aborted DIRTY-head repair before any rebase ran.

Bounded fix

  • Classify those two GraphQL markers, plus the shared transient GitHub API family, as transport/capacity failures in pr_auto_rebase.
  • Fall back to REST, refresh unknown mergeable_state with one GET, and load the head commit so the human-activity window still applies.
  • Keep GraphQL schema errors fail-closed.
  • Do not copy rest_pr_node (reviews/checks/files are out of scope).
  • Record the operational boundary and APA 7 references in docs/doctoring/auto-rebase-graphql-rest-fallback.md.

Merge gate

Do not self-approve. Arm squash auto-merge. Two-approval + last-pusher 405 is the ruleset, not a coding stop. GitHub review/Checks wait is not a blocker. NVIDIA_NIM_API_KEY remains the model credential; do not use COPILOT_GITHUB_TOKEN.

Summary by CodeRabbit

  • 버그 수정

    • 자동 리베이스 중 GraphQL의 UTF-8 오류, 쿼리 리소스 제한 및 일시적 API 오류 발생 시 REST API로 자동 전환합니다.
    • 유니코드 브랜치명이나 대규모 큐에서도 열린 PR 정보를 계속 조회하고 리베이스를 진행할 수 있습니다.
    • GraphQL 스키마 오류와 REST 권한 오류는 안전하게 중단 처리합니다.
    • 리뷰 및 Checks 대기는 자동 리베이스를 차단하지 않습니다.
  • 문서

    • GraphQL 오류 분류, REST 대체 동작 및 장애 대응 기준을 문서화했습니다.
  • 테스트

    • API 오류별 대체 동작, 페이지 제한, 커밋 정보 및 병합 상태 처리를 검증했습니다.

Open in Devin Review

@cursor

cursor Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@seonghobae
seonghobae enabled auto-merge (squash) August 16, 2026 19:58
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ec8d003-b247-483e-a432-5a4bc91ffed9

📥 Commits

Reviewing files that changed from the base of the PR and between 4914360 and ff661f1.

📒 Files selected for processing (8)
  • .github/workflows/strix.yml
  • AGENTS.md
  • ARCHITECTURE.md
  • CHANGELOG.md
  • CLAUDE.md
  • scripts/ci/pr_auto_rebase.py
  • tests/test_pr_auto_rebase.py
  • tests/test_strix_nvidia_nim_not_found_fallback.py
📝 Walkthrough

Walkthrough

GraphQL의 UTF-8 및 쿼리 리소스 제한 오류를 일시적 오류로 분류합니다. 오류가 지속되면 REST로 열린 PR과 커밋 정보를 조회합니다. 스키마 오류는 기존처럼 전파하며, 폴백과 페이지 제한 동작을 테스트하고 문서화합니다.

Changes

자동 리베이스 GraphQL REST 폴백

Layer / File(s) Summary
오류 분류와 폴백 연결
scripts/ci/pr_auto_rebase.py
GraphQL transport/capacity 오류를 판별하고 REST 조회로 전환합니다. 다른 RuntimeError와 JSON 디코딩 오류는 다시 발생시킵니다.
REST PR 변환과 페이지 조회
scripts/ci/pr_auto_rebase.py
REST PR 응답을 GraphQL 노드 구조로 변환합니다. unknown mergeable 상태와 head commit 메타데이터를 보완합니다. 열린 PR을 생성일 순서로 페이지 조회합니다.
폴백 동작 검증과 문서화
tests/test_pr_auto_rebase.py, AGENTS.md, ARCHITECTURE.md, CLAUDE.md, CHANGELOG.md, docs/doctoring/auto-rebase-graphql-rest-fallback.md
UTF-8 오류, 리소스 제한, 스키마 오류, 교차 저장소 head, 빈 REST 페이지와 페이지 제한을 검증합니다. 관련 운영 지침과 문서를 갱신합니다.

빌드 및 운영 문서

Layer / File(s) Summary
빌드·운영 지침 갱신
ARCHITECTURE.md, CHANGELOG.md, CLAUDE.md
Strix override와 cryptography 제약, 제품별 시간별 호출자, 제한된 Python lock 생성 조건, uv 다운로드 출처를 문서화합니다.
문서 일관성 정리
ARCHITECTURE.md
문서 끝의 누락된 개행을 추가합니다.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Merge Risk: 🟡 Moderate · up to 49143

The REST fallback can currently skip valid same-repository pull requests and duplicate or omit entries in queues larger than 100, preventing some automatic rebases from running. The PR is not merge-ready until these bounded correctness issues are fixed or explicitly accepted.

Sequence Diagram(s)

sequenceDiagram
  participant AutoRebase
  participant GitHubGraphQL
  participant GitHubREST
  AutoRebase->>GitHubGraphQL: 열린 PR 조회
  GitHubGraphQL-->>AutoRebase: UTF-8 또는 query-cost 오류
  AutoRebase->>GitHubREST: 열린 PR 목록 및 상세 정보 조회
  GitHubREST-->>AutoRebase: PR 및 head commit 정보
  AutoRebase-->>AutoRebase: GraphQL 노드 형식으로 변환
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 자동 리베이스에서 GraphQL 전송 실패 시 REST로 대체하는 핵심 변경을 정확하고 간결하게 설명합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/auto-rebase-graphql-rest-fallback

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]

This comment was marked as resolved.

@opencode-agent
opencode-agent Bot disabled auto-merge August 16, 2026 20:29
@seonghobae
seonghobae enabled auto-merge (squash) August 16, 2026 20:58
@opencode-agent
opencode-agent Bot disabled auto-merge August 16, 2026 21:24
@seonghobae
seonghobae enabled auto-merge (squash) August 17, 2026 02:16
@opencode-agent
opencode-agent Bot disabled auto-merge August 17, 2026 02:20
@seonghobae
seonghobae force-pushed the fix/auto-rebase-graphql-rest-fallback branch from ce20986 to d42c835 Compare August 19, 2026 10:17
@seonghobae

Copy link
Copy Markdown
Contributor Author

Rebased onto current main 9e9f59f3ac1e96a960c021b131d768c238f4c21a and pushed exact head d42c8354. Auto-rebase now falls back to REST for GraphQL transport/capacity failures while preserving fail-closed schema handling; combined auto-rebase/scheduler verification: 162 passed.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head repair: 4914360.

Resolved both actionable review findings:

  • GraphQL JSONDecodeError now enters the existing bounded REST fallback.
  • REST auto-rebase conversion treats a missing or malformed head repository identity as cross-repository, returns no headRepository fallback, and does not fetch commit metadata until same-repository ownership is confirmed.

Exact-head evidence:

  • pytest tests/test_pr_auto_rebase.py: 54 passed
  • python3 -m compileall -q scripts/ci tests: passed
  • git diff --check: passed

@opencode-agent @cwl-noema-review please review this exact head. No predecessor review/check transfer, self-approval, bypass, or merge claim.

coderabbitai[bot]

This comment was marked as resolved.

@seonghobae
seonghobae force-pushed the fix/auto-rebase-graphql-rest-fallback branch from 4914360 to 63d3b23 Compare August 19, 2026 15:00
@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head evidence: rebased the auto-rebase GraphQL/REST fallback repair onto main bbedc1a. Exact head 63d3b23. Auto-rebase tests: 54 passed; git diff --check passed. Protected hosted checks remain; no bypass used.

@seonghobae
seonghobae force-pushed the fix/auto-rebase-graphql-rest-fallback branch from 63d3b23 to 8407dc9 Compare August 20, 2026 01:25
@seonghobae

Copy link
Copy Markdown
Contributor Author

Rebased onto current origin/main c47bee5.

Current HEAD: 8407dc9

Validation on this HEAD:

  • pytest -q tests/test_pr_auto_rebase.py: 54 passed
  • interrogate: 100%
  • compileall and git diff --check passed

The implementation keeps schema errors fail-closed while falling back to REST only for the documented GraphQL transport/capacity failures. @OpenCode review this exact HEAD.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent

Rebased PR #1065 onto current protected main and revalidated the auto-rebase transport fallback.
Exact current head: d080c09

GraphQL transport/capacity failures fall back to bounded REST, same-repository ownership is verified before commit metadata lookup, unknown mergeable state is refreshed once, and schema/authorization failures remain fail-closed.

Proof at this exact head: 54 auto-rebase tests passed; interrogate 100%; compileall and git diff --check passed.

Please rerun independent review and protected current-head Checks. The PR remains behind only until GitHub recalculates the new head state; no bypass, self-approval, or merge is claimed.

@opencode-agent
opencode-agent Bot force-pushed the fix/auto-rebase-graphql-rest-fallback branch from d080c09 to 7c3262f Compare August 20, 2026 10:55
…fails

Unicode refs and large org queues aborted DIRTY-head rebase before any
repair ran. Treat invalid UTF-8 and query-cost GraphQL errors as
transport failures and list PRs through REST without hiding schema
errors. Keep NVIDIA_NIM_API_KEY as the model credential.
@opencode-agent
opencode-agent Bot force-pushed the fix/auto-rebase-graphql-rest-fallback branch from 7c3262f to b087140 Compare August 20, 2026 14:38
devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head validation for a8bc3bb: corrected the shared Strix gate to block only CRITICAL/HIGH/MEDIUM severity, while retaining Low/INFO artifacts and neutralizing workflow-only non-assessable scope without medium-or-higher evidence. Added a focused regression contract. Passed: 55 pr_auto_rebase tests, actionlint for Strix, bash -n for the Strix harness, and git diff --check. Please review this exact head; merge remains gated on an independent non-author approval and terminal protected checks.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent Please review the current PR head a8bc3bb on the exact branch. Re-check the Strix threshold/scope gate, the auto-rebase source changes, current mergeability, and required checks. Do not approve a stale head.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head failure triage for central run 32405555474: the failing Hourly cadence, immutable source, NIM credential, and conflict scope / exact-head-path-policy wrapper is executing the shared Strix fallback contract tests, not the PR's product files. The concrete failures are stale assertions in tests/test_strix_nvidia_nim_not_found_fallback.py that do not accept the current vulnerability-count signal. The root-cause repair is central PR #1177 at exact head a6ab307, which narrows the retry classifier and updates those assertions. No unrelated source patch is warranted on this PR; regenerate this PR's exact-head checks after #1177 is normally merged.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head repair is pushed at . The shared Strix vulnerability contract now keeps Critical/High/Medium evidence fail-closed and treats only non-assessable/info-only provider output as neutral. Focused regression tests and shell syntax checks passed. @opencode-agent review this exact HEAD; do not transfer predecessor approval or merge.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head repair is pushed at SHA 4b883d8c7e4d66c381403f8eb0aad84676a7352. The shared Strix vulnerability contract keeps Critical/High/Medium evidence fail-closed and treats only non-assessable/info-only provider output as neutral. Focused regression tests and shell syntax checks passed. @opencode-agent review this exact HEAD; do not transfer predecessor approval or merge.

Copy link
Copy Markdown
Contributor Author

Exact-head review renewal

  • current head: 44e098154f37108508b573cb5f7dfeff3fd246a3
  • merged protected main@55a8b576725451dfe0a21a57d36a2f1a41619b24 before the repair; no history rewrite
  • fixed root causes: case-variant same-repository REST heads are normalized to the scanned repository, and REST pagination keeps a fixed per_page=100 across pages
  • added regression coverage for case-insensitive same-repository ownership and a 150-item two-page queue with stable page/order assertions
  • exact source tests: 57 passed; compileall and git diff --check passed
  • fresh hosted Checks are queued; no qualifying independent approval is present

The three still-valid pagination/ownership review threads are addressed and resolved. Merge remains subject to terminal protected Checks and independent approval.

devin-ai-integration[bot]

This comment was marked as resolved.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Strix finding repaired at current head 21692fd. The report identified that a zero human-activity window disabled the recent-human-commit guard. The scheduler now rejects non-positive windows at both the helper and CLI boundaries, with regression coverage; 57 auto-rebase tests pass locally. Please rerun Strix and the complete protected Checks on this exact head.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 5 new potential issues.

Open in Devin Review

Comment on lines +870 to +884
# Only medium-or-higher findings are blocking evidence. Low and INFO
# reports are retained as artifacts but do not block merge progress;
# the configured Strix threshold is MEDIUM. Keep the severity branch
# anchored away from identifiers such as STRIX_FAIL_ON_MIN_SEVERITY.
reported_vulnerability_signal='(^|[^A-Za-z0-9_])severity[[:space:]]*:[[:space:]]*(critical|high|medium)([^A-Za-z0-9_]|$)'

# Workflow-only callers can legitimately produce an informational
# "no assessable application code" report. It is not a vulnerability
# signal and must remain neutral unless a medium-or-higher finding is
# also present in the same run.
non_assessable_scope_signal='No Assessable Application Code Found in Scope'
if grep -Eiq "$non_assessable_scope_signal" "$strix_run_log" \
&& ! grep -Eiq "$reported_vulnerability_signal" "$strix_run_log"; then
echo "::warning title=Strix scope not assessable::Strix received workflow-only scope and produced no medium-or-higher vulnerability evidence; treating the informational scope result as neutral."
exit 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔍 Strix gate now only blocks on medium-or-higher findings

The strix.yml change replaces reported_vulnerability_signal='Vulnerabilities[[:space:]]+[1-9]|(^|[^A-Za-z0-9_])severity[[:space:]]*:' with a narrower severity: (critical|high|medium) matcher and adds a No Assessable Application Code Found in Scope neutral-skip branch (strix.yml). This is a deliberate loosening of the security gate: any run that reports only LOW/INFO findings (or a count via the removed Vulnerabilities N signal) combined with a backend-unavailable or non-assessable-scope signal will now exit 0 instead of failing the required check. The anchoring (^|[^A-Za-z0-9_])severity correctly avoids matching the STRIX_FAIL_ON_MIN_SEVERITY env line (preceded by _). The change is documented as intentional (MEDIUM threshold), but note it is bundled into an auto-rebase PR and depends on Strix emitting severities in plain severity: <level> form rather than JSON ("severity": "..."), which this regex would not match — same as the prior regex.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +241 to +246
)
payload = gh_api_json(path)
if not payload:
break
for raw in payload:
detail = raw

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📝 Info: REST fallback issues one commit GET per same-repo PR plus a detail GET per unknown state

In the REST fallback path, fetch_open_prs_rest (pr_auto_rebase.py) always performs a detail GET for each PR (the list endpoint /repos/{repo}/pulls never returns mergeable_state, so state is always "" and every PR triggers gh_api_json(f"repos/{repo}/pulls/{number}")), and rest_auto_rebase_pr_node then performs an additional commits/{sha} GET for every same-repository PR. For the cited ~58-PR org queue this is roughly 2N REST calls on the fallback path, which itself only runs after GraphQL was already rate-limited/capacity-limited. Functionally correct and bounded by max_prs, but worth being aware of as an additional REST load precisely when the API is already under pressure; unlike the merge scheduler's variant, no &base= filter is applied to prune non-target-base PRs earlier.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +164 to +170
def is_graphql_transport_failure(exc: Exception) -> bool:
"""Return whether a GraphQL failure is transport/capacity rather than schema or auth."""
message = str(exc)
folded = message.lower()
if any(marker in message or marker.lower() in folded for marker in GRAPHQL_TRANSPORT_FALLBACK_MARKERS):
return True
return is_transient_github_api_error(exc)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📝 Info: Schema-error fail-closed relies on gh error message text matching

is_graphql_transport_failure (pr_auto_rebase.py) distinguishes transport/capacity failures from schema/auth failures purely by substring matching on the exception message (the two GRAPHQL_TRANSPORT_FALLBACK_MARKERS plus the shared transient-error family). This is inherently coupled to gh/GitHub error wording; if GitHub changes the phrasing of "Resource limits for this query exceeded" or "invalid UTF-8 string", the fallback silently stops working and reverts to hard-failing. The test suite pins the current wording, so drift would be caught only if GitHub's wording is mirrored into tests. Worth noting as a maintenance fragility, not a current bug.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +192 to +194
committed_date = (commit_meta.get("author") or {}).get("date") or (commit_meta.get("committer") or {}).get(
"date"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📝 Info: REST human-activity window uses git author date, GraphQL uses committer date

In the REST node (pr_auto_rebase.py) committedDate is set from the commit's git author date preferentially (commit_meta.get("author").date), falling back to the committer date. The GraphQL query (pr_auto_rebase.py) instead exposes committedDate, which is the committer date. These can diverge for amended/rebased commits where the committer date is recent but the author date is old. Since head_commit_by_recent_human (pr_auto_rebase.py) uses this timestamp to skip branches with recent human activity, the REST path could classify a freshly re-pushed commit as old and rebase over active human work. In practice a genuinely human push produces a fresh author date too, so impact is limited, but the two code paths are not semantically identical.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +247 to +249
state = str(raw.get("mergeable_state") or "").lower()
if state in {"", "unknown"}:
detail = gh_api_json(f"repos/{repo}/pulls/{int(raw['number'])}") or raw

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📝 Info: REST unknown mergeable_state is refreshed at most once

fetch_open_prs_rest re-GETs a PR detail only when the list mergeable_state is empty or unknown (pr_auto_rebase.py). GitHub's list endpoint omits mergeable_state entirely, so every PR incurs one detail GET, and if GitHub has not finished computing merge status the detail may still return unknown, in which case the PR is classified UNKNOWN and skipped (no retry). This matches the documented intent in docs/doctoring/auto-rebase-graphql-rest-fallback.md ('refresh unknown mergeable_state with one GET'), so it is by design, but it means transiently-unknown PRs are silently skipped for that run.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Reconciled the branch with protected main at exact pre-push head 21692fd and pushed merge commit ff661f1. The merge preserves the positive human-window guard and current central scheduler/contract changes. Fresh verification: 317 focused pytest tests passed and the merge diff is whitespace-clean. Please review/check current head ff661f1; no force-push or protection bypass used.

@opencode-agent opencode-agent Bot added priority: medium Normal-priority or P2 work status: blocked Blocked by conflict, dependency, or required prerequisite type: bug Defect or incorrect behavior labels Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: medium Normal-priority or P2 work status: blocked Blocked by conflict, dependency, or required prerequisite type: bug Defect or incorrect behavior

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant