fix(ci): close HTTP error response bodies - #1879
Conversation
Signed-off-by: Seongho Bae <me@seonghobae.me>
|
Warning Review limit reachedNext included review available in 13 minutes. View limit detailsLimit 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. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (11)
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. Comment |
#1883) The admission-controller feature burst (#1859-#1869) shipped review_admission_controller.py, pr_review_merge_scheduler_core.py's SchedulerAdmissionGate, and (separately, pre-existing) a coverage gap in audit_codeql_default_setup_rollout.py without full test coverage or docstrings, breaking the required 100% coverage/docstring gate for every PR in this repository regardless of that PR's own diff. The original fix for this landed on .github#1871, which was later closed in favor of narrower successors (#1877 for the stale schedule oracles, #1879 for HTTP error response bodies) -- but the coverage and docstring portion of #1871's delta was dropped in that narrowing and never reached main. This PR recovers exactly that portion from #1871's still-present branch (fix/hourly-review-repair-callers-cron- format-drift) and completes it: - review_admission_controller.py: 85% -> 100% coverage (new tests/test_review_admission_controller.py), 14 missing docstrings added across its WorkerBoundary/AdmissionRequest/RequestRecord/ DispatchLease/ControllerState/DispatchPlan dataclasses and methods. - audit_codeql_default_setup_rollout.py: 79% -> 100% coverage (new tests/test_codeql_default_setup_rollout.py), 2 missing docstrings added (parse_args, main). - pr_review_merge_scheduler_core.py's SchedulerAdmissionGate: 3 missing docstrings added (__init__ and its two nested closures, lease/reconcile_state). Additionally closed pr_review_merge_scheduler_core.py's own separate, longer-standing coverage gap (98% -> 100%, unrelated to the admission-controller work) discovered while verifying this fix would actually bring main to a green gate rather than a differently-shaped 99%: the durable admission gate's own bounded-budget/stale-head branches across every dispatch call site (9 "admission_deferred" checks across post_update_branch_followup/dispatch_draft_review_only/ inspect_pr, plus dispatch_strix_evidence's own two "admission_deferred"/ "stale_head" pairs), reconcile()'s live-head-moved and still-running branches, rotating_pr_window's/dispatch_draft_review_only's/the workflow-run classifier's/the empty-PR-close path's/main()'s own --admission-state-path wiring's remaining gaps, and two untestable package-import fallback lines marked `# pragma: no cover - package import path` matching this file's established convention for that exact pattern. Full local triad: 2875 passed, 1 skipped; coverage 100%; interrogate 100%. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…pline (#1909) Two rules from mistakes this session actually made and corrected, per the per-session lane split agreed with the other concurrent sessions (peer 3 took verification discipline in #1907; peer 2 has gate/merge mechanics; host 1 has close-time diff comparison and noema concurrency; host 2 has CI failure diagnosis). - Narrowing a PR does not carry its delta. #1871 was closed in favor of #1877 plus #1879; both successors were green, but neither carried the coverage/docstring delta, leaving main's required 100% gate broken until #1883 recovered it. "Each piece works" and "the pieces together cover the original's scope" are different questions. - Compare content, not ancestry. main mixes squash and merge commits (last 200: 153 single-parent, 47 two-parent, counted directly), so `git merge-base --is-ancestor` gives false negatives for squashed deltas and false positives for reverted merge-commit deltas. - Never endorse a timeout or retry constant on a model-invocation path without reading docs/product-goal-directive.md section 8, which accepts more than two hours per model and states speed is not a core consideration. #1889/#1890/#1892 each capped a model step at 900s on real multi-hour-hang evidence and were all reverted (#1891, #1895). Every PR number, the section-8 quotes, the parent-count distribution, and the 100% gate values were verified against the repository directly. An earlier draft of the timeout bullet cited a section number that does not exist and attributed a sentence to that file which appears only in #1891's PR body; both were caught by grepping rather than trusting the summary that introduced them, and that failure is recorded in the text. Full suite: 2883 passed, 1 skipped. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Noema LLM review
The PR correctly and safely closes HTTP error response bodies across four scripts using HTTPError.close(), which is idempotent and prevents resource leaks (file descriptors, connections). Each code change is accompanied by a regression test asserting the response body is closed. The changes are narrowly scoped, preserve existing behavior for non-HTTP errors, and introduce no correctness, security, or maintainability regressions. The only minor gap is that test_repository_metadata_live_verification.py does not cover the plain URLError (non-HTTP) branch, but that branch is unchanged by this PR, so it is non-blocking.
Reviewed changed lines
scripts/ci/noema_review_gate.py:1639 (RIGHT): Thefinallyblock guaranteesexc.close()is called even if_extract_http_error_telemetryraises. CPython'sHTTPError.close()is idempotent and closes the underlyingfp. The new testtest_call_llm_reports_only_safe_model_from_bounded_http_errorassertsresponse_body.closed, confirming the resource is released. The exception handling path is otherwise unchanged.scripts/ci/pingora_edge_policy.py:307 (RIGHT): Theisinstance(exc, HTTPError)check andexc.close()before re-raisingPolicyErrormatch CPython semantics. The testtest_github_open_json_raises_policy_error_for_transport_errorsassertsexc.fp.closed. Non-HTTPURLErrorandTimeoutErrorpaths are unaffected.scripts/ci/reconcile_repository_metadata.py:251 (RIGHT):HTTPErroris a subclass ofURLError, so theisinstanceguard correctly catches redirected 302 cases from_NoPagesRedirects. Theexc.close()call is idempotent; the new testtest_pages_transport_error_closes_response_bodyverifiesbody.closed. Non-HTTPURLError/timeout/OSError branches are untouched.scripts/ci/sandboxed_web_e2e.py:587 (RIGHT): Theexcept (urllib.error.URLError, TimeoutError) as excblock now checksisinstance(exc, urllib.error.HTTPError)and callsexc.close()before sleeping. This matches CPython'sHTTPError.close()semantics. The new testtest_wait_for_url_closes_http_error_responseassertsbody.closed. Retry and sleep logic are unchanged for other error types.tests/test_repository_metadata_live_verification.py:67 (RIGHT): The test constructs anHTTPErrorwith aBytesIObody and verifiesbody.closedafter_pages_publication_readyraises aRuntimeError. It exercises theHTTPErrorbranch of the newexc.close()logic. The non-HTTPURLErrorbranch is not covered here, but that branch was not modified by this PR.
Adversarial validation
scripts/ci/noema_review_gate.py:1639 (RIGHT)falsified: Callingexc.close()in afinallyblock could cause a double-close or an exception if_extract_http_error_telemetryalready closed the body. — CPython source (urllib/error.py L94-96) and the added testtest_call_llm_reports_only_safe_model_from_bounded_http_errorwhich assertsresponse_body.closedafter the call.scripts/ci/sandboxed_web_e2e.py:587 (RIGHT)falsified: Closing the HTTP error body in the polling loop could break the retry logic or cause a sleep to be skipped. — The test assertsbody.closedand thatwait_for_urlreturns False after the timeout period, proving the sleep path is unaffected.- Residual risk: Low. The only untested scenario is a plain (non-HTTP) URLError in reconcile_repository_metadata.py, but that code path is unchanged and existing tests cover transport errors broadly. The risk of a resource leak is mitigated by the idempotent close() and the confirmed tests for all HTTPError paths.
Findings
- No blocking findings.
- Result: APPROVE
- Head SHA:
0723a0c7d9d4da82e64f884cff8babf1f0e0c81a - Reviewer credential:
noema-review-github-app-refresh - Actor:
cwl-noema-review[bot]
|
현재 head 0723a0c7d9d4da82e64f884cff8babf1f0e0c81a와 main43024633을 확인했습니다. 기존 수정은 세 요청 소유자의 응답 누수 진단을 통과합니다. 다만 경고 엄격 검사(-W error)에서는 직접 redirect 예외를 만든 테스트 네 곳의 정리 누락으로 4 failed / 260 passed(외부 진단3개 포함)를 재현했습니다. 이 작업(01a06aac-7183-7910-aa64-48e0ae87d955)은 별도 격리 worktree에서 기존8파일 delta를 보존한 최신 main 일반 통합과 close 실패/사용자 취소 회귀를 보완합니다. 신규 PR·강제 갱신·권한 변경은 하지 않습니다. 다른 활성 작성자가 있으면 원격 갱신 전에 알려 주세요. Noema #1641의 schema/리뷰 의미 변경은 이 PR로 복사하지 않습니다. 기존 승인과 Checks는 새 head에 승계하지 않습니다. |
PR #1879의 응답 정리 변경을 최신 main과 정상 통합한다. 네 요청 경계의 정리 실패가 원래 실패를 가리지 않게 하고 직접 만든 redirect 테스트 응답도 닫는다. 새 계약 검사는 12 RED를 재현했으며 전체 후보 검사는 2954 passed, 1 optional skip, branch coverage 100%를 확인했다. Noema #1641의 별도 schema 변경은 포함하지 않는다. Commit-Message-Assisted-by: Codex Signed-off-by: Seongho Bae <me@seonghobae.me>
|
후속 작성 완료·인계: d4366f8 일반 push, main43024633 base와 본문 원문 readback을 확인했습니다. 정확한 커밋에서 일반·GitHub Actions 환경 전체 각각2954 passed/LLVM19부재1skip/21subtests, 문장·분기100%, docstring100%입니다. 현재 source writer 작업은 완료·해제합니다. 새 head의 Checks와 독립 리뷰는 별도 대기 상태이며 이전 승인·실패를 승계하지 않습니다. Noema#1641의schema 기능은 포함하지 않았습니다. 기존 구현·이력은 보존했고 강제 push·수동 재실행·권한 변경·병합은 하지 않았습니다. 자세한 재현12RED→0 및 환경·정리 보장 한계는 갱신된 PR 본문에 있습니다. |
|
Read-only exact-head audit of Independent exact-tree GREEN:
The fixtures exercise ordinary cleanup, Stack finding: #1879 and Draft #1641 ( The active writer claim in comment |
최신 main 통합 검증현재 head는 충돌은 CHANGELOG 첫머리뿐이었으며 양쪽 기록을 모두 보존했습니다. 최신 main 대비 변경은 11개 파일, 199줄 추가·7줄 삭제입니다. CHANGELOG를 제외한 기존·통합 후 변경의 stable patch-id는 모두
이는 로컬 시험 증거이며, 새 head의 hosted Checks·독립 승인·보호 병합을 대신하지 않습니다. 이전 head의 CodeQL dispatch 대기, OpenCode 판정 부재, Strix 사전 점검 실패를 새 head의 성공으로 간주하지 않습니다. Project API 권한 부족과 Mac 잠금으로 이번 변경의 새 Project·브라우저 확인은 수행하지 못했습니다. |
|
현재 head |
|
Noema 637초 실패의 내부 경로를 추가 확인했습니다. artifact 9990082549의 원본 stderr(SHA-256 e0c879d13daa0f73f145d6e58fb3782dc0f1aca3c9b51fb6558edfca3196fe78)에는 TimeoutError 5건과 마지막 circuit_opened → provider_connection_error 502가 있습니다. 마지막 provider_attempt 13:17:07.262에서 실패 13:18:37.342까지는 90.080초입니다. 실제 설치 CO 414f22973658c4ddc3d4320fcf7acd9b4e8ba991의 contextual_orchestrator/orchestrator.py:1696은 기본 timeout=90, :2256은 이를 connection_timeout으로 사용합니다. trusted source 0b0f10476469d52adc40f98495d50855486cd32f의 launcher:1240–1243은 ModelClient에 timeout을 전달하지 않습니다. 담당자의 산출물 분석 뒤 제가 원본 로그·해시와 두 exact-revision 소스를 별도로 확인했습니다. 따라서 묵시적 90초 제한 경로가 이번 실패를 뒷받침합니다. 전체 후보 소진의 완전한 재구성이나 제한 제거 후 정상 verdict까지 증명한 것은 아닙니다. CO canonical owner의 기존 수정에서 이어가며 caller 재실행·유료 fallback·권한 변경은 하지 않았습니다. |
|
Strix 실제 종료 증거 갱신: run34031339200/job101486795855는 2026-09-06 14:54:04 UTC에 failure로 종료됐습니다. 대상 head23eb2833794f829985e3cef81e8da77fe10b91e1. Run Strix quick 단계13:24:19→14:53:58 UTC, 로그는 orchestrator/free after5377s exit1을 기록합니다. OpenAI SDK 경로에서 HTTP500 internal_error가 발생했고 request_id는 5055fdba76e54ecabdb5e741c3c311f5 및 80843d4b38c04131b05d588ecc19b3d1입니다. 이 실행을 900초 wrapper 제한이나 인증 실패로 분류할 근거는 없습니다. wrapper의 provider-unavailable 문구만으로 upstream 원인을 확정하지 않으며 CO 측 trace 연결이 필요합니다. artifact9991542931(strix-reports) 보존 확인. 원본 job log SHA256 783ab7b1ad3ffaba368a3976602d43c67c0831b8e4610671a4a640bcd6b74128. 재실행이나 timeout 변경은 하지 않았습니다. |
현재 변경과 검증
Head:
d4366f837afd9f988707618c6855c1661f81c3f8.Parents: 기존 head
0723a0c7d9d4da82e64f884cff8babf1f0e0c81a+ main43024633eba9d96b0456970391360da5a171fbda.두 부모를 보존한 일반 merge/push이며, 현재 main 대비 11파일 199줄 추가·7줄 삭제입니다. 기존 8파일의 응답 정리·회귀 변경을 유지했습니다.
네 요청 경계에서 응답 정리 오류가 원래 통신 실패를 가리지 않게 했습니다. 정리 한 문장에만 표준 라이브러리를 사용하고
KeyboardInterrupt·SystemExit는 전파합니다. 직접 redirect 예외를 만든 네 기존 테스트도 응답을 닫습니다. 새 클라이언트·의존성·재시도·경고 필터는 없습니다. URL·프록시·리다이렉트 차단, 모델 제한 시간, 권한·리뷰 의미 검증은 바꾸지 않았으며 #1641의 schema 기능을 복제하지 않았습니다.재현과 정확한 커밋 검증
OSError·ValueError·RuntimeError정리 실패를 주입하면 원래 결과가 사라졌습니다.GITHUB_ACTIONS=true전체 검사: 2954 passed, 1 skipped, 21 subtests passed, 112.37초.-W error, 문장 13197/13197, 분기 5332/5332, 100% coverage.interrogate scripts/ci도 **100%**이며 whitespace 검사는 통과했습니다.JUnit SHA-256:
81ea82402292471832c132c681eda201e54e3e2b8eb93c747fc4b7b55e0ac07a932f2c11c0c858901f0db789fff5e776b6752d9aba10e8f271ca06cb53f594b81ff8ec5af9c21691f4df9f5672413590db7ebbc658f651423177ef1226c4725f증거 한계와 인계
독립 읽기 전용 검토에서 요청 소유권·취소·기존 delta 보존·schema 비복제를 확인했습니다. 이는 GitHub 승인이 아닙니다. 정리 전에 구현 자체가 실패하는 경우 모든 운영체제 자원의 해제까지 보장하지 않습니다. 테스트의 닫힘 assertion은 정상/정리 후 실패 경우를 증명하며, 이 한계를 기존 doctoring 문서에 명시했습니다.
이전 head의 OpenCode 실패는 exact-head formal verdict 부재, CodeQL은 비동기 terminal verdict 대기, Strix는 provider/backend 사용 불가였습니다. metadata 전체 검사 실패 17개는 최신 main의 scheduler fixture 수리와 구분했습니다. 이전 성공·실패·승인은 새 head에 승계하지 않습니다. 현재 head의 실제 공급자 호출, required Checks, 독립 승인, 보호 병합은 별도이며 아직 병합하지 않았습니다. principal/규칙/토큰 범위 변경이나 수동 재실행은 하지 않았습니다.
Project #1의 별도 상태 갱신은 조회 권한이 없어 확인하지 못했습니다. 정확한 head와 본 PR의 검증 영수증으로 인계합니다.
이전 본문 보존 — 현재 head의 검증 아님
Summary
Verification
git diff --checkpytest -q tests/test_noema_review_gate.py tests/test_pingora_edge_policy.py tests/test_repository_metadata_live_verification.py tests/test_sandboxed_web_e2e.py— 261 passedReplaces the only substantive runtime fixes from #1871 without its unrelated 928-line coverage/docstring expansion.