Skip to content

feat: give the retriable-error predicate its own seam#22

Merged
lesnik512 merged 8 commits into
mainfrom
feat/retriable-error-seam
Jun 26, 2026
Merged

feat: give the retriable-error predicate its own seam#22
lesnik512 merged 8 commits into
mainfrom
feat/retriable-error-seam

Conversation

@lesnik512

Copy link
Copy Markdown
Member

What & why

Moves the retriable-error decision behind a pure is_retriable(exc) -> bool seam so it's tested in memory instead of through a live Postgres round-trip. The classification logic (unwrap DBAPIError, classify the asyncpg error, walk the __cause__/__context__ chain) was the deepest code in the package but sat behind the wrong seam — its only test surface was a stored proc raising a chosen SQLSTATE.

Behaviour-preserving refactor: same retriable classes in, same out, same logs, same surfaced exception.

Changes

  • db_retry/retriable.py (new) — pure is_retriable + named RETRIABLE_ASYNCPG_ERRORS taxonomy. No logger, no side effects. Walk order and cycle guard lifted verbatim.
  • db_retry/retry.py — consumes the seam via a thin _log_and_decide wrapper that preserves both debug lines verbatim; deletes the two old private functions. is_retriable is an internal seamnot added to __all__; the package keeps its five public symbols.
  • tests/test_retriable.py (new) — in-memory classification matrix built from real DBAPIError/asyncpg types (40001, 08000, an 08-subclass, non-retriable, re-wrapped RepositoryError.__cause__ chain, __context__-only, a __cause__ cycle, bare non-DBAPI).
  • tests/test_retry.py — trimmed to wiring proofs: one parametrized retriable/non-retriable pair + the retries= override, proving the decorator wires the predicate into tenacity and reraise=True surfaces the original error.
  • Architecture promotion — new architecture/retriable.md; cause-chain prose moved out of retry.md; README.md capability index updated; architecture/glossary.md authored with the Retriable error term.
  • Planning — Full-lane bundle under planning/changes/2026-06-26.01-retriable-error-seam/ (design.md + plan.md).

Verification

  • just test (Docker Postgres) → 24 passed, 100% coverage
  • just lint-ci → all checks pass (ruff format/check, ty, eof-fixer, planning)
  • Built test-first (TDD); executed via subagent-driven-development with per-task spec+quality review and a final whole-branch review (Ready to merge: Yes, no Critical/Important findings).

🤖 Generated with Claude Code

lesnik512 and others added 8 commits June 26, 2026 22:03
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pure is_retriable(exc) -> bool in db_retry/retriable.py; walks __cause__/__context__ chain
with cycle guard to classify retriable DBAPIErrors without a live database.
Reduce test_postgres_retry to two rows (40001 retriable, 40002
non-retriable). Delete test_postgres_retry_advanced_alchemy (covered
by test_retriable.py). Remove unused advanced_alchemy imports.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lesnik512 lesnik512 merged commit 8cd91fb into main Jun 26, 2026
2 checks passed
@lesnik512 lesnik512 deleted the feat/retriable-error-seam branch June 26, 2026 19:44
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