Skip to content

feat: expose the wrapped transport as a public read-only property - #163

Merged
bagowix merged 3 commits into
mainfrom
feat/156-expose-wrapped-transport
Aug 12, 2026
Merged

feat: expose the wrapped transport as a public read-only property#163
bagowix merged 3 commits into
mainfrom
feat/156-expose-wrapped-transport

Conversation

@bagowix

@bagowix bagowix commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

Both httpx2/httpx transport wrappers kept the transport they wrap in a private
self._transport, while registry was already a public read-only property.
Verifying what a wrapper was actually built around — the pool limits, the TLS
context, the proxy — meant reading privates across two libraries
(transport._transport._pool._max_connections), so tests ended up asserting
constructor kwargs instead of the object that was built.

Both the synchronous and asynchronous transports now expose a read-only
wrapped property alongside registry, in interlock.integrations.httpx and
interlock.integrations.httpx2. The wrapped transport is fixed at
construction, so there is no setter.

CircuitBreakerAdapter (requests) inherits from HTTPAdapter and has no
equivalent inner object, and the aiohttp middleware wraps no transport, so the
change stays transport-specific — as scoped in the issue.

Additive only: a new property on existing classes, no behaviour change on any
request path (griffe check reports no API breakage).

Checklist

  • Tests added or updated (suite stays at 100% coverage)
  • uv run ruff format --check and uv run ruff check pass
  • uv run mypy, uv run pyright and uv run pyrefly check pass
  • Docs updated (docs/) for user-facing changes
  • CHANGELOG.md [Unreleased] updated
  • Commits follow Conventional Commits

Test plan: four unit tests (sync + async × httpx + httpx2) asserting the
property returns the exact transport passed in; written first, verified failing
with AttributeError before the property existed. Full suite: 771 passed,
2 skipped, coverage 100%. Docs examples were executed against both libraries.

Related issues

Closes #156

Added

  • Added read-only wrapped properties to synchronous and asynchronous CircuitBreakerTransport classes in the httpx and httpx2 extras.
  • Exposed the underlying transport through the public API alongside registry.

Changed

  • Updated integration and API documentation for wrapped.
  • Added tests for synchronous and asynchronous httpx and httpx2 transports.

The httpx2/httpx transports kept the transport they wrap in a private
`self._transport`, while `registry` was already public. Verifying what a
wrapper was built around — pool limits, TLS context, proxy — meant reading
privates across two libraries, so tests asserted constructor kwargs instead
of the object that was built.

Both the synchronous and asynchronous transports now expose `wrapped`
alongside `registry`. The requests adapter has no equivalent (it inherits
`HTTPAdapter`), so this stays transport-specific.

Closes #156
Both sides added a `### Added` block to the unreleased changelog; kept
both entries. The transports auto-merged: main's `call_sync`/`call_async`
fast path (#161) sits next to the new `wrapped` property untouched.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ec6d97f-88c8-4b4c-ac62-b1a635d8bd73

📥 Commits

Reviewing files that changed from the base of the PR and between 274df1b and 647eb6e.

📒 Files selected for processing (2)
  • docs/llms-full.txt
  • docs/reference.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/reference.md
  • docs/llms-full.txt
📜 Recent review details
⏰ Context from checks skipped due to timeout. (13)
  • GitHub Check: Platform smoke (windows-latest, Python 3.14)
  • GitHub Check: quality (3.14t)
  • GitHub Check: quality (3.13)
  • GitHub Check: Coverage
  • GitHub Check: quality (3.11)
  • GitHub Check: quality (3.14)
  • GitHub Check: Platform smoke (macos-latest, Python 3.14)
  • GitHub Check: Platform smoke (windows-latest, Python 3.11)
  • GitHub Check: Platform smoke (macos-latest, Python 3.11)
  • GitHub Check: quality (3.12)
  • GitHub Check: github-advanced-security
  • GitHub Check: GitGuardian Security Checks
  • GitHub Check: Analyze (python)
⚠️ CI failures not shown inline (2)

GitHub Actions: CodSpeed / Run benchmarks: feat: expose the wrapped transport as a public read-only property

Conclusion: failure

View job details

##[group]Run RUNNER_VERSION="5.0.1"
 �[36;1mRUNNER_VERSION="5.0.1"�[0m
 �[36;1mVERSION_TYPE="release"�[0m
 �[36;1m�[0m
 �[36;1mSKIP_HASH_CHECK_WARNING="false"�[0m
 �[36;1m�[0m
 �[36;1mif [ "$VERSION_TYPE" = "latest" ]; then�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available when using 'latest' version. Consider pinning a specific version for supply chain security."�[0m
 �[36;1m  fi�[0m
 �[36;1m  curl -fsSL https://codspeed.io/install.sh | bash -s -- --quiet�[0m
 �[36;1melif [ "$VERSION_TYPE" = "prerelease" ]; then�[0m
 �[36;1m  # Prereleases are not pinned, so install from the versioned installer without hash verification.�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available for prerelease version $RUNNER_VERSION."�[0m
 �[36;1m  fi�[0m
 �[36;1m  curl -fsSL "https://codspeed.io/v$RUNNER_VERSION/install.sh" | bash -s -- --quiet�[0m
 �[36;1melif [ "$VERSION_TYPE" = "branch" ]; then�[0m
 �[36;1m  # Install from specific branch using cargo�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available when installing from a branch."�[0m
 �[36;1m  fi�[0m
 �[36;1m  source $HOME/.cargo/env�[0m
 �[36;1m  cargo install --locked --git https://github.com/CodSpeedHQ/codspeed --branch "$RUNNER_VERSION" codspeed-runner�[0m
 �[36;1melif [ "$VERSION_TYPE" = "rev" ]; then�[0m
 �[36;1m  # Install from specific commit/rev using cargo�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available when installing from a revision."�[0m
 �[36;1m  fi�[0m
 �[36;1m  source $HOME/.cargo/env�[0m
 �[36;1m  cargo install --locked --git https://github.com/CodSpeedHQ/codspeed --rev "$RUNNER_VERSION" codspeed-runner�[0m
 �[36;1melse�[0m
 �[36;1m  # Release version - download to temp file and verify hash�...

GitHub Actions: CodSpeed / 0_Run benchmarks.txt: feat: expose the wrapped transport as a public read-only property

Conclusion: failure

View job details

##[group]Run RUNNER_VERSION="5.0.1"
 �[36;1mRUNNER_VERSION="5.0.1"�[0m
 �[36;1mVERSION_TYPE="release"�[0m
 �[36;1m�[0m
 �[36;1mSKIP_HASH_CHECK_WARNING="false"�[0m
 �[36;1m�[0m
 �[36;1mif [ "$VERSION_TYPE" = "latest" ]; then�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available when using 'latest' version. Consider pinning a specific version for supply chain security."�[0m
 �[36;1m  fi�[0m
 �[36;1m  curl -fsSL https://codspeed.io/install.sh | bash -s -- --quiet�[0m
 �[36;1melif [ "$VERSION_TYPE" = "prerelease" ]; then�[0m
 �[36;1m  # Prereleases are not pinned, so install from the versioned installer without hash verification.�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available for prerelease version $RUNNER_VERSION."�[0m
 �[36;1m  fi�[0m
 �[36;1m  curl -fsSL "https://codspeed.io/v$RUNNER_VERSION/install.sh" | bash -s -- --quiet�[0m
 �[36;1melif [ "$VERSION_TYPE" = "branch" ]; then�[0m
 �[36;1m  # Install from specific branch using cargo�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available when installing from a branch."�[0m
 �[36;1m  fi�[0m
 �[36;1m  source $HOME/.cargo/env�[0m
 �[36;1m  cargo install --locked --git https://github.com/CodSpeedHQ/codspeed --branch "$RUNNER_VERSION" codspeed-runner�[0m
 �[36;1melif [ "$VERSION_TYPE" = "rev" ]; then�[0m
 �[36;1m  # Install from specific commit/rev using cargo�[0m
 �[36;1m  if [ "$SKIP_HASH_CHECK_WARNING" != "true" ]; then�[0m
 �[36;1m    echo "::warning::Hash verification is not available when installing from a revision."�[0m
 �[36;1m  fi�[0m
 �[36;1m  source $HOME/.cargo/env�[0m
 �[36;1m  cargo install --locked --git https://github.com/CodSpeedHQ/codspeed --rev "$RUNNER_VERSION" codspeed-runner�[0m
 �[36;1melse�[0m
 �[36;1m  # Release version - download to temp file and verify hash�...

Walkthrough

HTTPX and HTTPX2 circuit-breaker transports expose their underlying sync or async transports through read-only wrapped properties. Tests verify identity, and documentation describes access and immutability.

Changes

Wrapped transport API

Layer / File(s) Summary
Transport properties and identity tests
interlock/integrations/httpx.py, interlock/integrations/httpx2.py, tests/test_httpx.py, tests/test_httpx2.py
Sync and async transport wrappers expose their delegated transport through wrapped. Tests verify that the property returns the original instance.
Documentation and release notes
docs/integrations/httpx.md, docs/integrations/httpx2.md, docs/llms-full.txt, docs/reference.md, CHANGELOG.md
Documentation describes wrapped as read-only, fixed at construction, and available on both transport variants.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested labels: enhancement

🚥 Pre-merge checks | ✅ 9
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title uses the required Conventional Commits format and accurately describes the public read-only property change.
Linked Issues check ✅ Passed The changes implement the read-only wrapped property for all four HTTPX transport classes and add the required tests and documentation for issue [#156].
Out of Scope Changes check ✅ Passed The changelog, documentation, implementation, and tests directly support issue [#156]; no unrelated code changes are present.
Zero-Dependency Core ✅ Passed The PR changes no core files outside interlock/integrations; pyproject.toml still has dependencies = []; interlock/init.py has no integrations re-export.
Changelog Entry ✅ Passed CHANGELOG.md gains a bullet under ## [Unreleased] describing the user-visible read-only wrapped property for synchronous and asynchronous transports.
Docs And Llm Mirror ✅ Passed The PR adds public wrapped APIs under interlock and updates both HTTPX integration pages plus reference.md; docs/llms-full.txt is changed in the same feature commit. No new docs page was added.
Tests Accompany Behaviour Change ✅ Passed The PR adds executable properties under interlock/ and changes tests/test_httpx.py and tests/test_httpx2.py with four matching wrapped-property tests.
Public Api Surface ✅ Passed Diff evidence shows no change to interlock/init.py and only execute-body changes in pipeline.py; exported names and public signatures remain unchanged.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/156-expose-wrapped-transport

Comment @coderabbitai help to get the list of available commands.

@codspeed-hq

codspeed-hq Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing feat/156-expose-wrapped-transport (647eb6e) with main (1d4c0f9)

Open in CodSpeed

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@bagowix

bagowix commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
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/reference.md`:
- Around line 199-201: Update the documentation around the per-host registry and
wrapped transport to qualify that close() and aclose() release registry breakers
only when the transport owns the registry; when a caller injects registry=...,
cleanup affects only the wrapped transport, so callers must close the injected
registry separately.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 059bca76-91d6-4e4c-8496-8e549c435816

📥 Commits

Reviewing files that changed from the base of the PR and between 1d4c0f9 and 274df1b.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • docs/integrations/httpx.md
  • docs/integrations/httpx2.md
  • docs/llms-full.txt
  • docs/reference.md
  • interlock/integrations/httpx.py
  • interlock/integrations/httpx2.py
  • tests/test_httpx.py
  • tests/test_httpx2.py
📜 Review details
⚠️ CI failures not shown inline (2)

GitHub Actions: Code scanning AI findings on PR #163 / 0_github-advanced-security.txt: Code scanning AI findings on PR #163

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "RUNNER_TEMP=$RUNNER_TEMP"�[0m
 �[36;1mfind "$RUNNER_TEMP" -maxdepth 1 -type f -name 'git-credentials-*.config' -print -delete�[0m
 �[36;1m�[0m
 �[36;1m# Generate a unique token and stop processing workflow commands to prevent the runtime from injecting commands�[0m
 �[36;1mSTOP_***REDACTED_SECRET_ASSIGNMENT*** /proc/sys/kernel/random/uuid)�[0m
 �[36;1m�[0m
 �[36;1m# Use a trap to ensure we always resume command processing and check for�[0m
 �[36;1m# fallback error annotations, even if the runtime exits with a non-zero code�[0m
 �[36;1m# (which would otherwise cause set -e to abort the shell before we get here).�[0m
 �[36;1m# The trap preserves the original exit code.�[0m
 �[36;1mcopilot_cleanup() {�[0m
 �[36;1m  �[0m
 �[36;1m  if [ -n "${GIT_PROXY_PID:-}" ] && kill -0 "$GIT_PROXY_PID" 2>/dev/null; then�[0m
 �[36;1m    echo "Stopping git-proxy (pid=$GIT_PROXY_PID)..."�[0m
 �[36;1m    kill "$GIT_PROXY_PID" 2>/dev/null || true�[0m
 �[36;1m    for _ in {1..25}; do�[0m
 �[36;1m      if ! kill -0 "$GIT_PROXY_PID" 2>/dev/null; then break; fi�[0m
 �[36;1m      sleep 0.2�[0m
 �[36;1m    done�[0m
 �[36;1m    if kill -0 "$GIT_PROXY_PID" 2>/dev/null; then�[0m
 �[36;1m      echo "git-proxy did not stop gracefully; forcing termination."�[0m
 �[36;1m      kill -KILL "$GIT_PROXY_PID" 2>/dev/null || true�[0m
 �[36;1m    fi�[0m
 �[36;1m    wait "$GIT_PROXY_PID" 2>/dev/null || true�[0m
 �[36;1m  fi�[0m
 �[36;1m  �[0m
 �[36;1m  echo "::$STOP_***REDACTED_SECRET_ASSIGNMENT***
 �[36;1m  FALLBACK_FILE="${RUNNER_TEMP}/copilot-fallback-error.txt"�[0m
 �[36;1m  if [ -f "$FALLBACK_FILE" ]; then�[0m
 �[36;1m    FALLBACK_MSG=$(head -c 500 "$FALLBACK_FILE" | tr -d '\n\r')�[0m
 �[36;1m    echo "::error title=Copilot Error::${FALLBACK_MSG}"�[0m

GitHub Actions: Code scanning AI findings on PR #163 / github-advanced-security: Code scanning AI findings on PR #163

Conclusion: failure

View job details

##[group]Run set -euo pipefail
 �[36;1mset -euo pipefail�[0m
 �[36;1mecho "RUNNER_TEMP=$RUNNER_TEMP"�[0m
 �[36;1mfind "$RUNNER_TEMP" -maxdepth 1 -type f -name 'git-credentials-*.config' -print -delete�[0m
 �[36;1m�[0m
 �[36;1m# Generate a unique token and stop processing workflow commands to prevent the runtime from injecting commands�[0m
 �[36;1mSTOP_***REDACTED_SECRET_ASSIGNMENT*** /proc/sys/kernel/random/uuid)�[0m
 �[36;1m�[0m
 �[36;1m# Use a trap to ensure we always resume command processing and check for�[0m
 �[36;1m# fallback error annotations, even if the runtime exits with a non-zero code�[0m
 �[36;1m# (which would otherwise cause set -e to abort the shell before we get here).�[0m
 �[36;1m# The trap preserves the original exit code.�[0m
 �[36;1mcopilot_cleanup() {�[0m
 �[36;1m  �[0m
 �[36;1m  if [ -n "${GIT_PROXY_PID:-}" ] && kill -0 "$GIT_PROXY_PID" 2>/dev/null; then�[0m
 �[36;1m    echo "Stopping git-proxy (pid=$GIT_PROXY_PID)..."�[0m
 �[36;1m    kill "$GIT_PROXY_PID" 2>/dev/null || true�[0m
 �[36;1m    for _ in {1..25}; do�[0m
 �[36;1m      if ! kill -0 "$GIT_PROXY_PID" 2>/dev/null; then break; fi�[0m
 �[36;1m      sleep 0.2�[0m
 �[36;1m    done�[0m
 �[36;1m    if kill -0 "$GIT_PROXY_PID" 2>/dev/null; then�[0m
 �[36;1m      echo "git-proxy did not stop gracefully; forcing termination."�[0m
 �[36;1m      kill -KILL "$GIT_PROXY_PID" 2>/dev/null || true�[0m
 �[36;1m    fi�[0m
 �[36;1m    wait "$GIT_PROXY_PID" 2>/dev/null || true�[0m
 �[36;1m  fi�[0m
 �[36;1m  �[0m
 �[36;1m  echo "::$STOP_***REDACTED_SECRET_ASSIGNMENT***
 �[36;1m  FALLBACK_FILE="${RUNNER_TEMP}/copilot-fallback-error.txt"�[0m
 �[36;1m  if [ -f "$FALLBACK_FILE" ]; then�[0m
 �[36;1m    FALLBACK_MSG=$(head -c 500 "$FALLBACK_FILE" | tr -d '\n\r')�[0m
 �[36;1m    echo "::error title=Copilot Error::${FALLBACK_MSG}"�[0m
🧰 Additional context used
📓 Path-based instructions (9)
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Document user-facing changes in English Markdown documentation and keep generated documentation mirrors synchronized.

Files:

  • docs/integrations/httpx.md
  • CHANGELOG.md
  • docs/integrations/httpx2.md
  • docs/reference.md
{interlock/**/*.py,docs/**/*.md,docs/llms-full.txt,docs/llms.txt}

📄 CodeRabbit inference engine (Custom checks)

When a change affects user-facing behaviour through the public API, integrations, or configuration options, update the relevant page under docs/ and regenerate docs/llms-full.txt; when adding a new documentation page, list it under ## Docs in docs/llms.txt.

Files:

  • docs/integrations/httpx.md
  • docs/integrations/httpx2.md
  • interlock/integrations/httpx2.py
  • interlock/integrations/httpx.py
  • docs/reference.md
  • docs/llms-full.txt
docs/**/*.md

⚙️ CodeRabbit configuration file

User-facing documentation. Check that code samples match the current public API and would actually run. A new page must also be listed in docs/llms.txt under ## Docs. Keep the existing voice: short sentences, no marketing.

Files:

  • docs/integrations/httpx.md
  • docs/integrations/httpx2.md
  • docs/reference.md
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Support Python 3.11 and newer; use Python 3.11+ features where required.
Keep the core zero-dependency and use only the standard library; external dependencies must be isolated behind optional integrations.
Use injected Clock instances for all time access; do not call time.monotonic() or sleep() directly in logic.
Implement the core as an I/O-free state machine with a single threading.Lock around the await-free critical section, never held across the protected call.
Use Protocols for extension points: Clock, SlidingWindow, Storage, FailureClassifier, and EventListener; do not inherit from internal classes.
Expose one public CircuitBreaker class for sync and async operation, with separate internal paths selected by coroutine detection.
Expose the public API through the package __init__.py; keep helpers underscore-prefixed and hidden.
Use absolute imports, placed at the top of the file, ordered as standard library, third-party, then local imports with blank lines between groups.
Use a maximum line length of 100 characters, single-quoted strings, f-strings, and pathlib.Path instead of os.path.
Annotate every parameter and return value; use modern generic syntax and X | None instead of Optional[X].
Use StrEnum or module-level constants instead of magic constants.
When a constructor or function has three or more arguments, pass them by keyword.
Keep functions focused on one job, generally no longer than 20–30 lines, with minimal side effects and extracted repeated loop logic.
Use async/await for I/O-bound work, asyncio.TaskGroup instead of asyncio.gather, and asyncio.to_thread or ProcessPoolExecutor for CPU-bound work.
Do not mix sync and async in one function; never await a sync callable or block on an async callable.
Fail fast on invalid input or state by raising immediately; do not continue with partial results or invented defaults.
Catch only expected exceptions, log them with context, and re-raise; do not use ...

Files:

  • tests/test_httpx.py
  • interlock/integrations/httpx2.py
  • interlock/integrations/httpx.py
  • tests/test_httpx2.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.py: Use pytest functions rather than test classes, with names formatted as test__unit_of_work__state_under_test__expected_behavior.
Mirror package layout in test filenames, use Arrange-Act-Assert, and create fixtures for repeated setup.
Use injected Clock instances for deterministic tests; do not use sleep() in tests.
Use pytest-asyncio and @pytest.mark.asyncio for asynchronous tests, and use pytest-mock to isolate external dependencies.
Use Hypothesis property-based tests for the state machine and cover all transitions and races.
Write the reproducing test before a bug fix and specify the required behavior before implementing a feature.

Files:

  • tests/test_httpx.py
  • tests/test_httpx2.py

⚙️ CodeRabbit configuration file

pytest functions only, never test classes. Names follow test__unit_of_work__state_under_test__expected_behavior in lower case. One behaviour per test, Arrange-Act-Assert. Time is the injected fake Clock — any real sleep or wall-clock read is flakiness, flag it. Async tests use @pytest.mark.asyncio; state-machine work carries hypothesis property tests. Coverage must stay at 100%: point out uncovered branches the diff introduces. Tests run under -n auto, so anything relying on ordering or shared global state is a bug.

Files:

  • tests/test_httpx.py
  • tests/test_httpx2.py
CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

Add every change to the [Unreleased] section under Added, Fixed, or Changed, explaining user impact rather than only symbol movement.

Files:

  • CHANGELOG.md

⚙️ CodeRabbit configuration file

Keep a Changelog format. New entries go under ## [Unreleased] in Added / Fixed / Changed. An entry describes what a user could not do before and can now, not which symbol moved. Only the release commit dates a section and updates the link references.

Files:

  • CHANGELOG.md
interlock/**/*.py

📄 CodeRabbit inference engine (Custom checks)

Every production behaviour change in interlock/ must be accompanied by a change under tests/; changes limited to docstrings, comments, or type annotations are exempt. Bug fixes must include at least one regression test that fails without the production fix.

Files:

  • interlock/integrations/httpx2.py
  • interlock/integrations/httpx.py

⚙️ CodeRabbit configuration file

Core rules (AGENTS.md is authoritative): (1) Zero-dependency core — anything under interlock/ except interlock/integrations/ may import stdlib only. Flag every third-party import as a blocking issue. (2) No fallbacks, no silent excepts, no a or b or c for required config or data, no hidden retries. Invalid input or state raises immediately. interlock/_notify.py is the one sanctioned swallow (listener hooks are observability, logged with traceback, BaseException still propagates) — do not suggest generalising or "fixing" it. (3) Time comes only from the injected Clock protocol; direct time.monotonic()/time.sleep() in library logic is a bug. (4) Style: 100-char lines, single quotes, f-strings, pathlib, full annotations, X | None never Optional[X], keyword arguments for calls with 3+ arguments, no magic constants (StrEnum or module constants), functions under ~30 lines. (5) Extension points are Protocols (Clock, SlidingWindow, Storage, FailureClassifier, EventListener) — do not propose inheriting internal classes. (6) Sync and async live in one CircuitBreaker with separate internal paths; never propose Sync*/Async* twins and never mix the two paths in one function. (7) Public API is exported from interlock/init.py; everything else is underscore-prefixed. New public symbols need __all__ and a docstring. (8) Python 3.11 is the floor — no 3.12+ syntax or stdlib.

Files:

  • interlock/integrations/httpx2.py
  • interlock/integrations/httpx.py
interlock/integrations/**/*.py

⚙️ CodeRabbit configuration file

Optional extras. The third-party import must stay inside this package, must never be re-exported from interlock/init.py, and a missing extra must fail with a clear install hint rather than a fallback. Wrap the dependency behind the project's own types so its objects do not leak into core signatures. Check that the extra is declared in pyproject.toml [project.optional-dependencies] and documented under docs/integrations/.

Files:

  • interlock/integrations/httpx2.py
  • interlock/integrations/httpx.py
docs/llms-full.txt

⚙️ CodeRabbit configuration file

Generated artefact — produced by uv run python scripts/build_llms_full.py. Do not review its content or suggest edits; only confirm it was regenerated together with the docs/ changes in the same PR.

Files:

  • docs/llms-full.txt
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: bagowix/interlock PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-08-07T15:34:32.493Z
Learning: Applies to **/*.py : Expose one public `CircuitBreaker` class for sync and async operation, with separate internal paths selected by coroutine detection.
📚 Learning: 2026-08-07T15:34:32.493Z
Learnt from: CR
Repo: bagowix/interlock PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-08-07T15:34:32.493Z
Learning: Applies to **/*.py : Expose one public `CircuitBreaker` class for sync and async operation, with separate internal paths selected by coroutine detection.

Applied to files:

  • tests/test_httpx.py
  • interlock/integrations/httpx2.py
  • interlock/integrations/httpx.py
  • tests/test_httpx2.py
📚 Learning: 2026-08-07T15:34:59.595Z
Learnt from: CR
Repo: bagowix/interlock PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-08-07T15:34:59.595Z
Learning: Applies to {interlock/**/*.py,docs/**/*.md,docs/llms-full.txt,docs/llms.txt} : When a change affects user-facing behaviour through the public API, integrations, or configuration options, update the relevant page under `docs/` and regenerate `docs/llms-full.txt`; when adding a new documentation page, list it under `## Docs` in `docs/llms.txt`.

Applied to files:

  • docs/llms-full.txt
🔇 Additional comments (8)
interlock/integrations/httpx.py (1)

224-228: LGTM!

Also applies to: 322-326

interlock/integrations/httpx2.py (1)

224-228: LGTM!

Also applies to: 323-327

tests/test_httpx.py (1)

227-233: LGTM!

Also applies to: 560-566

tests/test_httpx2.py (1)

210-216: LGTM!

Also applies to: 414-420

docs/integrations/httpx.md (1)

163-183: LGTM!

docs/integrations/httpx2.md (1)

169-189: LGTM!

docs/llms-full.txt (1)

2940-2960: LGTM!

Also applies to: 3185-3205, 4519-4521, 4536-4538

CHANGELOG.md (1)

30-36: LGTM!

Comment thread docs/reference.md Outdated
`close()` / `aclose()` release the wrapped transport unconditionally, but
close breakers only when the transport owns the registry — an injected one
stays open for its owner to close. The httpx2/httpx sections of the
reference stated the unqualified version; the integration pages already
carried the caveat.
@bagowix
bagowix merged commit 8d8e62e into main Aug 12, 2026
21 of 24 checks passed
@bagowix
bagowix deleted the feat/156-expose-wrapped-transport branch August 12, 2026 18:14
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.

Expose the wrapped transport as a public read-only property

1 participant