Skip to content

runtime: bound pg-erd slow-drip response bodies - #39

Draft
seonghobae wants to merge 41 commits into
test/pg-erd-upstream-tls-v1from
fix/pg-erd-response-lifetime-v2
Draft

runtime: bound pg-erd slow-drip response bodies#39
seonghobae wants to merge 41 commits into
test/pg-erd-upstream-tls-v1from
fix/pg-erd-response-lifetime-v2

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #38.

Dependency root and succession

Final #37 is unchanged at 4a57acaf0205cf202a4ef554f297e9c97ddd7f99 with terminal exact-head CI 34257163107, Supply Chain 34257163076, and current-range owner technical COMMENT evidence. That COMMENT is not independent human APPROVED governance credit.

This branch ordinarily/non-force adopted final #37. Two-parent commit db60f8e77efd729760ab76edffabf699080dfc9f preserves historical response-lifetime child c92d670fa9eb2811855bf49f80e7132e511f2d81 as first parent and final #37 as second parent, with a resolution tree based on final #37. No force-push or destructive rebase was used. Final #37 remains the exact merge base and the branch remains behind=0.

Effective scope versus final #37 remains the versioned response-lifetime source/config/tests plus associated code-current docs and Proposed ADR 0010. Product auth/business routing, retry/failover policy, WebSocket/Upgrade enablement, Keyverse, Wardnet, EgressWeave, and consumer repository source remain outside this PR.

RED and causal production repair

The real-listener slow-drip contract distinguishes Pingora peer read_ms from an overall response-body lifetime. Pg-erd version 2 requires explicit positive max_upstream_response_body_ms; version 1 rejects that field and generic gateway v1 remains unchanged. ResponseBodyLifetimeBudget starts once at the first non-informational upstream response header. Empty/end-of-stream bookkeeping is not body progress; only a non-empty body callback at or beyond the budget becomes an upstream-scoped fatal error. Post-commit behavior remains no second status, retry, or route failover: terminate the incomplete response, preserve readiness, record low-cardinality error telemetry, and release request admission.

This is deliberately progress-driven, not an exact timer interrupt for a pending Pingora read. Quiescent reads remain governed by independent read_ms; incomplete response-header lifetime and broader admitted long-lived streaming remain separate gaps.

Hosted RED history

  • 27c094c4... exposed Rust 1.98.0 formatter-only RED; commits through cd0c3582... applied runner-prescribed layout only.
  • cd0c3582... exposed a compile-test oracle defect because assert_eq!(config.build_proxy(), Err(...)) unnecessarily required runtime proxy PartialEq; 9b135db... replaced it with exact error-variant matches!.
  • 9b135db... exposed one missing 100%-region success continuation; d8156eed... added the non-empty-before-expiry 299 ms unit case while retaining 300 ms rejection.
  • d8156eed... independently reproduced an adapter-only structural region miss. Artifact 10072198032, digest c346bb92f2d3555ad58b923f273ee07ac5f0cf97e7d61e9b1d707d8642751a58, isolated the sole zero-count region to the success continuation of adapter-local .map_err(...)?. 0bdc7f703075ef4db5d629b0d2c63140b7e1d48e made the existing tested progress helper return final pingora::Result<Option<Duration>> and tail-delegated from the Pingora callback, removing that untestable continuation without changing timing/error/routing/security semantics.

Current review-driven evidence repairs

CodeRabbit Run ID 8ac74a66-4172-4030-ae5b-50f386b704a3 identified two valid evidence defects.

  • ADR 0010 incorrectly said every body callback was checked. Documentation-only b4d7387fc148b3daa114e30dcd6dcb90b99da98a aligns the decision with the executable non-empty-progress condition; the inline thread is answered/resolved.
  • The real-listener fixture could terminate too early and still satisfy only an upper elapsed-time/body-incomplete oracle. 942c58933bfdd3f6f6beefe41c96bf456e237f7b first added the requested elapsed >= 300 ms bound plus non-empty committed body progress.

A deeper causal read then showed that a 300 ms request-level lower bound alone does not distinguish the selected response-header start anchor from a regression that starts the budget at request reception when the origin returns its header immediately. Test-only current commit 56c7c4822d35c0506d660c71ace54dade104ab0e closes that remaining false-GREEN: after the routed request reaches the backend, the origin deliberately waits 150 ms (still below read_ms=500) before committing HTTP 200, then drips one byte every 60 ms. The downstream must now survive at least 150 ms + 300 ms before lifetime termination, while still terminating below the conservative 1 s outer bound, delivering at least one body byte, preserving exact single Content-Length: 20 framing, ending before all 20 bytes complete, recording exact one-request error telemetry, keeping /readyz healthy, and serving the independent frontend recovery route. A request-start lifetime would expire on body progress around the earlier request-relative boundary and fail this 450 ms lower-bound oracle.

This current change is test-only. Production Rust, Admin Config, 300 ms budget, 500 ms read timeout, route policy, auth/business authority, security policy, k6 traffic and performance thresholds are unchanged. The prior CodeRabbit inline finding is resolved. Exact-current owner technical COMMENT on 56c7c... finds no additional actionable finding; this is technical evidence only, not independent human APPROVED. An explicit CodeRabbit exact-range re-review was requested, but no newer formal bot review has been returned, so no predecessor review credit is transferred beyond the verified repaired findings.

Documentation and authority

ADR 0010 remains Proposed. API_CONFIG_CONTRACT.md, OPERABILITY.md, TEST_STRATEGY.md, TRD.md, CHANGELOG.md, and docs/product-technical-gap-baseline.md remain the durable contract/boundary documents; mutable exact head/run/review state stays in live PR/issue authority. The source contract remains first-final-header start + non-empty progress enforcement; the strengthened fixture adds causal timing evidence without changing that contract.

Exact-head hosted GREEN

Current exact head remains 56c7c4822d35c0506d660c71ace54dade104ab0e. CI 34269245914 is terminal GREEN on this unchanged SHA: load-contract 102206623251, oci-runtime 102206623529, and test 102206623591 all completed success. The test job passed exact checkout, Rust 1.98.0, formatting, compile/test, strict lint, warnings-denied public rustdoc, pinned coverage tooling, complete owned-production line+region coverage, resolved dependency-lock verification, and evidence upload. OCI passed exact candidate-image build, declared non-root identity, and generic/pg-erd read-only least-privilege runtime. Load passed generic concurrent loopback and routed pg-erd k6 contracts with exact-SHA evidence uploads.

Supply Chain 34269245810 / candidate-evidence 102206463239 is also terminal GREEN on exact 56c7c...: committed dependency audit, exact candidate images, SPDX SBOM, both image scans, exact-source binding, and evidence upload all completed success. No predecessor execution result is needed or transferred.

#39 is therefore technically closed on its unchanged exact head for dependent ordinary/non-force succession. Keep the PR Draft because protected promotion remains gated by the separate supplier/compiler/governance root; do not infer protected merge readiness from this branch-local closure. #42 may now ordinary/non-force adopt final #39, preserving only its still-valid capacity delta and reacquiring exact-head evidence on the resulting tree.

No self-approval, gate weakening, protected merge, immutable release, canary/cutover, rollback, or legacy-removal credit is claimed.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

📝 Walkthrough

Walkthrough

pg-erd 구성 버전 2에 양수 max_upstream_response_body_ms 설정을 추가했습니다. 런타임은 최종 응답 헤더 이후 본문 진행 시간을 검사합니다. 제한 초과 시 커밋된 응답을 종료하고, 실제 slow-drip 트래픽으로 오류 telemetry와 복구 경로를 검증합니다.

Changes

pg-erd 응답 본문 수명 계약

Layer / File(s) Summary
버전 2 구성 계약과 검증
src/migration_admin.rs, tests/pg_erd_response_lifetime_config.rs, tests/pg_erd_admin_config_contract.rs, API_CONFIG_CONTRACT.md, OPERABILITY.md, TRD.md
버전 2는 명시적인 양수 max_upstream_response_body_ms를 요구합니다. 버전 1은 해당 필드를 거부합니다. 0, 누락, 미래 버전, 불완전 구성에 대한 검증을 추가했습니다.
런타임 응답 수명 예산
src/runtime_isolation.rs
RuntimeIsolationLimits에 선택적 응답 본문 수명 제한을 추가했습니다. ResponseBodyLifetimeBudget은 최초 시작 시각을 유지하고, 제한 이상 경과한 본문 진행을 거부합니다.
프록시 응답 본문 집행
src/migration_proxy.rs
첫 번째 비정보성 업스트림 응답 헤더에서 수명을 시작합니다. 비어 있지 않은 본문 콜백에서만 만료를 검사합니다. 초과 시 업스트림 범위 오류를 반환하며, 재시도나 failover를 수행하지 않습니다.
실제 slow-drip 트래픽과 운영 문서
tests/pg_erd_slow_drip_response_traffic.rs, CHANGELOG.md, TEST_STRATEGY.md, docs/adr/0010-version-pg-erd-response-body-lifetime.md, docs/product-technical-gap-baseline.md
read_ms보다 빠르게 진행하는 slow-drip 응답이 본문 완료 전에 종료되는지 검증합니다. 커밋된 200 상태와 framing, 오류 telemetry, /readyz, 독립 frontend 경로를 확인합니다. 응답 수명 가드의 한계와 남은 검증 범위도 문서화했습니다.

Priority: ⚪ Not assessed

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

Severity of issue fixed: Medium

Merge Risk: 🔵 Low · up to d8156

The runtime behavior is largely covered, but the published contract and end-to-end test oracle should be corrected before relying on this change as evidence of the response-lifetime guarantee.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MigrationGatewayProxy
  participant SlowDripOrigin
  participant MetricsAndReadiness
  Client->>MigrationGatewayProxy: pg-erd 요청
  MigrationGatewayProxy->>SlowDripOrigin: 업스트림 요청
  SlowDripOrigin-->>MigrationGatewayProxy: 최종 헤더와 200 응답
  MigrationGatewayProxy->>MigrationGatewayProxy: 응답 본문 수명 시작
  SlowDripOrigin-->>MigrationGatewayProxy: 본문 바이트 진행
  MigrationGatewayProxy->>MigrationGatewayProxy: max_upstream_response_body_ms 검사
  MigrationGatewayProxy-->>Client: 커밋된 응답 종료
  MigrationGatewayProxy->>MetricsAndReadiness: request-error telemetry 기록
  Client->>MetricsAndReadiness: /readyz 확인
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive 구현은 [#38]의 핵심 코딩 요구사항인 버전 2 설정, 양수 응답 본문 수명 예산, read_ms와의 분리, 응답 진행 시점의 만료 검사, 재시도·페일오버 방지, 오류 텔레메트리, readiness 및 lease 해제를 반영합니다. 그러나 exact-head CI, 부하·OCI·보안·공급망 및 독립 검토 증거가 아직 진행 중이므로 전체 이슈 준수 여부… 정확한 현재 커밋에 대해 필수 fmt, compile, test, clippy, rustdoc, 커버리지, 부하, OCI, 보안, 공급망 및 독립 검토 결과를 완료하고 증거를 제공하십시오. 모든 검사가 통과하면 이슈 준수 여부를 재평가하십시오.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed 변경 사항은 [#38]의 응답 본문 수명 제한, 구성 계약, Runtime Isolation 구현, 통합 테스트 및 관련 문서 범위에 포함됩니다. WebSocket, HTTP/3, downstream TLS, 자동 재시도, 소비자 전환과 같은 비승인 범위의 변경은 확인되지 않습니다.
Docstring Coverage ✅ Passed Docstring coverage is 87.72% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 57 functions across 6 files. (7 skipped: 7 …
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 pg-erd slow-drip 응답 본문에 수명 제한을 적용하는 이 PR의 주요 변경 사항을 정확하고 간결하게 설명합니다.
Full details: Linked Issues check

Explanation

구현은 [#38]의 핵심 코딩 요구사항인 버전 2 설정, 양수 응답 본문 수명 예산, read_ms와의 분리, 응답 진행 시점의 만료 검사, 재시도·페일오버 방지, 오류 텔레메트리, readiness 및 lease 해제를 반영합니다. 그러나 exact-head CI, 부하·OCI·보안·공급망 및 독립 검토 증거가 아직 진행 중이므로 전체 이슈 준수 여부는 확정할 수 없습니다.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pg-erd-response-lifetime-v2

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.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-current technical sweep on 4a57acaf0205cf202a4ef554f297e9c97ddd7f99..cd0c3582d25aeaa59f4f3b8385ac4c07beb5e9fc: re-read the version-2 Admin Config boundary, public build_proxy() revalidation, Runtime Isolation lifetime state, Pingora response-header/body callbacks, upstream-scoped error mapping, slow-drip real-listener fixture, framing/status/metric lookalike regressions, ADR 0010 and code-current operational/test docs. The current-parent adaptation correctly avoids treating None/empty/end-of-stream bookkeeping as response-body progress; only non-empty progress can trip the lifetime. Hosted Rust 1.98.0 formatting RED on predecessor 27c094c4... was reproduced from job logs and the exact rustfmt diff was applied without changing runtime semantics. No additional actionable source/test/documentation/DDD authority finding in this sweep. This COMMENT is owner technical evidence only, not an independent APPROVED governance decision; exact-current CI/Supply Chain must still close unchanged.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-current follow-up after hosted compile RED: CI 34264481286 / test job 102190401661 proved Rust 1.98.0 formatting GREEN, then failed compilation only because assert_eq!(config.build_proxy(), Err(...)) required MigrationGatewayProxy: PartialEq. The intended oracle is the error variant, not proxy equality. Current commit replaces that assertion with matches!(..., Err(PgErdMigrationConfigError::MissingUpstreamResponseBodyLifetime)), preserving the public build_proxy() revalidation contract without adding meaningless equality semantics to the runtime proxy. Re-read the exact delta and no other source/test/docs/DDD authority finding is introduced by this repair. This COMMENT is technical evidence only, not independent APPROVED; exact-current hosted gates must rerun and close unchanged.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-current technical follow-up on d8156eed6c4622b135daee5a7ddce209cfa82acb: predecessor CI 34264874185 supplied a deterministic 100%-region gate RED, not a runtime or traffic failure. Its exact coverage artifact 10071733273 shows the sole missed region in src/migration_proxy.rs on the successful continuation of ctx.response_body_lifetime.reject_if_expired(now)? for a non-empty chunk. Existing tests already exercised skipped None/empty callbacks and the expired non-empty error path. This commit adds only the missing non-empty-before-expiry case at 299 ms under a 300 ms budget, preserving the 300 ms rejection. Commit diff is one test hunk; no production code, versioned Admin Config, traffic, response-lifetime semantics, routing, auth/policy authority, or gate threshold changed. I find no additional actionable finding in this one-file causal repair. COMMENT is technical evidence only and is not an independent APPROVED governance credit; exact-head CI/Supply Chain must independently close.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please re-review exact current head d8156eed6c4622b135daee5a7ddce209cfa82acb, specifically the one-hunk coverage repair after predecessor CI 34264874185 exposed the sole missed LLVM region. Verify that adding non-empty response-body progress at 299 ms closes only the success continuation of the 300 ms lifetime check and does not weaken the expired-body, empty-callback, traffic, DDD authority, or coverage gates. Do not transfer predecessor review credit if the exact head changes.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='d8156eed6c4622b135daee5a7ddce209cfa82acb'
parent='9b135db0947f88dfd525c07f34687fba92490592'

printf '%s\n' '== Checked-out HEAD and requested commit =='
git rev-parse HEAD
git show -s --format='commit=%H%nparents=%P%nsubject=%s' "$head"
git merge-base --is-ancestor "$parent" "$head" && echo "predecessor_is_ancestor=true"

printf '%s\n' '== Exact parent delta =='
git diff --stat "$parent" "$head"
git diff --name-status "$parent" "$head"
git diff --check "$parent" "$head"
git diff --find-renames --unified=80 "$parent" "$head"

printf '%s\n' '== Relevant Rust test and production structure =='
fd -a 'migration_proxy\.rs|response.*lifetime.*\.rs|slow_drip.*\.rs' .
ast-grep outline . --items all --type function --match 'response|Response|expired|Expired|Lifetime|lifetime' 2>/dev/null || true
rg -n -C 12 --glob '*.rs' \
  'reject_if_expired|ResponseBodyLifetimeBudget|max_upstream_response_body_ms|MissingUpstreamResponseBodyLifetime|299|300' .

printf '%s\n' '== Exact GitHub workflow/check status =='
gh api "repos/ContextualWisdomLab/pingora-gateway/commits/$head/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name, .status, .conclusion, .html_url] | `@tsv`' || true

Length of output: 98556


@seonghobae Re-review completed for exact head d8156eed6c4622b135daee5a7ddce209cfa82acb.

No finding in the one-hunk repair.

The exact delta from 9b135db0947f88dfd525c07f34687fba92490592 changes only src/migration_proxy.rs. It adds seven test lines. It does not change production logic, traffic tests, configuration semantics, DDD authority boundaries, or coverage thresholds.

The new assertion sends a non-empty body chunk at 299 ms and requires success. This covers the successful continuation of reject_if_expired before the 300 ms limit.

The existing assertions remain intact:

  • None passes at 300 ms.
  • An empty Bytes callback passes at 300 ms.
  • A non-empty body chunk fails at 300 ms.

The implementation still calls reject_if_expired only for non-empty body chunks. The budget still rejects when elapsed time is greater than or equal to the configured limit. Therefore, the expired-body and empty-callback boundaries remain unchanged.

The exact-head test, load-contract, oci-runtime, and candidate-evidence checks are still in progress. I did not transfer predecessor CI or review credit to this changed head. The remaining gates require exact-head terminal evidence.

✅ Action performed

Review finished.

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.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-current technical follow-up on 0bdc7f703075ef4db5d629b0d2c63140b7e1d48e: predecessor exact d8156eed... proves the remaining failure is structural region coverage, not runtime behavior. CI 34266086213 had formatting, compile/test, Clippy, rustdoc, routed load and dual-profile OCI GREEN; exact artifact 10072198032 shows the sole zero-count LLVM region at src/migration_proxy.rs:322, the success continuation of .map_err(response_body_lifetime_to_pingora)? in the Pingora adapter. This commit removes only that adapter-local continuation by making the existing pure progress helper return the final pingora::Result<Option<Duration>> and tail-delegating from upstream_response_body_filter. Existing unit coverage exercises None, empty, pre-expiry non-empty and expired non-empty cases, including both mapping outcomes. No versioned config, timing threshold, error type/source, traffic, route, auth/business authority or security boundary changed. I find no additional actionable source/test/docs/DDD finding in this exact diff. COMMENT is technical evidence only, not independent APPROVED; current exact hosted gates must close independently.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please re-review exact current head 0bdc7f703075ef4db5d629b0d2c63140b7e1d48e. Predecessor d8156eed... exact artifact 10072198032 isolated the only missing LLVM region to the adapter-local success continuation of .map_err(...)?. Verify that moving the final pingora::Result<Option<Duration>> mapping into the already-tested progress helper and tail-delegating from upstream_response_body_filter preserves the same response-lifetime/error semantics and does not weaken coverage, traffic, DDD authority, or security boundaries. Do not transfer predecessor review credit if the head changes.

@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

🧹 Nitpick comments (1)
tests/pg_erd_slow_drip_response_traffic.rs (1)

301-304: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

종료 원인을 고정하는 하한 단언을 추가하십시오.

현재 오라클은 상한만 확인합니다. elapsed < 1sbody.len() < 20은 "응답 헤더 직후 즉시 실패" 또는 "예산 시작 시점이 요청 수신 시점으로 앞당겨짐" 같은 회귀에서도 통과합니다. 그러면 이 픽스처가 증명하려는 인과, 즉 300 ms 본문 진행 예산이 종료 원인이라는 사실이 고정되지 않습니다.

src/migration_proxy.rs:180-188은 비정보성 업스트림 응답 헤더에서 예산을 시작합니다. started는 그보다 앞선 다운스트림 connect 시점입니다. 따라서 정상 동작에서 elapsed >= 300ms는 항상 성립하며 하한 단언은 불안정하지 않습니다.

♻️ 하한 단언 추가 제안
     assert!(
         elapsed < Duration::from_secs(1),
         "the 300ms response-body budget must stop a continuously progressing response instead of allowing the full 1.2s drip: {elapsed:?}"
     );
+    assert!(
+        elapsed >= Duration::from_millis(300),
+        "termination must be caused by the 300ms body-progress budget, not by an immediate post-header failure: {elapsed:?}"
+    );
     let body = &partial[header_end..];
+    assert!(
+        !body.is_empty(),
+        "the committed response must deliver body progress before the budget terminates it"
+    );
     assert!(
         body.len() < 20,
         "the configured response-body budget must terminate before the declared body completes"
     );

Also applies to: 322-326

🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In `@tests/pg_erd_slow_drip_response_traffic.rs` around lines 301 - 304, Extend
the elapsed-time assertion in the slow-drip response test to require the request
to run for at least the 300 ms body-progress budget, while retaining the
existing one-second upper bound. Apply the same lower-bound assertion to the
related assertion at the later test location, using the existing elapsed timing
value.
🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. 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 `@docs/adr/0010-version-pg-erd-response-body-lifetime.md`:
- Line 37: Update the ADR’s execution-condition wording to state that the budget
is checked only on upstream response-body callbacks containing non-empty body
chunks, matching enforce_response_body_lifetime and the existing wording in the
related documentation. Do not imply that empty callbacks or stream-termination
callbacks trigger expiry.

---

Nitpick comments:
In `@tests/pg_erd_slow_drip_response_traffic.rs`:
- Around line 301-304: Extend the elapsed-time assertion in the slow-drip
response test to require the request to run for at least the 300 ms
body-progress budget, while retaining the existing one-second upper bound. Apply
the same lower-bound assertion to the related assertion at the later test
location, using the existing elapsed timing value.

After applying the fix, consider running `coderabbit review --agent` for local
review. Visit https://docs.coderabbit.ai/cli.
🪄 Autofix

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: Advanced

Run ID: 8ac74a66-4172-4030-ae5b-50f386b704a3

📥 Commits

Reviewing files that changed from the base of the PR and between 4a57aca and d8156ee.

📒 Files selected for processing (13)
  • API_CONFIG_CONTRACT.md
  • CHANGELOG.md
  • OPERABILITY.md
  • TEST_STRATEGY.md
  • TRD.md
  • docs/adr/0010-version-pg-erd-response-body-lifetime.md
  • docs/product-technical-gap-baseline.md
  • src/migration_admin.rs
  • src/migration_proxy.rs
  • src/runtime_isolation.rs
  • tests/pg_erd_admin_config_contract.rs
  • tests/pg_erd_response_lifetime_config.rs
  • tests/pg_erd_slow_drip_response_traffic.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread docs/adr/0010-version-pg-erd-response-body-lifetime.md Outdated
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Oops, something went wrong! Please try again later. 🐰 💔

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-current technical follow-up on 942c58933bfdd3f6f6beefe41c96bf456e237f7b: re-read the two-file post-review repair from 0bdc7f703075ef4db5d629b0d2c63140b7e1d48e. ADR 0010 now states the implemented execution condition precisely: the lifetime is checked only on non-empty upstream response-body progress callbacks, so empty/end-of-stream bookkeeping cannot be misread as an expiry trigger. The real-listener slow-drip acceptance now also requires elapsed time to reach the configured 300 ms budget and requires non-empty committed body progress, while retaining the <1 s upper bound, exact HTTP/1.1 200/framing, incomplete Content-Length body, exact error metric, readiness, and independent-route recovery. These additions prevent an immediate post-header failure or prematurely started budget from manufacturing GREEN. No production Rust, Admin Config, timing value, routing, auth/business authority, security policy, traffic volume, or threshold changed. I find no additional actionable finding in this two-file causal repair. This COMMENT is technical evidence only, not independent human APPROVED; exact-head hosted CI/Supply Chain must close unchanged.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-current technical follow-up on 56c7c4822d35c0506d660c71ace54dade104ab0e: the prior 942c589... repair correctly added the CodeRabbit-requested 300 ms lower bound and non-empty body-progress oracle, but re-reading the causal timing model showed that an immediate response header made that lower bound unable to distinguish the selected first-final-response-header start anchor from a regression that started the budget at request reception. Current test-only delta adds a 150 ms origin pre-header delay, still safely below read_ms=500, and now requires client-observed termination only after at least 150 ms + 300 ms while retaining the <1 s outer bound, committed exact HTTP/1.1 200 + single Content-Length 20 framing, non-empty but incomplete body, exact error metric, readiness and independent-route recovery. A request-start budget would expire on an earlier body-progress callback and fail this strengthened oracle. No production Rust, Admin Config, budget/read timeout values, routing, auth/business authority, security policy, k6 traffic or p95 threshold changed. I find no additional actionable finding in this one-file evidence repair. COMMENT is technical evidence only, not independent human APPROVED; exact 56c7c... hosted CI/Supply Chain must close unchanged.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the exact current one-file delta 942c58933bfdd3f6f6beefe41c96bf456e237f7b..56c7c4822d35c0506d660c71ace54dade104ab0e, especially whether the 150 ms pre-response-header delay plus the 450 ms lower-bound oracle causally distinguishes the intended first-final-response-header lifetime start from an incorrect request-reception start, without weakening the existing <1 s, framing/body, metrics, readiness, and recovery acceptance. Current head only; do not transfer predecessor review credit.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='942c58933bfdd3f6f6beefe41c96bf456e237f7b'
head='56c7c4822d35c0506d660c71ace54dade104ab0e'
repo='ContextualWisdomLab/pingora-gateway'

printf '%s\n' '== Exact commits and ancestry =='
git show -s --format='base=%H%nbase_parents=%P%nbase_subject=%s' "$base"
git show -s --format='head=%H%nhead_parents=%P%nhead_subject=%s' "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=true'
printf '%s\n' '== Exact delta scope and contents =='
git diff --stat "$base" "$head"
git diff --name-status "$base" "$head"
git diff --check "$base" "$head"
git diff --find-renames --unified=100 "$base" "$head"

printf '%s\n' '== Candidate source and test files =='
fd -a 'migration_proxy\.rs|slow_drip.*\.rs|response.*lifetime.*\.rs' . | sort
printf '%s\n' '== Relevant declarations and timing-related calls =='
ast-grep outline src/migration_proxy.rs --items all --type function --match 'upstream_response|response_body|ResponseBody|Lifetime|reject|filter' 2>/dev/null || true
ast-grep outline tests/pg_erd_slow_drip_response_traffic.rs --items all --type function --match 'slow|response|header|lifetime|traffic' 2>/dev/null || true
rg -n -C 14 --glob '*.rs' \
  'upstream_response_filter|upstream_response_body_filter|ResponseBodyLifetimeBudget|reject_if_expired|first.*final|Instant::now|sleep\(|150|300|450|Duration::from_millis|<\s*Duration::from_secs' \
  src tests

printf '%s\n' '== Exact head checks =='
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name, .status, (.conclusion // "null"), .html_url] | `@tsv`' || true
printf '%s\n' '== Exact head workflow runs =='
gh api "repos/$repo/actions/runs?head_sha=$head&per_page=100" \
  --jq '.workflow_runs[] | [.name, .status, (.conclusion // "null"), .html_url] | `@tsv`' || true

Length of output: 240514


@seonghobae Re-review completed for exact delta 942c58933bfdd3f6f6beefe41c96bf456e237f7b..56c7c4822d35c0506d660c71ace54dade104ab0e.

No finding in this delta.

The delta changes only tests/pg_erd_slow_drip_response_traffic.rs. It adds a 150 ms delay before the backend sends the first final response header. It changes the lower-bound oracle from 300 ms to 450 ms.

The oracle distinguishes the intended start point from request reception:

  • If the lifetime starts at request reception, the continuous body progress reaches the 300 ms expiry point before 450 ms. The test fails the new lower bound.
  • If the lifetime starts at the first final response header, expiry occurs only on a non-empty body callback at or after approximately 150 ms + 300 ms. The test satisfies the lower bound.
  • The 150 ms delay remains below read_ms: 500, so a per-read timeout cannot explain the result.

The implementation starts ResponseBodyLifetimeBudget only from upstream_response_filter for the first non-informational header. It checks expiry only for non-empty body callbacks. The budget rejects at or after its 300 ms limit. The traffic oracle matches these semantics.

The delta preserves the existing <1 s termination bound, committed 200 status, Content-Length: 20, partial-body requirement, exact error metric, readiness check, and independent frontend recovery check. It does not modify production logic, routing authority, DDD boundaries, or security controls.

Exact-head load-contract succeeded. Exact-head test, oci-runtime, and candidate-evidence remain in progress. I did not transfer predecessor review or CI credit to this changed head.

You are interacting with an AI system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority: high type: bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant