Lessons-Learned Catalog
A catalog of recurring Python production mistakes drawn from case studies and incident themes - with prevention patterns so teams stop paying the same interest on tech debt.
Search across all documentation pages
A catalog of recurring Python production mistakes drawn from case studies and incident themes - with prevention patterns so teams stop paying the same interest on tech debt.
Quick-reference recipe card - copy-paste ready.
## Lesson template
**ID:** LL-014
**Pattern:** Async route calls sync ORM
**Impact:** p95 outage, low CPU
**Prevention:** AST CI check + asyncio.to_thread for CPU
**See:** Before/After Async MigrationWhen to reach for this:
### Web & API
| ID | Lesson | Prevention |
| LL-001 | Mutable default args in hot path | pytest lint; code review checklist |
| LL-002 | Missing tenant_id filter on query | repository requires tenant context |
| LL-003 | Webhook without idempotency | Idempotency-Key table |
| LL-004 | Sync sleep in async middleware | scripts/check_async_blocking.py |
### Data & Migrations
| LL-010 | Index migration without CONCURRENTLY | migration linter + row count gate |
| LL-011 | Staging 1% row count hides locks | large table seed script |
| LL-012 | Non-idempotent ETL append | MERGE on natural key |
### ML & Batch
| LL-020 | Training-serving skew | shared features package |
| LL-021 | No eval gate on promote | min AUC in train CI job |
| LL-022 | Notebook creds in git | secrets via orchestrator only |
### Ops & Delivery
| LL-030 | API rolled back, workers not paused | deploy-order.md mandatory |
| LL-031 | :latest prod tag | immutable SHA tags |
| LL-032 | Alert on ERROR log count | SLO burn alerts |"""lessons_registry.py - optional machine-readable index."""
LESSONS = {
"LL-004": {
"title": "Sync sleep in async middleware",
"guardrail": "scripts/check_async_blocking.py",
"doc": "./before-after-sync-to-async-migration/before-after-sync-to-async-migration.md",
},
}What this demonstrates:
## Post-mortem action → catalog
Action G2 "async CI check" closes → add LL-004 if not present| Alternative | Use When | Don't Use When |
|---|---|---|
| Wiki only | Quick start | Drift from repo |
| Incident database only | Rich search | No onboarding narrative |
| Lint rules without catalog | Tiny team | Need human context why |
| External blameless blog | Marketing | Internal operational detail |
Post-mortem owner proposes; platform curator approves format.
Grow organically; top 10 list stays stable; full catalog may reach 50+.
Yes - ADR references LL ID when decision triggered by incident pattern.
Add eval drift, prompt injection guardrails as ML section grows.
Internal only; exec summaries separate.
Checkbox in onboarding ticket linking to top 10 doc.
Increment occurrence note; strengthen guardrail priority.
Scaffold template enforces prevention by default for new services.
grep LL- IDs in repo; optional JSON registry for portal.
Each reference/before-after doc contributes 2-3 lessons on publish.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026