Skip to content

feat(composition): bound ASGI request-body lifecycle - #443

Draft
seonghobae wants to merge 13 commits into
feat/product-composition-serving-conflict-responsefrom
feat/product-composition-asgi-body-lifecycle
Draft

seonghobae wants to merge 13 commits into
feat/product-composition-serving-conflict-responsefrom
feat/product-composition-asgi-body-lifecycle

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Scope

ASGI request-body lifecycle owner stacked on #442 exact 9bbb792ef43fca8b08684f4f55a8bfe65e1120da. Current source head is 728f07a8c86f92bbf33586f2a8007da9f31f5e06, open · Draft · mergeable, 13 commits / 2 files. This branch owns bounded request-body receive semantics only: byte accumulation, receive-event work, ASGI receive/event capability shape, http.disconnect, cancellation and server/runtime failure ownership. It does not own authentication, owner HTTP dispatch, success-response semantics, deployment packaging or buyer-path performance. No SQL/migration byte changes; PostgreSQL lineage remains 0018→0025.

RED → repair

Earlier commits established exact body-byte and receive-event budgets, malformed-event rejection, non-callable/non-awaitable shape rejection, distinct disconnect handling, and await-side exception/cancellation preservation.

Fresh review of descendant #444 exposed an inconsistency in this owner: the old receive path wrapped every exception raised while invoking a callable as CompositionRequestBodyError, while #444 correctly concluded that invocation timing alone cannot prove a local capability defect. ASGI defines receive as an awaitable callable; a non-callable capability or a normal non-awaitable return is demonstrably malformed, but a callable may itself raise a server/runtime failure before returning an awaitable.

Test-first 6b61a5c78efc1000a96f73d96303d9623307eb85 requires an ordinary synchronous RuntimeError to retain exact identity. Repair 728f07a8c86f92bbf33586f2a8007da9f31f5e06 removes the broad invocation wrapper and currentizes the public docstring. The boundary now fails closed only for demonstrable capability shape; invocation exceptions, await-side exceptions, and cancellation remain caller/server lifecycle authority. http.disconnect remains the protocol-defined peer lifecycle signal.

Descendant adoption — current

#444 adopted this owner repair by ordinary-forward merged #445, then advanced to exact e1af671deeeec682dffdf809cb8579dcc4d439da with core response-event/status/header/send validation. Current response-completion leaf #446 exact 7954f5bf606584ddb5bbcd29e1b64e49041b9409 adds complete non-streaming response prevalidation, no-content/framing/transfer-coding authority and detached validated caller headers before the first send await. No force-push or destructive rebase was used. #444/#446 remain outbound owners; this PR remains inbound receive/body owner.

Verification boundary

This source-level RED → repair is not canonical runtime GREEN. Canonical acceptance must use one unchanged exact #446 7954f5bf606584ddb5bbcd29e1b64e49041b9409 leaf and execute the inherited composition closure with exact owned statement/branch/docstring/edge coverage. #447 exact 47ac3556dfef7d5d27af2af8ae2ba5038b837e7c is the current Draft #260 Foundation discovery/runtime implementation and remains non-GREEN pending normal #64/#305 metadata integration plus protected-base checks/review. #261 owns installed wheel/sdist acceptance. #311 exact dbc2fcf70ba6a6883381e8526cd62c6e19ce159c must execute the complete inherited 0018→0025 PostgreSQL inventory on the same composition candidate. Source-level typing, mergeability, bot status and predecessor GREEN do not transfer.

Proposed architecture #433 is source-current at ff50182c25ccf45928b1413f947c992f62be2ded but ADR 0432 remains Proposed.

Keep Draft until same-tree package/install/PostgreSQL execution, prerequisite checks and qualifying independent review exist. No self-approval, administrator bypass, gate weakening, synthetic status, feature-local quality workflow, force-push/destructive rebase, mutable sibling source, predecessor-GREEN transfer, premature Ready/merge/release or simple Close is authorized.

Refs #432 #433 #435 #437 #438 #439 #440 #442 #444 #445 #446 #447 #260 #261 #311 #100.

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 51963ed3-ea62-45eb-b9e1-23c9ddecf6d5

📥 Commits

Reviewing files that changed from the base of the PR and between d58dc07 and 52a2fa0.

📒 Files selected for processing (2)
  • services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py
  • services/product-composition-api/tests/test_asgi_request_body_lifecycle.py

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


📝 Walkthrough

Walkthrough

ASGI 요청 본문을 제한된 바이트 수와 receive 이벤트 수로 읽는 함수를 추가했습니다. 이 함수는 입력과 이벤트를 검증하고, 잘못된 입력, 한도 초과, 클라이언트 연결 끊김을 구분합니다. 테스트는 본문 조립과 한도 경계, 예외 및 취소 전파를 확인합니다.

Changes

제한된 요청 본문 읽기

Layer / File(s) Summary
본문 읽기 계약과 구현
services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py
제한된 요청 본문 읽기 함수와 관련 예외를 추가했습니다. 함수는 입력 형식과 awaitable 반환값을 확인하고, 본문 크기 및 receive 이벤트 수를 제한합니다.
본문 읽기 수명주기 테스트
services/product-composition-api/tests/test_asgi_request_body_lifecycle.py
기본 이벤트 처리, 청크 조립, 한도 경계, 잘못된 이벤트와 설정, 연결 끊김, awaitable 검증 및 취소 전파를 테스트합니다.

Priority: ⬇️ Low

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

Change: Feature

Merge Risk: ⚪ Minimal · up to 52a2f

This PR adds a standalone helper that reads ASGI request bodies within byte and event limits, with focused tests. It does not yet change any serving path, and no concrete defect was identified. It appears safe to merge once the exact-head test run the author already requires passes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 2 files.
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 제목은 ASGI 요청 본문 수명 주기를 제한하는 주요 변경을 정확히 설명합니다. 바이트 누적, 이벤트 제한, 검증, 연결 해제 처리를 모두 포함하는 변경 범위와 일치합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact head f1dda8ed572997fc2f4abdbfbbe6e2c37aa2b036, focusing on ASGI receive/body lifecycle semantics: default body/more_body, bounded accumulation, oversized partial-body early failure, disconnect-vs-malformed classification, cancellation propagation, exact built-in event fields, and whether the new module leaves any statement/branch/docstring edge uncovered. Do not treat inherited stack evidence as current-head acceptance.

@coderabbitai

coderabbitai Bot commented Sep 23, 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
printf 'HEAD: '; git rev-parse HEAD
printf 'PR head via gh: '; gh pr view 443 --repo ContextualWisdomLab/Orgmetra --json headRefOid --jq '.headRefOid' || true
printf 'Named files:\n'; fd -t f '^(asgi_request_body\.py|test_asgi_request_body_lifecycle\.py)$'
printf 'Head changed paths:\n'; git diff-tree --no-commit-id --name-only -r f1dda8ed572997fc2f4abdbfbbe6e2c37aa2b036

Length of output: 918


🏁 Script executed:

#!/bin/bash
set -euo pipefail
ast-grep outline services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py --items all || true
ast-grep outline services/product-composition-api/tests/test_asgi_request_body_lifecycle.py --items all || true
printf '\nProduction module:\n'
nl -ba services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py
printf '\nLifecycle tests:\n'
nl -ba services/product-composition-api/tests/test_asgi_request_body_lifecycle.py
printf '\nCoverage configuration references:\n'
rg -n -C2 'branch\s*=|coverage|docstring|edge' services/product-composition-api/pyproject.toml services/product-composition-api/.coveragerc pyproject.toml 2>/dev/null | head -180 || true

Length of output: 13313


🏁 Script executed:

#!/bin/bash
set -euo pipefail
ast-grep outline services/product-composition-api/src/orgmetra_product_composition/asgi_transport.py --items all || true
printf '\nTransport exception and projections:\n'
rg -n -C5 'class CompositionTransportError|CompositionClientDisconnectedError|CompositionRequestBodyTooLargeError|read_bounded_http_request_body' services/product-composition-api
printf '\nCoverage configuration:\n'
sed -n '20,58p' services/product-composition-api/pyproject.toml
printf '\nExact head statuses (read-only):\n'
gh api repos/ContextualWisdomLab/Orgmetra/commits/f1dda8ed572997fc2f4abdbfbbe6e2c37aa2b036/status --jq '{state: .state, statuses: [.statuses[] | {context, state, sha, updated_at}]}' || true

Length of output: 21288


@seonghobae, I reviewed exact head f1dda8ed572997fc2f4abdbfbbe6e2c37aa2b036. I found no actionable source-level defect in the requested ASGI receive and request-body lifecycle behavior.

read_bounded_http_request_body() accepts the omitted body and more_body defaults. It rejects non-exact built-in event fields. It rejects an oversized partial body before another receive() call. It classifies http.disconnect separately from malformed events and lets CancelledError propagate.

The tests exercise every visible production control-flow outcome, including the non-callable receive branch added at this head. I did not run the tests or coverage. Therefore, I cannot certify exact-head statement, branch, docstring, or edge coverage. The queried commit statuses do not establish the full inherited-suite acceptance required by the PR objectives.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact head bcabe53aa6ebb901fa67b57cb86762b75c90c3c2. Focus on the new dual request-body resource bound: byte accumulation and receive-event count. Verify exact-boundary behavior, fail-before-event-N+1 semantics for repeated empty/tiny more_body=True events, configuration type/range checks, preservation of disconnect and CancelledError semantics, and whether the two changed files leave any statement/branch/docstring/edge gap. Do not transfer the prior f1dda8ed... review or any predecessor execution evidence.

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf 'HEAD '; git rev-parse HEAD
printf 'PR head '; gh pr view 443 --repo ContextualWisdomLab/Orgmetra --json headRefOid --jq '.headRefOid'
printf 'Head changed paths:\n'; git diff-tree --no-commit-id --name-only -r bcabe53aa6ebb901fa67b57cb86762b75c90c3c2
printf 'Candidate names:\n'; fd -t f '^(asgi_request_body\.py|test_asgi_request_body_lifecycle\.py|pyproject\.toml)$' | head -60
printf 'Changed commit overview:\n'; git show --format=fuller --stat --no-renames bcabe53aa6ebb901fa67b57cb86762b75c90c3c2 | head -90

Length of output: 1998


🏁 Script executed:

#!/bin/bash
set -euo pipefail
ast-grep outline services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py --items all
ast-grep outline services/product-composition-api/tests/test_asgi_request_body_lifecycle.py --items all
printf '\nModule:\n'; nl -ba services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py
printf '\nTests:\n'; nl -ba services/product-composition-api/tests/test_asgi_request_body_lifecycle.py
printf '\nHead diff:\n'; git show --format= --no-ext-diff bcabe53aa6ebb901fa67b57cb86762b75c90c3c2 -- services/product-composition-api/src/orgmetra_product_composition/asgi_request_body.py
printf '\nCoverage settings:\n'; rg -n -C3 'coverage|branch|docstring|edge|pytest' services/product-composition-api/pyproject.toml | head -150

Length of output: 21324


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf 'PR diff paths against base:\n'; git diff --name-only d58dc07034082a18a5de6c9f4df03d40b096a72f bcabe53aa6ebb901fa67b57cb86762b75c90c3c2
printf 'Receive reader references:\n'; rg -n -C3 '\bread_bounded_http_request_body\s*\(|\bCompositionRequestBodyTooManyEventsError\b' services/product-composition-api
printf 'Test file history (compact):\n'; git log -4 --oneline -- services/product-composition-api/tests/test_asgi_request_body_lifecycle.py
printf 'Other adjacent tests and files:\n'; fd -t f 'asgi_.*\.py' services/product-composition-api | head -60
printf 'Exact-head commit status:\n'; gh api repos/ContextualWisdomLab/Orgmetra/commits/bcabe53aa6ebb901fa67b57cb86762b75c90c3c2/status --jq '{state, statuses: [.statuses[] | {context, state, sha, updated_at}]}' || true

Length of output: 13935


@seonghobae, I reviewed exact head bcabe53aa6ebb901fa67b57cb86762b75c90c3c2. I found no source-level defect in the requested request-body behavior.

The reader accepts a terminal event in the final receive-event slot. If that event has more_body=True, the reader raises before calling receive() again. It accepts a body at the exact byte limit and rejects an oversized partial body before another receive call. Configuration checks reject invalid byte and event limits before receive I/O. http.disconnect remains a distinct lifecycle error, and CancelledError propagates.

Test gap: test_receive_event_limit_fails_before_waiting_beyond_budget() catches CompositionRequestBodyError, the parent type. It does not verify the new CompositionRequestBodyTooManyEventsError classification. The test also covers repeated empty chunks but not repeated tiny nonempty chunks. Testing both would protect the new contract more directly.

I found no obvious untested production control-flow outcome by source inspection. I did not run the tests or coverage, so I cannot certify statement, branch, docstring, or edge coverage for either changed file. The prior review and predecessor execution evidence do not establish acceptance for this head.

⚠️ Action not completed

Pull request base or head changed.

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.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please restart review on exact head 52a2fa0e6f2910e09d689d1985f8955db9b53e2e; the prior bcabe53... review request is stale. In addition to byte/event resource bounds, verify the new receive-capability contract: a callable returning a non-awaitable must fail as CompositionRequestBodyError rather than leaking raw TypeError, while exceptions/cancellation from a valid awaitable are not broadly reclassified. Please inspect statement/branch/docstring/edge completeness for both changed files. Do not transfer predecessor verdicts.

@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

@seonghobae, I’ll restart the review for exact head 52a2fa0e6f2910e09d689d1985f8955db9b53e2e. I’ll check the byte and receive-event bounds, the non-awaitable receive() failure, exception and cancellation propagation from valid awaitables, and statement, branch, docstring, and edge completeness in both changed files. I will not carry forward the predecessor verdicts or execution 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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant