# Fix backend deprecation warnings ## Context `uv run pytest` on `backend/` emits 26 `DeprecationWarning`s. They are noise in CI output and two of the four sources are real forward-compat debt in our own code — the Starlette 422 constant is already renamed upstream, and Alembic's `version_path_separator` is superseded. Goal: our code emits zero deprecation warnings. Confirmed inventory (Python 3.14.0, fastapi 0.136.3, starlette 1.2.1, alembic 1.18.4, slowapi 0.1.9): | Source | Count | Ours? | |---|---|---| | `HTTP_422_UNPROCESSABLE_ENTITY` → use `HTTP_422_UNPROCESSABLE_CONTENT` | 8 | yes — 20 call sites | | `alembic/config.py:612` — `No path_separator found in configuration` | 12 | yes — `backend/alembic.ini` | | `slowapi/extension.py:717` — `asyncio.iscoroutinefunction` | 6 | no — upstream, out of scope | Decision made: fix our code only. No `filterwarnings` config is added; the slowapi warning stays visible as an upstream reminder. **Baseline:** 4 tests already fail on `main` (`test_migration_004_backfill.py::test_flexible_yearly_wish_keeps_the_same_bounding_range_every_year`, `test_leave_wish_repository.py::…test_flexible_series_keeps_one_bounding_range_per_year_unshifted`, two in `test_allocation_service.py`). These come from the uncommitted in-flight work in `app/entities/leave_wish.py` / `app/services/allocation_service.py` and are **unrelated** to this change. Expected result after the change: still exactly those 4, no more. ## Change 1 — rename the 422 constant (20 sites, 15 files) Mechanical rename, same numeric value (422), so no wire-format or frontend impact: ``` status.HTTP_422_UNPROCESSABLE_ENTITY → status.HTTP_422_UNPROCESSABLE_CONTENT ``` All sites are in `backend/app/routers/`. Representative files: `workspace.py` (3 sites, lines 51/94/223 — inside conditional expressions, not plain raises), `settings.py` (3), `fetch_data.py` (2), `leave_wishes.py` (2), `plan.py` (2), `preschool_planning_days.py` (2), plus one each in `auth.py`, `calendar.py`, `day_overrides.py`, `planned_day_exclusions.py`, `planned_days.py`, `vacation_days.py`. Notes: - `status` is already imported from `fastapi` in every one of these files — no import changes. - `status.HTTP_422_UNPROCESSABLE_CONTENT` is verified present in the installed starlette (evaluates to `422`). - No test file references the constant by name (`git grep UNPROCESSABLE -- tests` is empty), so tests need no update. - The warnings attributed to `fastapi/routing.py:328` are our handler frames raising through the dependency call — they disappear with this rename too. ## Change 2 — Alembic `path_separator` `backend/alembic.ini` currently has: ```ini prepend_sys_path = . version_path_separator = os ``` Replace `version_path_separator = os` with `path_separator = os`. In Alembic ≥1.16 `path_separator` governs both `prepend_sys_path` and `version_locations`, and its absence is what triggers the legacy-splitting warning. Leave `prepend_sys_path = .` and the annotated `sqlalchemy.url` fallback untouched. ## Out of scope - slowapi's `asyncio.iscoroutinefunction` warning — upstream, no released fix. - `typing.Dict` in `app/utils/holidays.py` and `datetime.timezone.utc` in `app/services/auth_service.py` — older spellings, but not deprecated and not warning sources. - The 4 pre-existing test failures. ## Verification Delegate to a **Haiku** subagent (per the cost rule); require raw verbatim output, from `backend/`: ```bash uv run ruff check . uv run ruff format --check . uv run pytest uv run alembic upgrade head # exercises the alembic.ini change directly ``` Acceptance criteria: 1. The warnings summary contains **only** the 6 `slowapi/extension.py:717` lines — no `UNPROCESSABLE_ENTITY`, no `path_separator`, count down from 26 to 6. 2. Failure list is exactly the 4 baseline failures above; pass count unchanged at 860. 3. Coverage still ≥ the `--cov-fail-under=80` gate (no gate changes). 4. `alembic upgrade head` completes without the `path_separator` warning. Then `graphify update .`.