| # Project-level configuration for tooling. The runtime app itself is still | |
| # driven by requirements.txt — this file exists so pytest/ruff/coverage pick | |
| # up a consistent config. | |
| [tool.pytest.ini_options] | |
| minversion = "8.0" | |
| testpaths = ["tests"] | |
| pythonpath = ["."] | |
| asyncio_mode = "auto" | |
| # Quiet the deprecation noise from dependencies we don't own (passlib's | |
| # crypt removal in Py3.13, pydantic v1 shims, etc.) so real test signal | |
| # stands out. | |
| filterwarnings = [ | |
| "ignore::DeprecationWarning:passlib.*", | |
| "ignore::DeprecationWarning:pydantic.*", | |
| "ignore:`torch.jit.script` is deprecated:DeprecationWarning", | |
| ] | |
| addopts = [ | |
| "-ra", | |
| "--strict-markers", | |
| "--strict-config", | |
| "--tb=short", | |
| ] | |
| markers = [ | |
| "slow: marks tests that take >1s (deselect with '-m \"not slow\"')", | |
| "integration: marks tests that require a real external dependency", | |
| ] | |
| [tool.coverage.run] | |
| source = ["app"] | |
| omit = [ | |
| "app/services/scheduler.py", # background jobs, tested via integration | |
| "app/middleware/request_logging.py", # logging plumbing | |
| "*/migrations/*", | |
| "alembic/*", | |
| ] | |
| branch = true | |
| [tool.coverage.report] | |
| precision = 1 | |
| show_missing = true | |
| skip_covered = false | |
| # Target: 35% global coverage. This is deliberately modest — the heavy | |
| # service layers (LLM, RAG, inference, reports, PDF, email) are mocked at | |
| # the route level and exercised end-to-end via Playwright. Chasing a | |
| # higher gate here would mean writing mock-validation theater that | |
| # doesn't catch real bugs. | |
| fail_under = 35 | |
| exclude_lines = [ | |
| "pragma: no cover", | |
| "raise NotImplementedError", | |
| "if __name__ == .__main__.:", | |
| "if TYPE_CHECKING:", | |
| ] | |