fix(http): retry 425 Too Early on bounded GETs - #71
Conversation
|
Warning Review limit reached
Next review available in: 13 minutes 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?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: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (22)
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 |
|
@coderabbitai review @opencode-agent @cwl-noema-review Review-only request for exact source head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
source_commit='ecb5a82c3170b4b95970a291dafd1adbd90829e2'
base_commit='bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10'
repo='ContextualWisdomLab/pg-llm-batch'
echo '== Repository state and requested commits =='
git rev-parse HEAD
git rev-parse "$source_commit"
git rev-parse "$base_commit"
git merge-base --is-ancestor "$base_commit" "$source_commit" && echo 'BASE_IS_ANCESTOR=yes' || echo 'BASE_IS_ANCESTOR=no'
git show -s --format='source=%H%nparents=%P%nsubject=%s' "$source_commit"
git show -s --format='base=%H%nparents=%P%nsubject=%s' "$base_commit"
echo '== Changed files and change statistics =='
git diff --stat "$base_commit" "$source_commit"
git diff --name-status "$base_commit" "$source_commit"
git diff --numstat "$base_commit" "$source_commit"
echo '== Full PR-range diff =='
git diff --find-renames --find-copies --no-ext-diff "$base_commit" "$source_commit"
echo '== Candidate source, test, and documentation files =='
fd -HI -t f . | sort | sed -n '1,500p'
echo '== Retry-related definitions and call sites =='
rg -n -i -C 5 \
'(retry[-_ ]?after|equal[-_ ]?jitter|retryable|retry.*status|status.*retry|Too Early|HTTP.?425|HTTP.?500|early data|ClientResponse|response\.release|\.release\(\)|request\(|\.get\(|\.post\()' \
-g '!**/.git/**' . || true
echo '== Public functions/classes in changed Python files =='
changed_py="$(git diff --name-only --diff-filter=ACMR "$base_commit" "$source_commit" -- '*.py')"
if [ -n "$changed_py" ]; then
printf '%s\n' "$changed_py" | while IFS= read -r file; do
echo "-- $file --"
ast-grep outline "$file" --items all --type class,function --view expanded || true
done
fi
echo '== Documentation references in changed Markdown/reStructuredText files =='
changed_docs="$(git diff --name-only --diff-filter=ACMR "$base_commit" "$source_commit" -- '*.md' '*.rst' '*.txt')"
if [ -n "$changed_docs" ]; then
printf '%s\n' "$changed_docs" | while IFS= read -r file; do
echo "-- $file --"
rg -n -i -C 3 '(RFC ?8470|RFC ?9110|RFC ?6585|425|500|Retry-After|early data)' "$file" || true
done
fi
echo '== GitHub PR metadata and checks by requested source commit =='
gh pr view 71 --repo "$repo" --json number,state,isDraft,headRefName,headRefOid,baseRefName,baseRefOid,mergeCommit,reviewDecision,statusCheckRollup,reviews
gh api "repos/$repo/commits/$source_commit/check-runs?per_page=100" \
--jq '.check_runs[] | {name, status, conclusion, head_sha, details_url, started_at, completed_at}'
gh api "repos/$repo/commits/$source_commit/status" \
--jq '{sha, state, statuses: [.statuses[] | {context, state, target_url, created_at, updated_at}]}'Length of output: 210011 🏁 Script executed: #!/bin/bash
set -euo pipefail
source_commit='ecb5a82c3170b4b95970a291dafd1adbd90829e2'
base_commit='bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10'
repo='ContextualWisdomLab/pg-llm-batch'
echo '== Retry control flow =='
sed -n '45,95p;300,412p' pg_llm_batch/batch_api_client.py
echo '== Existing GET retry and POST non-retry tests =='
rg -n -C 4 \
'(async def test_.*(post|POST|retryable_get|stops_after)|"post"|POST|Retry-After|exit_count|sleep)' \
tests/test_idempotent_get_retries.py tests/test_retry_edge_coverage.py tests/test_http_transport.py
echo '== Public retry documentation locations =='
rg -n -i -C 3 \
'(idempotent provider `GET`|retryable statuses|transient `408`|HTTP 425|Too Early|RETRYABLE_GET_STATUSES)' \
README.md CHANGELOG.md docs AGENTS.md
echo '== CI workflow trigger and coverage/docstring commands =='
sed -n '1,280p' .github/workflows/ci.yml
echo '== All workflow references to PR merge refs, head SHA, and checkout refs =='
rg -n -C 3 \
'(pull_request|merge_group|github\.sha|github\.event\.pull_request\.head\.sha|actions/checkout|ref:)' \
.github/workflows
echo '== Exact changed-file safety classification =='
git diff --name-only "$base_commit" "$source_commit" | \
awk '
/^(\.github\/|docker\/|pg_llm_batch\/schema\.sql$|.*\.(sql|lock|pem|key|crt|p12|pfx)$)/ {print "SENSITIVE_OR_GENERATED_CANDIDATE " $0; next}
{print "REVIEWED_CHANGE " $0}
'
echo '== GitHub Actions run event, SHA, and PR association =='
for run in 31248352447 31248352452 31248352460 31248351228; do
gh api "repos/$repo/actions/runs/$run" \
--jq '{id,event,status,conclusion,head_sha,head_branch,workflow_id,pull_requests}'
done
echo '== Branch protection and repository ruleset summary =='
gh api "repos/$repo/branches/main/protection" --jq '{required_status_checks,required_pull_request_reviews,enforce_admins,required_linear_history,restrictions}' 2>/dev/null || true
gh api "repos/$repo/rulesets" --jq '.[] | {id,name,target,enforcement,rules}' 2>/dev/null || trueLength of output: 54357 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo='ContextualWisdomLab/pg-llm-batch'
run_id='31248352447'
echo '== Coverage and test configuration =='
rg -n -C 5 \
'(tool\.coverage|coverage|branch|pytest|interrogate|fail-under|addopts)' \
pyproject.toml .coveragerc setup.cfg tox.ini 2>/dev/null || true
echo '== CI job identifiers =='
gh api "repos/$repo/actions/runs/$run_id/jobs?per_page=100" \
--jq '.jobs[] | {id,name,conclusion,started_at,completed_at}'
echo '== Quality-gate log: checkout revision and coverage report only =='
quality_job_id="$(
gh api "repos/$repo/actions/runs/$run_id/jobs?per_page=100" \
--jq '.jobs[] | select(.name == "Coverage, docstrings, lint, and package") | .id'
)"
gh api "repos/$repo/actions/jobs/$quality_job_id/logs" > /tmp/quality-gate.log
rg -n -i -C 3 \
'(checking out|checked out|git checkout|git rev-parse|HEAD is now at|coverage|branch|TOTAL|interrogate|100%)' \
/tmp/quality-gate.log || true
echo '== Source-head versus pull-request merge references =='
gh api "repos/$repo/git/ref/pulls/71/merge" --jq '.object.sha' 2>/dev/null || true
gh api "repos/$repo/git/ref/pulls/71/head" --jq '.object.sha'Length of output: 4608 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo='ContextualWisdomLab/pg-llm-batch'
quality_job_id='93080564666'
echo '== Quality-gate checkout and coverage evidence =='
gh api --allow-escape-sequences "repos/$repo/actions/jobs/$quality_job_id/logs" \
| sed -r 's/\x1B\[[0-9;]*[[:alpha:]]//g' > /tmp/quality-gate.log
rg -n -i -C 4 \
'(checking out|checked out|git checkout|git rev-parse|HEAD is now at|coverage|branch|TOTAL|interrogate|100%|passed)' \
/tmp/quality-gate.log || true
echo '== Pull request references =='
printf 'merge_ref='
gh api "repos/$repo/git/ref/pulls/71/merge" --jq '.object.sha' 2>/dev/null || echo 'not_available'
printf 'head_ref='
gh api "repos/$repo/git/ref/pulls/71/head" --jq '.object.sha'Length of output: 13767
Finding
Verified
CI evidenceThe quality gate reports 100% production statement and branch coverage, and 100% public docstrings. However, the job checked out Therefore, under the stated governance requirement, this is synthetic-merge-stage evidence only. It does not verify the exact source head. I do not approve or mark this Draft PR ready. You are interacting with an AI system. |
|
@coderabbitai review @opencode-agent @cwl-noema-review Fresh review-only request for exact head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo='ContextualWisdomLab/pg-llm-batch'
base='bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10'
head='52254aa95f245fceebc2a12a9a69aa94c0273b35'
echo '== Exact commits and range =='
git rev-parse "$base" "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=yes'
git show -s --format='head=%H%nparents=%P%nsubject=%s' "$head"
git diff --name-status "$base" "$head"
git diff --stat "$base" "$head"
echo '== Diff =='
git diff --find-renames --no-ext-diff "$base" "$head"
echo '== Retry implementation outline and relevant source =='
ast-grep outline pg_llm_batch/batch_api_client.py --items all --type class,function --view expanded
rg -n -C 8 \
'(RETRYABLE_GET_STATUSES|async def _request|response\.release|Retry-After|equal.*jitter|asyncio\.sleep|method.*GET|method.*POST)' \
pg_llm_batch/batch_api_client.py
echo '== Retry and README contract test definitions =='
rg -n -C 8 \
'(425|Too Early|RETRYABLE_GET_STATUSES|README|retry.*status|response.*release|Retry-After|equal.*jitter|500|POST)' \
tests README.md CHANGELOG.md docs AGENTS.md 2>/dev/null || true
echo '== PR, runs, check-runs, statuses, and checkout refs =='
gh pr view 71 --repo "$repo" \
--json number,state,isDraft,headRefOid,baseRefOid,reviewDecision,reviews,statusCheckRollup
for run in 31248982685 31248982690 31248982733; do
gh api "repos/$repo/actions/runs/$run" \
--jq '{id,event,status,conclusion,head_sha,head_branch,workflow_id,pull_requests}'
done
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
--jq '.check_runs[] | {name,status,conclusion,head_sha,details_url}'
gh api "repos/$repo/commits/$head/status" \
--jq '{sha,state,statuses:[.statuses[] | {context,state,target_url}]}'
printf 'pr_head_ref='
gh api "repos/$repo/git/ref/pulls/71/head" --jq '.object.sha'
printf 'pr_merge_ref='
gh api "repos/$repo/git/ref/pulls/71/merge" --jq '.object.sha' 2>/dev/null || trueLength of output: 181761 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo='ContextualWisdomLab/pg-llm-batch'
run='31248982685'
job='93082174686'
head='52254aa95f245fceebc2a12a9a69aa94c0273b35'
echo '== CI checkout configuration =='
sed -n '1,280p' .github/workflows/ci.yml
echo '== CI quality-gate checkout and result excerpts =='
gh api --allow-escape-sequences "repos/$repo/actions/jobs/$job/logs" \
| sed -r 's/\x1B\[[0-9;]*[[:alpha:]]//g' > /tmp/quality-gate.log
rg -n -i -C 3 \
'(checking out|checked out|git checkout|git rev-parse|HEAD is now at|refs/remotes/pull|coverage|TOTAL|branch|interrogate|100%|passed|deselected|built)' \
/tmp/quality-gate.log || true
echo '== Current Strix workflow and check state =='
gh api "repos/$repo/actions/runs/31248981773" \
--jq '{id,event,status,conclusion,head_sha,updated_at,pull_requests}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
--jq '[.check_runs[] | select(.name == "strix") | {status,conclusion,started_at,completed_at,details_url}]'
echo '== Review and unresolved review-thread state =='
gh pr view 71 --repo "$repo" --json reviews,reviewDecision
gh api graphql -F owner='ContextualWisdomLab' -F name='pg-llm-batch' -F number=71 -f query='
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes { isResolved comments(first: 1) { nodes { author { login } body } } }
}
}
}
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | {author: .comments.nodes[0].author.login, body: .comments.nodes[0].body}]'Length of output: 19168
No new code or documentation finding was identified. The predecessor P2 finding is fixed. I verified the following:
I also verified that CI checked out synthetic merge commit The
|
Purpose
Harden the OpenAI-compatible Files/Batches HTTP control plane without widening replay: bounded idempotent GET retries, fail-closed TLS trust handling, provider-error confidentiality, exact gateway authority, bounded wait controls, and fail-closed batch-status progress validation.
Bounded implementation
{408, 425, 429, 502, 503, 504}; HTTP 500 and every provider POST remain single-attempt.ClientSSLError/certificate-verification andServerFingerprintMismatchfailures are permanent for the current acquisition attempt and are never retried automatically.gateway.base_urlonly when the alias-specific value is actually absent (None). An explicit false-y value is still authoritative input and must be validated/rejected rather than silently inheriting another destination authority.wait_for_batch()accepts only finite positive numeric poll/timeout controls before credential/provider I/O.request_counts, when present, must be an object whosetotal,completed, andfailedare exact non-negative integers, withcompleted + failed <= total. Malformed evidence raises body-freeInvalidBatchStatusPayloadrather than raw runtime failures or unsafe normalization.Issue #98 integration
The current source contains the bounded data-integrity behavior tracked by Issue #98 for malformed
request_counts, boolean/string/negative/non-finite counters, inconsistent progress, and malformed status shape. This remains ACTIVE-PR evidence until #71 reaches protectedmain; Issue #98 is not a protected-main closure merely because the code is present here.Test-first evidence
The branch history retains RED→GREEN cycles for HTTP 425/TLS classification, response handoff, transport vocabulary, provider-error confidentiality, malformed-success exception privacy, exact gateway authority, wait-resource validation, and batch-status shape/progress validation.
The latest exact-authority cycle found a concrete fallback defect in the package-provided credential resolver:
e8ef75ba2af5a3f49b3790c48b5b6117b7b9211aadded alias-aware regressions. CI31516117889failed exactly six false-y non-string alias cases (False,0,0.0,b"",[],{}) because the old truthiness test silently fell back togateway.base_urlinstead of rejecting the explicit alias value. The observed coverage run still reported 100% owned production statement/branch coverage; the six regression failures are the intended product-boundary RED evidence.2e1ffd31148fcc8bc5a20b7e7096a5c646b3a459changes fallback selection from truthiness to explicit absence (is None), preserving legacy fallback only for a missing alias while routing explicit values through the existing exact URL validator before secret lookup. Current CI31516889156, Security Scan31516889318, and SAST Semgrep31516889246are all completed / success.docs/adr/0015-http-425-too-early-retry.mdanddocs/doctoring/http-425-too-early-retries.mdretain primary protocol/Python/aiohttp references and rollback boundaries. Predecessor checks remain development provenance only.Current exact staged state
2e1ffd31148fcc8bc5a20b7e7096a5c646b3a459.main:bf2cc2e140dc3ff4a56c3203f80f41bb9fed5d10.31516889156: completed / success.31516889318: completed / success.31516889246: completed / success.These successful PR-triggered runs remain staged integration evidence because protected-main CI still predates #88 exact-source checkout governance. They must not be promoted to final exact contributor-source-head acceptance merely because the generated-merge workflow is green.
Follow-up boundaries
Issue #128 remains separate:
GatewayCredentialsstill uses a generated dataclass representation that can exposeapi_key. Do not add that representation fix on a competing branch while #71 owns this provider-client surface; implement it test-first from the protected #71 result or a proven successor. Later session-ownership/concurrency follow-ups (#110/#111) must likewise compose from the protected result rather than race this branch.Issue #136 is also separate. Protected main and this branch still have no provider-file lifecycle authority for upload expiry, generated output/error expiry, or explicit Files API deletion. After #71 reaches protected main or is superseded, #136 must compose remote input/output/error retention and deletion through the then-protected validated gateway/credential/resource-ID boundary. Cancellation is not deletion, historical provider file identities remain reconciliation evidence after remote content expires/deletes, and no #71 checks/reviews transfer automatically to that future lifecycle slice.
Current prerequisite / merge boundary
Repository exact-source governance #88 is the immediate prerequisite. Current organization rules require the central workflow set and review-thread resolution, with
required_approving_review_count: 0, code-owner review disabled, and no last-push approval requirement. This PR currently has no formal reviews and no unresolved threads, so absence of an independent approval is not a live blocker unless policy changes.ContextualWisdomLab/.github#790remains read-only and cannot be copied, weakened, retriggered, dismissed, resolved, or merged by this writer. Its historical review state is not promoted into an extra leaf approval prerequisite beyond current live policy.Keep Draft until #88 reaches protected
main. Then refetch this exact head/base and active-writer state, promote to Ready only if unchanged and non-conflicting, and reacquire every live exact-source central/repository CI, security, coverage, package, provenance, review, and ruleset gate. Merge only with zero valid unresolved findings and every requirement actually imposed by the then-current ruleset satisfied.