feat: let the registry enumerate the breakers it created - #162
Conversation
`Registry` could only be asked about a name you already knew — `get`, `get_existing`, `close_all`, `aclose_all`. That is exactly the case that does not hold where the registry matters most: every HTTP integration creates its breakers lazily, one per host, so the set of names only exists at runtime. Listing them for a diagnostics endpoint during a `METRICS_ONLY` rollout, or applying an operator override to all of them before a maintenance window, meant reaching into the private `_breakers` dict. `names()` and `items()` return that set as an immutable point-in-time copy taken under the registry lock, mirroring what `_snapshot()` already does for teardown: a breaker created afterwards is not in it, and the returned tuple never changes. Closes #157
Both sides added a `### Added` entry to the unreleased changelog; kept both, main's `call_sync`/`call_async` entry first.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ Context from checks skipped due to timeout. (13)
|
| Layer / File(s) | Summary |
|---|---|
Implement and validate snapshot methods interlock/registry.py, tests/test_registry.py |
Added names() and items() with point-in-time tuple semantics. Tests cover empty registries, created breakers, and later creations. |
Document the public API docs/reference.md, docs/llms-full.txt |
Documented return values, lock-protected snapshots, and breaker inspection examples. |
Document runtime registry diagnostics README.md, docs/guides/states.md, docs/integrations/*, CHANGELOG.md |
Documented enumeration of breakers created by HTTP integrations and bulk inspection actions. |
Estimated code review effort: 2 (Simple) | ~10 minutes
Possibly related PRs
- bagowix/interlock#149: Both PRs modify the shared
Registryused by HTTP integrations. - bagowix/interlock#151: Both PRs modify
Registryusage and transport-facing breaker key semantics.
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 feat prefix, lowercase imperative wording, no period, and clearly describes registry enumeration. |
| Linked Issues check | ✅ Passed | The implementation, tests, and documentation satisfy issue #157 with lock-protected immutable snapshots from names() and items(). |
| Out of Scope Changes check | ✅ Passed | All code, tests, and documentation changes directly support the Registry enumeration objective in issue #157. |
| Zero-Dependency Core | ✅ Passed | The feature diff changes only interlock/registry.py, adding no imports; pyproject dependencies remains []; init.py has no interlock.integrations re-export. |
| Changelog Entry | ✅ Passed | The PR diff adds a bullet under ## [Unreleased] describing public Registry.names() and items() and their snapshot behavior. |
| Docs And Llm Mirror | ✅ Passed | Public Registry.names/items were added; docs/reference.md and affected guide/integration pages were updated, and docs/llms-full.txt contains matching changes. No new docs page was added. |
| Tests Accompany Behaviour Change | ✅ Passed | The PR adds substantive methods in interlock/registry.py and changes tests/test_registry.py with six tests for names() and items(). |
| Public Api Surface | ✅ Passed | The merge-base diff changes neither interlock/init.py nor pipeline.py; exported names and public declarations/signatures are identical. |
✨ 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/registry-enumeration
Comment @coderabbitai help to get the list of available commands.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests/test_registry.py (1)
132-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract repeated
Registry()setup into a pytest fixture.The six tests duplicate the same registry construction. Move it to a fixture and inject the fixture into each test.
As per coding guidelines, “create fixtures for repeated setup.”
Also applies to: 138-140, 146-147, 156-156, 162-164, 170-171
🤖 Prompt for 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. In `@tests/test_registry.py` at line 132, Extract the repeated Registry() construction into a pytest fixture in the test module, then inject that fixture into all six affected tests instead of creating local Registry instances. Preserve each test’s existing behavior while reusing the fixture value.Source: Coding guidelines
🤖 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/integrations/httpx.md`:
- Around line 74-75: Update the transport or middleware diagnostics paragraphs
in docs/integrations/httpx.md lines 74-75, docs/integrations/httpx2.md lines
78-79, docs/integrations/aiohttp.md lines 126-128, and
docs/integrations/requests.md lines 130-132 to document both names() and
items(). State that both return fixed point-in-time listings, so breakers
created after enumeration are excluded.
---
Nitpick comments:
In `@tests/test_registry.py`:
- Line 132: Extract the repeated Registry() construction into a pytest fixture
in the test module, then inject that fixture into all six affected tests instead
of creating local Registry instances. Preserve each test’s existing behavior
while reusing the fixture value.
🪄 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: 556921a6-ea6b-44ac-bc8c-84cbec07cc98
📒 Files selected for processing (11)
CHANGELOG.mdREADME.mddocs/guides/states.mddocs/integrations/aiohttp.mddocs/integrations/httpx.mddocs/integrations/httpx2.mddocs/integrations/requests.mddocs/llms-full.txtdocs/reference.mdinterlock/registry.pytests/test_registry.py
📜 Review details
⏰ Context from checks skipped due to timeout. (11)
- GitHub Check: quality (3.11)
- GitHub Check: Platform smoke (macos-latest, Python 3.11)
- GitHub Check: quality (3.12)
- GitHub Check: Platform smoke (windows-latest, Python 3.14)
- GitHub Check: Platform smoke (macos-latest, Python 3.14)
- GitHub Check: Platform smoke (windows-latest, Python 3.11)
- GitHub Check: Coverage
- GitHub Check: quality (3.14t)
- GitHub Check: quality (3.14)
- GitHub Check: quality (3.13)
- GitHub Check: Run benchmarks
⚠️ CI failures not shown inline (2)
GitHub Actions: Code scanning AI findings on PR #162 / github-advanced-security: Code scanning AI findings on PR #162
Conclusion: failure
##[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 #162 / 0_github-advanced-security.txt: Code scanning AI findings on PR #162
Conclusion: failure
##[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.mddocs/integrations/requests.mddocs/guides/states.mdCHANGELOG.mdREADME.mddocs/integrations/aiohttp.mddocs/reference.mddocs/integrations/httpx2.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 regeneratedocs/llms-full.txt; when adding a new documentation page, list it under## Docsindocs/llms.txt.
Files:
docs/integrations/httpx.mddocs/integrations/requests.mddocs/guides/states.mddocs/integrations/aiohttp.mdinterlock/registry.pydocs/llms-full.txtdocs/reference.mddocs/integrations/httpx2.md
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.mddocs/integrations/requests.mddocs/guides/states.mddocs/integrations/aiohttp.mddocs/reference.mddocs/integrations/httpx2.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 injectedClockinstances for all time access; do not calltime.monotonic()orsleep()directly in logic.
Implement the core as an I/O-free state machine with a singlethreading.Lockaround the await-free critical section, never held across the protected call.
UseProtocols for extension points:Clock,SlidingWindow,Storage,FailureClassifier, andEventListener; do not inherit from internal classes.
Expose one publicCircuitBreakerclass 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, andpathlib.Pathinstead ofos.path.
Annotate every parameter and return value; use modern generic syntax andX | Noneinstead ofOptional[X].
UseStrEnumor 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.
Useasync/awaitfor I/O-bound work,asyncio.TaskGroupinstead ofasyncio.gather, andasyncio.to_threadorProcessPoolExecutorfor 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_registry.pyinterlock/registry.py
tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
tests/**/*.py: Use pytest functions rather than test classes, with names formatted astest__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 injectedClockinstances for deterministic tests; do not usesleep()in tests.
Usepytest-asyncioand@pytest.mark.asynciofor asynchronous tests, and usepytest-mockto 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_registry.py
⚙️ CodeRabbit configuration file
pytest functions only, never test classes. Names follow
test__unit_of_work__state_under_test__expected_behaviorin 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_registry.py
CHANGELOG.md
📄 CodeRabbit inference engine (AGENTS.md)
Add every change to the
[Unreleased]section underAdded,Fixed, orChanged, 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 undertests/; 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/registry.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 cfor 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 | NoneneverOptional[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/registry.py
{interlock/*.py,interlock/!(integrations)/**/*.py,pyproject.toml}
📄 CodeRabbit inference engine (Custom checks)
Keep the core zero-dependency: files under
interlock/outsideinterlock/integrations/may import only the standard library or otherinterlockmodules;[project] dependenciesinpyproject.tomlmust remain empty; andinterlock/__init__.pymust not re-export frominterlock.integrations.
Files:
interlock/registry.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)
📚 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 CHANGELOG.md : Add every change to the `[Unreleased]` section under `Added`, `Fixed`, or `Changed`, explaining user impact rather than only symbol movement.
Applied to files:
CHANGELOG.md
📚 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:
CHANGELOG.md
📚 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
🪛 LanguageTool
CHANGELOG.md
[style] ~21-~21: To form a complete sentence, be sure to include a subject.
Context: ...as an immediate success. - **Registry can now be enumerated: names() and `items...
(MISSING_IT_THERE)
[style] ~22-~22: Consider an alternative for the overused word “exactly”.
Context: ...about a name you already knew, which is exactly the case that does not hold where it ...
(EXACTLY_PRECISELY)
[locale-violation] ~28-~28: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...r the registry lock — a breaker created afterwards is not in it, and the returned tuple ...
(AFTERWARDS_US)
docs/reference.md
[locale-violation] ~68-~68: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...er the registry lock: a breaker created afterwards is not in it, and the returned tuple ne...
(AFTERWARDS_US)
🔇 Additional comments (3)
docs/guides/states.md (1)
118-127: 📐 Maintainability & Code QualityConfirm the generated documentation mirror.
docs/llms-full.txtis not included in the supplied files, so this review cannot confirm that the new Registry enumeration guidance was regenerated there.As per path instructions:
docs/llms-full.txtis a generated artefact and must be regenerated with thedocs/changes in the same PR.Source: Path instructions
README.md (1)
97-98: LGTM!CHANGELOG.md (1)
21-29: LGTM!
…uides The four HTTP integration pages mentioned only `items()` and left the snapshot boundary to the reference, so the page a reader lands on while debugging a per-host breaker did not say that the listing is fixed.
There was a problem hiding this comment.
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/integrations/httpx.md`:
- Around line 75-77: Update the integration guides to consistently describe
resolved breaker names: in docs/integrations/httpx.md lines 75-77 and
docs/integrations/httpx2.md lines 79-81, show cached-breaker lookup with
get_existing(name) and describe names() and items() as point-in-time snapshots
of resolved breaker names; in docs/integrations/aiohttp.md lines 127-129 and
docs/integrations/requests.md lines 131-133, document the returned resolved
breaker name rather than the raw request host.
🪄 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: dd7abd94-49aa-4571-8037-abe2992aeaf2
📒 Files selected for processing (5)
docs/integrations/aiohttp.mddocs/integrations/httpx.mddocs/integrations/httpx2.mddocs/integrations/requests.mddocs/llms-full.txt
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/llms-full.txt
📜 Review details
⏰ Context from checks skipped due to timeout. (13)
- GitHub Check: github-advanced-security
- GitHub Check: quality (3.14t)
- GitHub Check: Coverage
- GitHub Check: quality (3.11)
- GitHub Check: quality (3.12)
- GitHub Check: Platform smoke (windows-latest, Python 3.14)
- GitHub Check: Platform smoke (macos-latest, Python 3.14)
- GitHub Check: Platform smoke (macos-latest, Python 3.11)
- GitHub Check: Platform smoke (windows-latest, Python 3.11)
- GitHub Check: quality (3.14)
- GitHub Check: quality (3.13)
- GitHub Check: Run benchmarks
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Document user-facing changes in English Markdown documentation and keep generated documentation mirrors synchronized.
Files:
docs/integrations/aiohttp.mddocs/integrations/httpx.mddocs/integrations/httpx2.mddocs/integrations/requests.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 regeneratedocs/llms-full.txt; when adding a new documentation page, list it under## Docsindocs/llms.txt.
Files:
docs/integrations/aiohttp.mddocs/integrations/httpx.mddocs/integrations/httpx2.mddocs/integrations/requests.md
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/aiohttp.mddocs/integrations/httpx.mddocs/integrations/httpx2.mddocs/integrations/requests.md
🧠 Learnings (2)
📓 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: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/integrations/httpx.md
🪛 LanguageTool
docs/integrations/aiohttp.md
[locale-violation] ~128-~128: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...me copies, without the hosts first seen afterwards. Use an EventListener for production ...
(AFTERWARDS_US)
docs/integrations/httpx.md
[locale-violation] ~76-~76: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...point-in-time copies: a host first seen afterwards is not in them. After tuning threshold...
(AFTERWARDS_US)
docs/integrations/httpx2.md
[locale-violation] ~80-~80: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...point-in-time copies: a host first seen afterwards is not in them. After tuning threshold...
(AFTERWARDS_US)
docs/integrations/requests.md
[locale-violation] ~132-~132: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...me copies, without the hosts first seen afterwards. Use an EventListener for production ...
(AFTERWARDS_US)
| runtime, so `transport.registry.items()` lists the breakers created so far and | ||
| `names()` just their hosts. Both are point-in-time copies: a host first seen | ||
| afterwards is not in them. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Use resolved breaker names consistently across the integration guides.
The registry key can differ from the request host when name_resolver is configured. The documentation must use get_existing(name) and describe names() and items() in terms of resolved breaker names.
docs/integrations/httpx.md#L75-L77: replace “their hosts” with resolved breaker-name wording and useget_existing(name).docs/integrations/httpx2.md#L79-L81: replace host-based enumeration wording with resolved breaker-name wording and useget_existing(name).docs/integrations/aiohttp.md#L127-L129: document the returned breaker name rather than the raw host.docs/integrations/requests.md#L131-L133: document the returned breaker name rather than the raw host.
As per path instructions: use get_existing(name) to inspect a cached breaker and describe names() and items() as snapshots of breakers created so far.
🧰 Tools
🪛 LanguageTool
[locale-violation] ~76-~76: In American English, ‘afterward’ is the preferred variant. ‘Afterwards’ is more commonly used in British English and other dialects.
Context: ...point-in-time copies: a host first seen afterwards is not in them. After tuning threshold...
(AFTERWARDS_US)
📍 Affects 4 files
docs/integrations/httpx.md#L75-L77(this comment)docs/integrations/httpx2.md#L79-L81docs/integrations/aiohttp.md#L127-L129docs/integrations/requests.md#L131-L133
🤖 Prompt for 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.
In `@docs/integrations/httpx.md` around lines 75 - 77, Update the integration
guides to consistently describe resolved breaker names: in
docs/integrations/httpx.md lines 75-77 and docs/integrations/httpx2.md lines
79-81, show cached-breaker lookup with get_existing(name) and describe names()
and items() as point-in-time snapshots of resolved breaker names; in
docs/integrations/aiohttp.md lines 127-129 and docs/integrations/requests.md
lines 131-133, document the returned resolved breaker name rather than the raw
request host.
Source: Path instructions
The host is only the default breaker key: a configured `name_resolver` makes `names()` return whatever it produced, so wording the listing as "hosts" was wrong for exactly the users who reach for the knob.
|
Good catch on the resolver — applied in part (160d80c). Applied: the enumeration wording no longer says "hosts". Not changed: the surrounding |
Summary
Registrycould only be asked about a name you already knew —get,get_existing,close_all,aclose_all. That is exactly the case that doesnot hold where the registry matters most: every HTTP integration creates its
breakers lazily, one per host, so the set of names only exists at runtime.
Listing them for a diagnostics endpoint during a
METRICS_ONLYrollout, orapplying an operator override to all of them before a maintenance window, meant
reaching into the private
_breakersdict.Both return an immutable point-in-time copy taken under the registry lock,
mirroring what
_snapshot()already does for teardown: a breaker createdafterwards is not in it, and the returned tuple never changes.
names()coversthe "which hosts exist" question on its own;
items()pairs each breaker withits name, which
_snapshot()cannot — it returns breakers only, enough forteardown but not for a diagnostics listing.
No
__iter__/__len__: a live view over a dict mutated under a lock is thewrong shape here, and explicit copy-returning methods make the snapshot
semantics obvious at the call site.
Docs: reference, the safe-rollout section of the states guide (bulk operator
action), the four transport integration pages and the README diagnostics
paragraph, plus the regenerated
llms-full.txt.Checklist
uv run ruff format --checkanduv run ruff checkpassuv run mypy,uv run pyrightanduv run pyrefly checkpassdocs/) for user-facing changesCHANGELOG.md[Unreleased]updateduv run griffe check interlock --search .is clean — the change is purelyadditive.
_state_machine.py/_engine.pyare untouched, so no mutmut run.Related issues
Closes #157
Added
Registry.names()to return an immutable snapshot of cached breaker names.Registry.items()to return an immutable snapshot of(name, CircuitBreaker)pairs.Changed
Registry.names()andRegistry.items().