From 317c416688f46bc70a6fb663c6cbc684366bd8cc Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Fri, 26 Jun 2026 22:49:34 +0300 Subject: [PATCH 1/2] test: assert .orig invariant and add cycle-with-retriable-link case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Folds the two deferred Minor findings from the final review: - _make_dbapi_error now asserts err.orig is not None, making the load-bearing invariant explicit. - Adds a complementary cycle case whose loop contains a retriable DBAPIError node (returns True) — companion to the terminate-on-cycle test that returns False. just test → 25 passed, 100% coverage. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_retriable.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_retriable.py b/tests/test_retriable.py index afbc0d2..93b4743 100644 --- a/tests/test_retriable.py +++ b/tests/test_retriable.py @@ -8,7 +8,9 @@ def _make_dbapi_error(cause: BaseException) -> DBAPIError: orig = Exception("db error") orig.__cause__ = cause - return DBAPIError("SELECT 1", None, orig) + err = DBAPIError("SELECT 1", None, orig) + assert err.orig is not None # the predicate hinges on .orig being set; make the invariant explicit + return err def test_retriable_asyncpg_errors_contains_expected_classes() -> None: @@ -55,3 +57,13 @@ def test_is_retriable_cause_cycle_terminates() -> None: a.__cause__ = b b.__cause__ = a assert is_retriable(a) is False + + +def test_is_retriable_cycle_containing_retriable_link() -> None: + # A cyclic chain that *contains* a retriable DBAPIError still returns True: + # the walk finds the retriable link before the cycle guard would re-visit a node. + outer = ValueError("outer") + dbapi_err = _make_dbapi_error(asyncpg.SerializationError()) + outer.__cause__ = dbapi_err + dbapi_err.__cause__ = outer + assert is_retriable(outer) is True From 97107b82e10913a291bf1c8e2481b0d772a2e4d0 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Fri, 26 Jun 2026 22:54:59 +0300 Subject: [PATCH 2/2] docs: lightweight bundle for retriable test hardening Co-Authored-By: Claude Opus 4.8 (1M context) --- .../change.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 planning/changes/2026-06-26.02-retriable-test-hardening/change.md diff --git a/planning/changes/2026-06-26.02-retriable-test-hardening/change.md b/planning/changes/2026-06-26.02-retriable-test-hardening/change.md new file mode 100644 index 0000000..7dfdfed --- /dev/null +++ b/planning/changes/2026-06-26.02-retriable-test-hardening/change.md @@ -0,0 +1,37 @@ +--- +summary: Hardened tests/test_retriable.py — made the `.orig` invariant explicit in the helper and added a cycle case whose loop contains a retriable DBAPIError link. +--- + +# Change: Harden the retriable predicate tests + +**Lane:** lightweight — ≲30 LOC net, ≤2 files, no new file, no public-API +change, a single straightforward test. + +## Goal + +Fold the two deferred Minor findings from the [retriable-error-seam +review](../2026-06-26.01-retriable-error-seam/design.md)'s final whole-branch +pass into the test suite, so the predicate's invariants are explicit rather than +implicit. + +## Approach + +Test-only hardening of the in-memory predicate suite. No production code or +capability contract changes, so no `architecture/` promotion. + +- The `_make_dbapi_error` helper now asserts `err.orig is not None`. The whole + matrix hinges on `.orig` being set (the predicate reads `.orig.__cause__`); + the assertion makes that load-bearing invariant explicit instead of relying on + the True-expected cases to fail if it ever broke. +- A new case complements `test_is_retriable_cause_cycle_terminates`: a cyclic + chain that *contains* a retriable `DBAPIError` link returns `True` — the walk + finds the link before the cycle guard would re-visit a node. + +## Files + +- `tests/test_retriable.py` — assertion in the helper; one new cycle-with-link test. + +## Verification + +- [x] `just test` — full suite green (25 passed, 100% coverage). +- [x] `just lint-ci` — clean.