@@ -28,6 +28,22 @@ Before pushing a raised dependency floor, run the `floors` steps from
2828[ ` _checks.yml ` ] ( .github/workflows/_checks.yml ) locally. If resolution fails, raise the direct floor
2929it names.
3030
31+ ## Versioning
32+
33+ - ** A change is breaking when a user's working code or deployed behaviour changes without them
34+ editing anything:** a new default, a removed or renamed public name or config field, a changed
35+ HTTP surface (path, status code, response body), or a raised dependency floor that the previous
36+ floor ran correctly with. Correcting a floor the code never worked with is a fix.
37+ - ** A breaking change ships only in a major release.** One exception: dropping a Python version past
38+ its end of life ships in a minor, as 1.11.0 did for 3.10. Installers skip a release whose
39+ ` requires-python ` excludes the running interpreter, so no deployed service breaks.
40+ - ** A rename keeps the old name working, with a ` DeprecationWarning ` , for at least one minor, and
41+ the next major deletes it.** The warning names that major. A module-level name goes through
42+ ` deprecated_module_getattr ` plus a ` typing.TYPE_CHECKING ` alias so type checkers still see it; a
43+ config field goes through ` BaseConfig._renamed_fields ` .
44+ - ** Every breaking change gets a line in a "Breaking changes" section of the release notes** , as
45+ [ 1.12.0] ( https://github.com/modern-python/lite-bootstrap/releases/tag/1.12.0 ) has.
46+
3147## Agent skills
3248
3349### Issue tracker
@@ -44,13 +60,10 @@ Single-context: `CONTEXT.md` and `docs/adr/` at the repo root. See `docs/agents/
4460
4561## Code style
4662
47- Four rules that are not visible in the code that follows them:
63+ Three rules that are not visible in the code that follows them:
4864
4965- ** No ` # noqa: PLR2004 ` .** Extract the magic value to a named local instead:
5066 ` expected_max_age = 600; assert config.cors_max_age == expected_max_age ` .
51- - ** A public rename ships a silent alias.** ` OldName = NewName ` at the end of the module, re-exported
52- from ` __init__.py ` if the old name was. A class assignment, not a subclass, so ` isinstance ` still
53- holds; ` OpentelemetryConfig ` is the worked example.
5467- ** A warning reached from config construction or an instrument's ` bootstrap() ` goes through
5568 ` warn_at_caller ` .** Neither depth is constant: a ` __post_init__ ` cascade runs as deep as that
5669 config's MRO, and ` bootstrap() ` sits a frame deeper whenever it calls ` super().bootstrap() ` . So
0 commit comments