# Contributor handoff — pallets/flask

> Canonical page: https://codevetter.com/unpack/flask/agent-handoff

# Contributor handoff — pallets/flask

Scanned commit d73fa1cdcbd8b1465c151db8924ba58b1dd14e35 (2026-09-08). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Read the sans-IO README first — it defines the hardest rule in this repo: nothing in `src/flask/sansio/` may do IO or touch the Flask globals, so context-dependent code belongs in `app.py`/`blueprints.py`. This is the 3.2 development line, so the second thing to internalise is that `RequestContext` no longer exists as a distinct class and that dispatch-related `Flask` methods take `ctx: AppContext` as their first parameter. Every user-visible change needs a `CHANGES.rst` entry with a `:pr:`/`:issue:` reference and a `.. versionadded:: 3.2` / `.. versionchanged:: 3.2` directive in the docstring — this is followed consistently throughout the codebase. Verify with `tox run -e py3.13` (or plain `pytest`), `tox run -e typing`, and `tox run -e style`; `filterwarnings = error` means a new warning without a matching test will break the suite.
- Read first, in order: `src/flask/sansio/README.md` (the IO boundary rule), `src/flask/ctx.py` (the merged `AppContext`), `src/flask/app.py` `wsgi_app`/`full_dispatch_request` (the dispatch spine), and `docs/lifecycle.rst` (the maintainers' own narrative of setup → serving → request). — [src/flask/sansio/README.md#L1-L6](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/README.md#L1-L6) [src/flask/ctx.py#L260-L298](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/ctx.py#L260-L298) [src/flask/app.py#L1569-L1626](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L1569-L1626) [docs/lifecycle.rst#L1-L60](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/docs/lifecycle.rst#L1-L60)
- Safe edit boundary: code in `src/flask/sansio/` must not import `flask.globals` or perform IO; if a change needs `current_app`, `request` or the filesystem, it belongs in the IO subclass in `src/flask/app.py` or `src/flask/blueprints.py`. — [src/flask/sansio/README.md#L1-L6](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/README.md#L1-L6) [src/flask/sansio/app.py#L1-L58](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/app.py#L1-L58) [src/flask/app.py#L32-L55](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L32-L55)
- Trap: if you add or change a `Flask` dispatch method, it must take `ctx: AppContext` as the first parameter after `self`, or `__init_subclass__`'s signature sniffing will treat subclass overrides as legacy and silently rewrap base-class methods. — [src/flask/app.py#L255-L310](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L255-L310) [CHANGES.rst#L11-L16](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/CHANGES.rst#L11-L16)
- Trap: `filterwarnings = ["error"]` turns every warning into a test failure — any new `DeprecationWarning` must be paired with a test that expects it. — [pyproject.toml#L90-L94](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L90-L94)
- Convention: every public change gets a `CHANGES.rst` bullet under the unreleased version with a `:pr:` or `:issue:` role, as the 3.2.0 section demonstrates for all 13 current entries. — [CHANGES.rst#L1-L33](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/CHANGES.rst#L1-L33)
- Convention: docstrings carry Sphinx `.. versionadded::` / `.. versionchanged::` directives naming the exact release — e.g. `select_jinja_autoescape` documents the 3.2 case-insensitivity change and `do_teardown_request` documents the 3.2 all-callbacks change. — [src/flask/sansio/app.py#L533-L548](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/app.py#L533-L548) [src/flask/app.py#L1423-L1455](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L1423-L1455)
- Tests to run: `pytest` (or `tox run` for a specific Python), `tox run -e typing` for mypy+pyright, and `tox run -e style` for the full pre-commit set; docs changes need `tox run -e docs`, which builds with `-W` so any Sphinx warning fails. — [pyproject.toml#L158-L232](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L158-L232) [.github/workflows/tests.yaml#L41-L66](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/.github/workflows/tests.yaml#L41-L66)
- Style is enforced by ruff with `select = ["B", "E", "F", "I", "UP", "W"]` and isort configured `force-single-line = true`, `order-by-type = false` — every import is on its own line throughout `src/`, matching that setting. — [pyproject.toml#L133-L149](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L133-L149) [src/flask/app.py#L1-L55](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L1-L55)
- Typing is strict and non-optional: `[tool.mypy] strict = true` over `src` and `tests/type_check`, plus pyright in basic mode; the package ships `src/flask/py.typed`, so any missing annotation is a public-API regression. — [pyproject.toml#L114-L131](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L114-L131) [src/flask/py.typed](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/py.typed)
- Shared return/callback types live in `src/flask/typing.py` (`ResponseReturnValue`, `ResponseValue`, `HeadersValue`, `AppOrBlueprintKey`); extend these rather than inlining unions, and note `ResponseValue` deliberately includes `AsyncIterable` for Quart's benefit. — [src/flask/typing.py#L11-L48](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/typing.py#L11-L48)
- Trap: `Blueprint.get_send_file_max_age` and `Blueprint.send_static_file` duplicate the `Flask` versions by design — a fix in one must be mirrored in the other. — [src/flask/blueprints.py#L55-L102](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/blueprints.py#L55-L102) [src/flask/app.py#L366-L414](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L366-L414)
- Trap: registration methods are frozen after the first request by `@setupmethod`/`_check_setup_finished`, so any new registration API must be decorated with `@setupmethod` to stay consistent. — [src/flask/sansio/scaffold.py#L42-L50](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/scaffold.py#L42-L50) [src/flask/sansio/app.py#L569-L604](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/sansio/app.py#L569-L604)
- Trap: `conftest.py`'s autouse `leak_detector` fails any test that leaves a context pushed — when adding context manipulation, make sure pushes and pops balance even on the error path. — [tests/conftest.py#L67-L79](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/tests/conftest.py#L67-L79) [src/flask/ctx.py#L446-L504](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/ctx.py#L446-L504)
- Dependency changes require regenerating `uv.lock` — the `uv-lock` pre-commit hook and the `update-requirements` tox env (`uv lock -U`) both enforce it, and the lock file is bundled into the sdist. — [.pre-commit-config.yaml#L6-L10](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/.pre-commit-config.yaml#L6-L10) [pyproject.toml#L226-L232](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L226-L232) [pyproject.toml#L80-L88](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L80-L88)
- Don't add new runtime dependencies casually: the six pinned runtime deps are all Pallets-maintained, and optional features (async, dotenv) are gated behind extras with graceful `ImportError` handling at the call site. (inferred) — [pyproject.toml#L23-L34](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/pyproject.toml#L23-L34) [src/flask/app.py#L1088-L1103](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/app.py#L1088-L1103) [src/flask/cli.py#L732-L744](https://github.com/pallets/flask/blob/d73fa1cdcbd8b1465c151db8924ba58b1dd14e35/src/flask/cli.py#L732-L744)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
