Skip to content

chore(deps): bump the dev-dependencies group across 1 directory with 40 updates - #3

Merged
ancongui merged 1 commit into
mainfrom
dependabot/pip/dev-dependencies-70f11fe1d0
May 7, 2026
Merged

chore(deps): bump the dev-dependencies group across 1 directory with 40 updates#3
ancongui merged 1 commit into
mainfrom
dependabot/pip/dev-dependencies-70f11fe1d0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Apr 15, 2026

Copy link
Copy Markdown
Contributor

Updates the requirements on pydantic, pyyaml, starlette, uvicorn, python-multipart, sqlalchemy, alembic, aiosqlite, motor, beanie, asyncpg, aiokafka, aio-pika, fastapi, granian, hypercorn, redis, httpx, prometheus-client, opentelemetry-api, opentelemetry-sdk, opentelemetry-instrumentation-starlette, structlog, croniter, pyjwt, bcrypt, cryptography, click, rich, jinja2, questionary, uvloop, pytest, pytest-asyncio, pytest-cov, coverage, mypy, ruff, mongomock-motor and jsonpath-ng to permit the latest version.
Updates pydantic to 2.13.3

Release notes

Sourced from pydantic's releases.

v2.13.3 2026-04-20

v2.13.3 (2026-04-20)

What's Changed

Fixes

Full Changelog: pydantic/pydantic@v2.13.2...v2.13.3

Changelog

Sourced from pydantic's changelog.

v2.13.3 (2026-04-20)

GitHub release

What's Changed

Fixes

v2.13.2 (2026-04-17)

GitHub release

What's Changed

Fixes

  • Fix ValidationInfo.field_name missing with model_validate_json() by @​Viicos in #13084

v2.13.1 (2026-04-15)

GitHub release

What's Changed

Fixes

v2.13.0 (2026-04-13)

GitHub release

The highlights of the v2.13 release are available in the blog post. Several minor changes (considered non-breaking changes according to our versioning policy) are also included in this release. Make sure to look into them before upgrading.

This release contains the updated pydantic.v1 namespace, matching version 1.10.26 which includes support for Python 3.14.

What's Changed

See the beta releases for all changes sinces 2.12.

New Features

  • Allow default factories of private attributes to take validated model data by @​Viicos in #13013

Changes

... (truncated)

Commits
  • 9e9a111 Fix backported test
  • 1ec8c6a Prepare release v2.13.3
  • fb4f204 Handle AttributeError subclasses with from_attributes
  • ca3ddd1 Prepare release v2.13.2
  • 000e823 Fix ValidationInfo.field_name missing with model_validate_json()
  • d45d8be Prepare release 2.13.1
  • 54aca60 Fix ValidationInfo.data missing with model_validate_json()
  • 46bf4fa Fix Pydantic release workflow (#13067)
  • 1b359ed Prepare release v2.13.0 (#13065)
  • b1bf194 Fix model equality when using runtime extra configuration (#13062)
  • Additional commits viewable in compare view

Updates pyyaml to 6.0.3

Release notes

Sourced from pyyaml's releases.

6.0.3

What's Changed

  • Support for Python 3.14 and free-threading (experimental).

Full Changelog: yaml/pyyaml@6.0.2...6.0.3

Changelog

Sourced from pyyaml's changelog.

6.0.3 (2025-09-25)

  • yaml/pyyaml#864 -- Support for Python 3.14 and free-threading (experimental)

6.0.2 (2024-08-06)

6.0.1 (2023-07-18)

6.0 (2021-10-13)

5.4.1 (2021-01-20)

  • yaml/pyyaml#480 -- Fix stub compat with older pyyaml versions that may unwittingly load it

5.4 (2021-01-19)

5.3.1 (2020-03-18)

  • yaml/pyyaml#386 -- Prevents arbitrary code execution during python/object/new constructor

5.3 (2020-01-06)

... (truncated)

Commits

Updates starlette to 1.0.0

Release notes

Sourced from starlette's releases.

Version 1.0.0

Starlette 1.0 is here! 🎉

After nearly eight years since its creation, Starlette has reached its first stable release.

A special thank you to @​lovelydinosaur, the creator of Starlette, Uvicorn, HTTPX and MkDocs, whose work helped to lay the foundation for the modern async Python ecosystem. 🙏

Thank you to @​adriangb, @​graingert, @​agronholm, @​florimondmanca, @​aminalaee, @​tiangolo, @​alex-oleshkevich, @​abersheeran, and @​uSpike for helping make Starlette what it is today. And to all my sponsors - especially @​tiangolo, @​huggingface, and @​elevenlabs - thank you for your support!

Thank you to all 290+ contributors who have shaped Starlette over the years! ❤️

Read more on the blog post.

Check out the full release notes at https://www.starlette.io/release-notes/#100-march-22-2026


Full Changelog: Kludex/starlette@1.0.0rc1...1.0.0

Changelog

Sourced from starlette's changelog.

1.0.0 (March 22, 2026)

Starlette 1.0 is here!

After nearly eight years since its creation, Starlette has reached its first stable release. Thank you to everyone who tested the release candidate and reported issues.

You can read more on the blog post.

Added

  • Track session access and modification in SessionMiddleware #3166.

Fixed

  • Handle websocket denial responses in StreamingResponse and FileResponse #3189.
  • Use bytearray for field accumulation in FormParser #3179.
  • Move parser.finalize() inside try/except in MultiPartParser.parse() #3153.

1.0.0rc1 (February 23, 2026)

We're ready! I'm thrilled to announce the first release candidate for Starlette 1.0.

Starlette was created in June 2018 by Tom Christie, and has been on ZeroVer for years. Today, it's downloaded almost 10 million times a day, serves as the foundation for FastAPI, and has inspired many other frameworks. In the age of AI, Starlette continues to play an important role as a dependency of the Python MCP SDK.

This release focuses on removing deprecated features that were marked for removal in 1.0.0, along with some last minute bug fixes. It's a release candidate, so we can gather feedback from the community before the final 1.0.0 release soon.

A huge thank you to all the contributors who have helped make Starlette what it is today. In particular, I'd like to recognize:

  • Kim Christie - The original creator of Starlette, Uvicorn, and MkDocs, and the current maintainer of HTTPX. Kim's work helped lay the foundation for the modern async Python ecosystem.
  • Adrian Garcia Badaracco - One of the smartest people I know, whom I have the pleasure of working with at Pydantic.
  • Thomas Grainger - My async teacher, always ready to help with questions.
  • Alex Grönholm - Another async mentor, always prompt to help with questions.
  • Florimond Manca - Always present in the early days of both Starlette and Uvicorn, and helped a lot in the ecosystem.
  • Amin Alaee - Contributed a lot with file-related PRs.
  • Sebastián Ramírez - Maintains FastAPI upstream, and always in contact to help with upstream issues.
  • Alex Oleshkevich - Helped a lot on templates and many discussions.
  • abersheeran - My go-to person when I need help on many subjects.

I'd also like to thank my sponsors for their support. A special thanks to @​tiangolo, @​huggingface, and @​elevenlabs for their generous sponsorship, and to all my other sponsors:

... (truncated)

Commits
  • 0e88e92 Version 1.0.0 (#3178)
  • 9ee9519 Handle websocket denial responses in streaming and file responses (#3189)
  • a0bcc26 chore(deps-dev): bump black from 26.1.0 to 26.3.1 (#3183)
  • 79b3f26 chore(deps-dev): bump the python-packages group with 7 updates (#3168)
  • 789b926 Use bytearray for field accumulation in FormParser (#3179)
  • a1fd9d8 docs: fix typo in routing.md (#3176)
  • c14d0f7 Document session cookie security flags (#3169)
  • c2e2878 Move parser.finalize() inside try/except in MultiPartParser.parse() (#3153)
  • 89630a8 chore(deps): bump the github-actions group with 3 updates (#3167)
  • 4647e53 Track session access and modification in SessionMiddleware (#3166)
  • Additional commits viewable in compare view

Updates uvicorn to 0.46.0

Release notes

Sourced from uvicorn's releases.

Version 0.46.0

What's Changed

Full Changelog: Kludex/uvicorn@0.45.0...0.46.0

Changelog

Sourced from uvicorn's changelog.

0.46.0 (April 23, 2026)

Added

  • Support ws_max_size in wsproto implementation (#2915)
  • Support ws_ping_interval and ws_ping_timeout in wsproto implementation (#2916)

Changed

  • Use bytearray for incoming WebSocket message buffer in websockets-sansio (#2917)

0.45.0 (April 21, 2026)

Added

  • Add --reset-contextvars flag to isolate ASGI request context (#2912)
  • Accept os.PathLike for log_config (#2905)
  • Accept log_level strings case-insensitively (#2907)

Changed

  • Revert "Emit http.disconnect on server shutdown for streaming responses" (#2913)
  • Revert "Explicitly start ASGI run with empty context" (#2911)

Fixed

  • Preserve forwarded client ports in proxy headers middleware (#2903)
  • Raise helpful ImportError when PyYAML is missing for YAML log config (#2906)

0.44.0 (April 6, 2026)

Added

  • Implement websocket keepalive pings for websockets-sansio (#2888)

0.43.0 (April 3, 2026)

You can quit Uvicorn now. We heard you, @​pamelafox - all 47 of your Ctrl+C's (thanks for flagging it, and thanks to @​tiangolo for the fix 🙏). See the tweet.

Changed

  • Emit http.disconnect ASGI receive() event on server shutting down for streaming responses (#2829)
  • Use native context parameter for create_task on Python 3.11+ (#2859)
  • Drop cast in ASGI types (#2875)

0.42.0 (March 16, 2026)

Changed

  • Use bytearray for request body accumulation to avoid O(n^2) allocation on fragmented bodies (#2845)

... (truncated)

Commits
  • b224045 Version 0.46.0 (#2918)
  • 7375b5b Use bytearray for incoming WebSocket message buffer in websockets-sansio (#...
  • d438fb1 Support ws_ping_interval and ws_ping_timeout in wsproto implementation ...
  • 3e6b964 Support ws_max_size in wsproto implementation (#2915)
  • 2c423bd Version 0.45.0 (#2914)
  • 7f027f8 Revert "Emit http.disconnect on server shutdown for streaming responses" (#...
  • 73a80c3 Add --reset-contextvars flag to isolate ASGI request context (#2912)
  • 45c0b56 Revert empty context for ASGI runs (#2911)
  • 850d926 Raise helpful ImportError when PyYAML is missing for YAML log config (#2906)
  • fdcacb4 Accept log_level strings case-insensitively (#2907)
  • Additional commits viewable in compare view

Updates python-multipart to 0.0.27

Release notes

Sourced from python-multipart's releases.

0.0.27

What's Changed

Full Changelog: Kludex/python-multipart@0.0.26...0.0.27

Changelog

Sourced from python-multipart's changelog.

0.0.27 (2026-04-27)

  • Add multipart header limits #267.
  • Pass parse offsets via constructors #268.

0.0.26 (2026-04-10)

  • Skip preamble before the first multipart boundary more efficiently #262.
  • Silently discard epilogue data after the closing multipart boundary #259.

0.0.25 (2026-04-10)

  • Add MIME content type info to File #143.
  • Handle CTE values case-insensitively #258.
  • Remove custom FormParser classes #257.
  • Add UPLOAD_DELETE_TMP to FormParser config #254.
  • Emit field_end for trailing bare field names on finalize #230.
  • Handle multipart headers case-insensitively #252.
  • Apply Apache-2.0 properly #247.

0.0.24 (2026-04-05)

  • Validate chunk_size in parse_form() #244.

0.0.23 (2026-04-05)

  • Remove unused trust_x_headers parameter and X-File-Name fallback #196.
  • Return processed length from QuerystringParser._internal_write #229.
  • Cleanup metadata dunders from __init__.py #227.

0.0.22 (2026-01-25)

  • Drop directory path from filename in File 9433f4b.

0.0.21 (2025-12-17)

  • Add support for Python 3.14 and drop EOL 3.8 and 3.9 #216.

0.0.20 (2024-12-16)

  • Handle messages containing only end boundary #142.

0.0.19 (2024-11-30)

  • Don't warn when CRLF is found after last boundary on MultipartParser #193.

0.0.18 (2024-11-28)

  • Hard break if found data after last boundary on MultipartParser #189.

... (truncated)

Commits

Updates sqlalchemy to 2.0.49

Release notes

Sourced from sqlalchemy's releases.

2.0.49

Released: April 3, 2026

orm

  • [orm] [bug] Fixed issue where _orm.Session.get() would bypass the identity map and emit unnecessary SQL when with_for_update=False was passed, rather than treating it equivalently to the default of None. Pull request courtesy of Joshua Swanson.

    References: #13176

  • [orm] [bug] Fixed issue where chained _orm.joinedload() options would not be applied correctly when the final relationship in the chain is declared on a base mapper and accessed through a subclass mapper in a _orm.with_polymorphic() query. The path registry now correctly computes the natural path when a property declared on a base class is accessed through a path containing a subclass mapper, ensuring the loader option can be located during query compilation.

    References: #13193

  • [orm] [bug] [inheritance] Fixed issue where using _orm.Load.options() to apply a chained loader option such as _orm.joinedload() or _orm.selectinload() with _orm.PropComparator.of_type() for a polymorphic relationship would not generate the necessary clauses for the polymorphic subclasses. The polymorphic loading strategy is now correctly propagated when using a call such as joinedload(A.b).options(joinedload(B.c.of_type(poly))) to match the behavior of direct chaining e.g. joinedload(A.b).joinedload(B.c.of_type(poly)).

    References: #13202

  • [orm] [bug] [inheritance] Fixed issue where using chained loader options such as _orm.selectinload() after _orm.joinedload() with _orm.PropComparator.of_type() for a polymorphic relationship would not properly apply the chained loader option. The loader option is now correctly applied when using a call such as joinedload(A.b.of_type(poly)).selectinload(poly.SubClass.c) to eagerly load related objects.

    References: #13209

typing

  • [typing] [bug] Fixed a typing issue where the typed members of :data:.func would return the appropriate class of the same name, however this creates an issue for

... (truncated)

Commits

Updates alembic to 1.18.4

Release notes

Sourced from alembic's releases.

1.18.4

Released: February 10, 2026

bug

  • [bug] [operations] Reverted the behavior of Operations.add_column() that would automatically render the "PRIMARY KEY" keyword inline when a Column with primary_key=True is added. The automatic behavior, added in version 1.18.2, is now opt-in via the new Operations.add_column.inline_primary_key parameter. This change restores the ability to render a PostgreSQL SERIAL column, which is required to be primary_key=True, while not impacting the ability to render a separate primary key constraint. This also provides consistency with the Operations.add_column.inline_references parameter and gives users explicit control over SQL generation.

    To render PRIMARY KEY inline, use the Operations.add_column.inline_primary_key parameter set to True:

    op.add_column( "my_table", Column("id", Integer, primary_key=True), inline_primary_key=True )References: #1232

Commits

Updates aiosqlite to 0.22.1

Changelog

Sourced from aiosqlite's changelog.

v0.22.1

Bug fix release

NOTE: Starting with v0.22.0, the aiosqlite.Connection object no longer inherits from threading.Thread. If not using aiosqlite as a context manager, clients must await connection.close() or call connection.stop() to ensure the helper thread is completed and terminated correctly. A ResourceWarning will be emitted for any connection that is garbage collected without being closed or stopped.

  • Added synchronous stop() method to aiosqlite.Connection to enable safe cleanup and termination of the background thread without dependence on having an active event loop (#370)
$ git shortlog -s v0.22.0...v0.22.1
     2	Amethyst Reese

v0.22.0

Feature release

  • Support set_authorizer query access controls (#349)
  • Wait for transaction queue to complete when closing connection (#305)
  • Emit warning when connection goes out of scope without being closed (#355)
  • Remove dependency on typing_extensions (#365)
$ git shortlog -s v0.21.0...v0.22.0
     1	Alec Berryman
     1	Amethyst Reese
     1	David Andreoletti
     1	Markus Heidelberg
     1	beerpsi
    19	dependabot[bot]

v0.21.0

Maintenance release

  • Fix: close connection correctly when BaseException raised in connection (#317)
  • Metadata improvements

... (truncated)

Commits

Updates motor to 3.7.1

Release notes

Sourced from motor's releases.

Motor 3.7.1

Community notes: https://www.mongodb.com/community/forums/t/motor-3-7-1-released/321388.

Changelog

Sourced from motor's changelog.

Motor 3.7.1

The 3.7.1 release contains only documentation changes.

.. warning:: As of May 14th, 2025, Motor is deprecated in favor of the GA release of the PyMongo Async API. No new features will be added to Motor, and only bug fixes will be provided until it reaches end of life on May 14th, 2026. After that, only critical bug fixes will be made until final support ends on May 14th, 2027. We strongly recommend migrating to the PyMongo Async API while Motor is still supported. For help transitioning, see the Migrate to PyMongo Async guide <https://www.mongodb.com/docs/languages/python/pymongo-driver/current/reference/migration/>_.

Motor 3.7.0

  • Add support for PyMongo 4.10.
  • Drop support for Python 3.8.
  • Drop support for MongoDB 3.6.

Motor 3.6.1

  • Add return type to to_list method in stub file.
  • Fix ability to install pymongo from source while testing.

Motor 3.6.0

  • Add support for MongoDB 8.0 and PyMongo 4.9.
  • The length parameter in :meth:MotorCursor.to_list is now optional.

.. note::

This is the last planned minor version of Motor. We are sunsetting Motor in favor of native asyncio support in PyMongo 4.9+. We will continue to provide security releases and bug fixes for Motor, but it will not gain new features.

Motor 3.5.1

  • Fix runtime behavior of Motor generic class typing, e.g. client: AsyncIOMotorClient[Dict[str, Any]].

Motor 3.5.0

  • Drop support for Python 3.7.
  • Switch to using Hatchling as a build backend and remove setup.py.
  • Add Secure Software Development Life Cycle automation to release process. GitHub Releases for pymongocrypt now include a Software Bill of Materials, and signature files corresponding to the distribution files released on PyPI.

Motor 3.4.0

... (truncated)

Commits
  • 1b2e255 Bump version to 3.7.1 for release (#337)
  • c734a3a Update changelog for 3.7.1 (#336)
  • e20ae5f PYTHON-5377 - Further update assets to align with GA release of Async PyMongo...
  • f6a70b8 PYTHON-5377 - Update assets to align with GA release of Async PyMongo (#334)
  • 83f735a PYTHON-5353 Use pinned sources for GitHub Actions (#333)
  • c291853 PYTHON-5348 Fix CodeQL Scanning for GitHub Actions (#332)
  • d5d0995 MOTOR-1453 & MOTOR-1454 Update expected attributes tests and links (#331)
  • eae1d25 PYTHON-5188 Make version setting a part of the release process (#330)
  • a879ce5 PYTHON-5131 Migrate off of Ubuntu 20.04 GitHub Actions Runners (#329)
  • 6751d66 PYTHON-5136 Add check-json to pre-commit checks (#328)
  • Additional commits viewable in compare view

Updates beanie to 2.1.0

Release notes

Sourced from beanie's releases.

2.1.0

What's Changed

New Contributors

Full Changelog: BeanieODM/beanie@2.0.1...2.1.0

Changelog

Sourced from beanie's changelog.

2.1.0 - 2026-03-20

Drop EOL Python 3.9, MongoDB 4.4/5.0/6.0, Pydantic v1

Speed up init by avoiding duplicate db commands

Improve class filter and is/is not for enum comparison

Fix OperationFailure when saving with keep_nulls=False and no None values

Fix FindQuery.count() ignoring pymongo_kwargs

Add Beanie version to handshake metadata

Docs: clarify state management description

Add docstring to DocumentWithSoftDelete

Fix: support frozen fields on save() and replace()

Fix: handle RootModel with custom iter in save()

Fix: handle BackLink types in fetch_link and fetch_all_links

Fix: persist before_event changes to DB on save/update/replace

Fix: resolve Pydantic field aliases in nested ...

Description has been truncated

@dependabot dependabot Bot added dependencies Pull requests that update a dependency file python Pull requests that update python code labels Apr 15, 2026
…40 updates

Updates the requirements on [pydantic](https://github.com/pydantic/pydantic), [pyyaml](https://github.com/yaml/pyyaml), [starlette](https://github.com/Kludex/starlette), [uvicorn](https://github.com/Kludex/uvicorn), [python-multipart](https://github.com/Kludex/python-multipart), [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy), [alembic](https://github.com/sqlalchemy/alembic), [aiosqlite](https://github.com/omnilib/aiosqlite), [motor](https://github.com/mongodb/motor), [beanie](https://github.com/BeanieODM/beanie), [asyncpg](https://github.com/MagicStack/asyncpg), [aiokafka](https://github.com/aio-libs/aiokafka), [aio-pika](https://github.com/mosquito/aio-pika), [fastapi](https://github.com/fastapi/fastapi), [granian](https://github.com/emmett-framework/granian), [hypercorn](https://github.com/pgjones/hypercorn), [redis](https://github.com/redis/redis-py), [httpx](https://github.com/encode/httpx), [prometheus-client](https://github.com/prometheus/client_python), [opentelemetry-api](https://github.com/open-telemetry/opentelemetry-python), [opentelemetry-sdk](https://github.com/open-telemetry/opentelemetry-python), [opentelemetry-instrumentation-starlette](https://github.com/open-telemetry/opentelemetry-python-contrib), [structlog](https://github.com/hynek/structlog), [croniter](https://github.com/pallets-eco/croniter), [pyjwt](https://github.com/jpadilla/pyjwt), [bcrypt](https://github.com/pyca/bcrypt), [cryptography](https://github.com/pyca/cryptography), [click](https://github.com/pallets/click), [rich](https://github.com/Textualize/rich), [jinja2](https://github.com/pallets/jinja), [questionary](https://github.com/tmbo/questionary), [uvloop](https://github.com/MagicStack/uvloop), [pytest](https://github.com/pytest-dev/pytest), [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio), [pytest-cov](https://github.com/pytest-dev/pytest-cov), [coverage](https://github.com/coveragepy/coveragepy), [mypy](https://github.com/python/mypy), [ruff](https://github.com/astral-sh/ruff), [mongomock-motor](https://github.com/michaelkryukov/mongomock_motor) and [jsonpath-ng](https://github.com/h2non/jsonpath-ng) to permit the latest version.

Updates `pydantic` to 2.13.3
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](pydantic/pydantic@v2.0...v2.13.3)

Updates `pyyaml` to 6.0.3
- [Release notes](https://github.com/yaml/pyyaml/releases)
- [Changelog](https://github.com/yaml/pyyaml/blob/6.0.3/CHANGES)
- [Commits](yaml/pyyaml@6.0...6.0.3)

Updates `starlette` to 1.0.0
- [Release notes](https://github.com/Kludex/starlette/releases)
- [Changelog](https://github.com/Kludex/starlette/blob/main/docs/release-notes.md)
- [Commits](Kludex/starlette@0.40.0...1.0.0)

Updates `uvicorn` to 0.46.0
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](Kludex/uvicorn@0.30.0...0.46.0)

Updates `python-multipart` to 0.0.27
- [Release notes](https://github.com/Kludex/python-multipart/releases)
- [Changelog](https://github.com/Kludex/python-multipart/blob/main/CHANGELOG.md)
- [Commits](Kludex/python-multipart@0.0.9...0.0.27)

Updates `sqlalchemy` to 2.0.49
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst)
- [Commits](https://github.com/sqlalchemy/sqlalchemy/commits)

Updates `alembic` to 1.18.4
- [Release notes](https://github.com/sqlalchemy/alembic/releases)
- [Changelog](https://github.com/sqlalchemy/alembic/blob/main/CHANGES)
- [Commits](https://github.com/sqlalchemy/alembic/commits)

Updates `aiosqlite` to 0.22.1
- [Changelog](https://github.com/omnilib/aiosqlite/blob/main/CHANGELOG.md)
- [Commits](omnilib/aiosqlite@v0.20.0...v0.22.1)

Updates `motor` to 3.7.1
- [Release notes](https://github.com/mongodb/motor/releases)
- [Changelog](https://github.com/mongodb/motor/blob/master/doc/changelog.rst)
- [Commits](mongodb/motor@3.3.0...3.7.1)

Updates `beanie` to 2.1.0
- [Release notes](https://github.com/BeanieODM/beanie/releases)
- [Changelog](https://github.com/BeanieODM/beanie/blob/main/docs/changelog.md)
- [Commits](BeanieODM/beanie@1.25.0...2.1.0)

Updates `asyncpg` to 0.31.0
- [Release notes](https://github.com/MagicStack/asyncpg/releases)
- [Commits](MagicStack/asyncpg@v0.29.0...v0.31.0)

Updates `aiokafka` to 0.14.0
- [Release notes](https://github.com/aio-libs/aiokafka/releases)
- [Changelog](https://github.com/aio-libs/aiokafka/blob/master/CHANGES.rst)
- [Commits](aio-libs/aiokafka@v0.10.0...v0.14.0)

Updates `aio-pika` to 9.6.2
- [Release notes](https://github.com/mosquito/aio-pika/releases)
- [Changelog](https://github.com/mosquito/aio-pika/blob/master/CHANGELOG.md)
- [Commits](mosquito/aio-pika@9.0.0...9.6.2)

Updates `fastapi` to 0.136.1
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](fastapi/fastapi@0.115.0...0.136.1)

Updates `granian` to 2.7.4
- [Release notes](https://github.com/emmett-framework/granian/releases)
- [Commits](emmett-framework/granian@v2.6.0...v2.7.4)

Updates `hypercorn` to 0.18.0
- [Changelog](https://github.com/pgjones/hypercorn/blob/main/CHANGELOG.rst)
- [Commits](pgjones/hypercorn@0.17.0...0.18.0)

Updates `redis` to 7.4.0
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](redis/redis-py@v5.0.0...v7.4.0)

Updates `httpx` to 0.28.1
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](encode/httpx@0.27.0...0.28.1)

Updates `prometheus-client` to 0.25.0
- [Release notes](https://github.com/prometheus/client_python/releases)
- [Commits](prometheus/client_python@v0.20.0...v0.25.0)

Updates `opentelemetry-api` to 1.41.1
- [Release notes](https://github.com/open-telemetry/opentelemetry-python/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-python/blob/v1.41.1/CHANGELOG.md)
- [Commits](open-telemetry/opentelemetry-python@v1.24.0...v1.41.1)

Updates `opentelemetry-sdk` to 1.41.1
- [Release notes](https://github.com/open-telemetry/opentelemetry-python/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-python/blob/v1.41.1/CHANGELOG.md)
- [Commits](open-telemetry/opentelemetry-python@v1.24.0...v1.41.1)

Updates `opentelemetry-instrumentation-starlette` to 0.62b1
- [Release notes](https://github.com/open-telemetry/opentelemetry-python-contrib/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-python-contrib/commits)

Updates `structlog` to 25.5.0
- [Release notes](https://github.com/hynek/structlog/releases)
- [Changelog](https://github.com/hynek/structlog/blob/main/CHANGELOG.md)
- [Commits](hynek/structlog@24.1.0...25.5.0)

Updates `croniter` to 6.2.2
- [Changelog](https://github.com/pallets-eco/croniter/blob/main/CHANGELOG.rst)
- [Commits](pallets-eco/croniter@2.0.0...6.2.2)

Updates `pyjwt` to 2.12.1
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](jpadilla/pyjwt@2.8.0...2.12.1)

Updates `bcrypt` to 5.0.0
- [Changelog](https://github.com/pyca/bcrypt/blob/main/CHANGELOG.rst)
- [Commits](pyca/bcrypt@4.0.0...5.0.0)

Updates `cryptography` to 48.0.0
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@42.0.0...48.0.0)

Updates `click` to 8.3.3
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.1.0...8.3.3)

Updates `rich` to 15.0.0
- [Release notes](https://github.com/Textualize/rich/releases)
- [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md)
- [Commits](Textualize/rich@v13.0.0...v15.0.0)

Updates `jinja2` to 3.1.6
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](pallets/jinja@3.1.0...3.1.6)

Updates `questionary` to 2.1.1
- [Commits](tmbo/questionary@2.0.0...2.1.1)

Updates `uvloop` to 0.22.1
- [Release notes](https://github.com/MagicStack/uvloop/releases)
- [Commits](MagicStack/uvloop@v0.21.0...v0.22.1)

Updates `pytest` to 9.0.3
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pytest@8.0.0...9.0.3)

Updates `pytest-asyncio` to 1.3.0
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](pytest-dev/pytest-asyncio@v0.23.0...v1.3.0)

Updates `pytest-cov` to 7.1.0
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](pytest-dev/pytest-cov@v5.0.0...v7.1.0)

Updates `coverage` to 7.13.5
- [Release notes](https://github.com/coveragepy/coveragepy/releases)
- [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst)
- [Commits](coveragepy/coveragepy@7.0.0...7.13.5)

Updates `mypy` to 1.20.2
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](python/mypy@v1.8.0...v1.20.2)

Updates `ruff` to 0.15.12
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](astral-sh/ruff@v0.3.0...0.15.12)

Updates `mongomock-motor` to 0.0.36
- [Release notes](https://github.com/michaelkryukov/mongomock_motor/releases)
- [Commits](michaelkryukov/mongomock_motor@v0.0.6...v0.0.36)

Updates `jsonpath-ng` to 1.8.0
- [Release notes](https://github.com/h2non/jsonpath-ng/releases)
- [Changelog](https://github.com/h2non/jsonpath-ng/blob/master/CHANGELOG.md)
- [Commits](h2non/jsonpath-ng@v1.6.0...v1.8.0)

---
updated-dependencies:
- dependency-name: aio-pika
  dependency-version: 9.6.2
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: aiokafka
  dependency-version: 0.13.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: aiosqlite
  dependency-version: 0.22.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: alembic
  dependency-version: 1.18.4
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: asyncpg
  dependency-version: 0.31.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: bcrypt
  dependency-version: 5.0.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: beanie
  dependency-version: 2.1.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: click
  dependency-version: 8.3.2
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: coverage
  dependency-version: 7.13.5
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: croniter
  dependency-version: 6.2.2
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: cryptography
  dependency-version: 46.0.7
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: fastapi
  dependency-version: 0.135.3
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: granian
  dependency-version: 2.7.3
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: hypercorn
  dependency-version: 0.18.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: jinja2
  dependency-version: 3.1.6
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: jsonpath-ng
  dependency-version: 1.8.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: mongomock-motor
  dependency-version: 0.0.36
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: motor
  dependency-version: 3.7.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: mypy
  dependency-version: 1.20.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: opentelemetry-api
  dependency-version: 1.41.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: opentelemetry-instrumentation-starlette
  dependency-version: 0.62b0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: opentelemetry-sdk
  dependency-version: 1.41.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: prometheus-client
  dependency-version: 0.25.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: pydantic
  dependency-version: 2.13.0
  dependency-type: direct:production
  dependency-group: dev-dependencies
- dependency-name: pyjwt
  dependency-version: 2.12.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: pytest
  dependency-version: 9.0.3
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: pytest-asyncio
  dependency-version: 1.3.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: pytest-cov
  dependency-version: 7.1.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: python-multipart
  dependency-version: 0.0.26
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: pyyaml
  dependency-version: 6.0.3
  dependency-type: direct:production
  dependency-group: dev-dependencies
- dependency-name: questionary
  dependency-version: 2.1.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: redis
  dependency-version: 7.4.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: rich
  dependency-version: 15.0.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: ruff
  dependency-version: 0.15.10
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: sqlalchemy
  dependency-version: 2.0.49
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: starlette
  dependency-version: 1.0.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: structlog
  dependency-version: 25.5.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: uvicorn
  dependency-version: 0.44.0
  dependency-type: direct:development
  dependency-group: dev-dependencies
- dependency-name: uvloop
  dependency-version: 0.22.1
  dependency-type: direct:development
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot changed the title chore(deps): bump the dev-dependencies group with 40 updates chore(deps): bump the dev-dependencies group across 1 directory with 40 updates May 6, 2026
@dependabot
dependabot Bot force-pushed the dependabot/pip/dev-dependencies-70f11fe1d0 branch from d0b65ab to 97e224b Compare May 6, 2026 04:47
@ancongui

ancongui commented May 7, 2026

Copy link
Copy Markdown
Contributor

@dependabot rebase

@ancongui
ancongui merged commit 6200d7c into main May 7, 2026
5 checks passed
@ancongui
ancongui deleted the dependabot/pip/dev-dependencies-70f11fe1d0 branch May 7, 2026 21:05
@dependabot @github

dependabot Bot commented on behalf of github May 7, 2026

Copy link
Copy Markdown
Contributor Author

Oh no! Something went wrong on our end. Please try again later.

If the problem persists, please contact GitHub support for assistance 🙇

ancongui pushed a commit that referenced this pull request Jun 4, 2026
…ivate (audit #2/#3/#4/#6)

Starter stacks set property keys their auto-configs never read, so the bundled
adapters/services silently never activated (the old keys had ZERO consumers).
Fixed to the keys the conditions actually gate on:

  #2 data/domain: pyfly.relational.enabled  -> pyfly.data.relational.enabled
                  pyfly.document.enabled     -> pyfly.data.document.enabled
  #3 core:        pyfly.eda.enabled          -> pyfly.eda.provider=auto
                  (EdaAutoConfiguration gates on pyfly.eda.provider; 'auto' resolves
                   to the best installed broker, falling back to the in-memory bus)
  #4 application: pyfly.security-jwt.enabled / pyfly.security-password.enabled
                  / pyfly.session-filter.enabled -> pyfly.security.enabled=true
                  (JWT auth WebFilter stays opt-in via pyfly.security.jwt.filter.enabled)
  #6 core/web:    pyfly.actuator.enabled / pyfly.actuator.metrics.enabled
                  -> pyfly.web.actuator.enabled

Scaffold (pyfly.yaml.j2): added pyfly.security.enabled to the security feature
block so generated security apps wire JWTService + the password encoder. Left the
'eda' feature's messaging: block as-is — pyfly.messaging.provider drives the SEPARATE
MessagingAutoConfiguration (MessageBrokerPort), a real distinct subsystem, and is
covered by an existing test; it is not the EDA EventPublisher path.

Updated the existing test_starters.py assertions (old keys) in lockstep.
Tests: tests/starters/test_wave_starter_keys.py (8, functionally proving each
auto-config's conditions now pass via ConditionEvaluator with deps installed) +
1 scaffold security test.

Deferred: #5 test-slice decorators (net-new), #10 testcontainers (net-new),
#11 inert pyfly.web/observability/metrics/tracing/resilience/aop.enabled keys
(deliberate convention: those auto-configs activate on @conditional_on_class, not
property flags).

Suite 3519 -> 3528 green; ruff + mypy clean.
ancongui added a commit that referenced this pull request Jun 5, 2026
* fix(di): DI-core keystones from full-parity audit (Wave 0)

Fixes audit findings that affect every bean lifecycle:

- #113 interface-typed @bean was registered under both its concrete and
  return type, so @post_construct / AOP weaving / every BeanPostProcessor
  ran TWICE on the same instance. Startup lifecycle, wiring, and pre_destroy
  passes now de-duplicate by instance identity and propagate the woven
  instance to all aliases.
- #114 synchronous @around advice was silently dropped; _build_sync_wrapper
  now builds a sync around chain mirroring the async one.
- #115 a synchronous @app_event_listener crashed startup (await on None);
  ApplicationEventBus.publish awaits only awaitable results.
- #116 TRANSIENT @bean factory methods were ignored on resolution (rebuilt
  via __init__); Registration now carries a factory closure that the
  container prefers.
- #117 conditional_on_property gains match_if_missing and Spring-correct
  empty-having_value semantics (present-and-not-"false").
- #119 app-event-type inference no longer mistakes the return annotation
  for the event type.

Full suite 3397 passed; ruff + mypy clean.

* fix(web): post-start dynamic wiring keystone (Wave 0, audit #40/#163)

create_app() builds the WebFilter chain and collects routes BEFORE
ApplicationContext.start(), so beans only instantiated during startup were
silently dropped: security/session/CSRF WebFilters never ran, and
@bean-produced controllers (orchestration, IDP, config-server) were
unreachable.

Both the Starlette and FastAPI adapters now re-run filter discovery and
controller/ws/sse/OAuth2-login route collection inside the wrapped lifespan,
after start():
- WebFilterChainMiddleware holds the live filter list so in-place additions
  are seen per request.
- Filter/route discovery is factored into re-runnable, identity/path
  deduplicated closures; FastAPIControllerRegistrar.register_controllers is
  now idempotent.
- The rescan is exposed via app.state.pyfly_install_dynamic_wiring for
  callers managing their own lifespan.

This unblocks the security (#41/#42/#43/#44), admin (#66/#70),
orchestration-web (#163), config-server (#83) and CORS (#204) fixes.

Full suite 3399 passed; ruff + mypy clean.

* fix(transactional): workflow + TCC + scheduling parity (audit #53-65)

Orchestration was largely inert because nothing wired the declared beans:

- #53 @saga/@workflow/@tcc beans are now auto-discovered into their
  registries via a new OrchestrationBeanPostProcessor (mirrors Java
  ensureScanned) — previously every declared orchestration was dead.
- #54 @scheduled_saga/@scheduled_workflow/@scheduled_tcc are turned into
  live ScheduledTasks and the OrchestrationScheduler (already started by the
  context lifecycle) now fires them; register() spins up loops post-start.
- #55 wait_for_any no longer swallows timeouts and captures the winning
  signal payload.
- #56 TCC participant retry is N+1 attempts (was off-by-one) and falls back
  to class-level @tcc(retry_enabled, max_retries, backoff_ms).
- #57 per-participant try/confirm/cancel errors + latency are recorded so
  TccResult.failed_participants() works.
- #58 @on_workflow_error(suppress_error/error_types/step_ids) downgrades
  FAILED→COMPLETED.
- #59 @workflow_step(condition=...) is evaluated via a new safe AST
  expression evaluator (no eval); false → step SKIPPED.
- #60 async_ steps are fire-and-forget; #62 fire-and-forget run tasks hold a
  strong reference so they aren't GC-cancelled.
- #61 workflow-level retry propagates to steps that declare none.
- #63 @WaitForAll/@WaitForAny support timers; #64 named timer_id surfaced in
  the timer event; #65 warns on a compensatable step with no comp method.

Full suite 3411 passed; ruff + mypy clean.

* fix(security): wire JWT/OAuth2/CSRF/HttpSecurity filters + session + OIDC (audit #41-52)

The keystone (#40/#163) re-scans WebFilter beans post-start, but several
filters had no bean at all and were dead code:

- #41 SecurityFilter (symmetric JWT, opt-in via pyfly.security.jwt.filter.enabled)
  and OAuth2ResourceServerFilter are now registered as WebFilter beans by the
  security auto-configs that own their JWTService/JWKSTokenValidator (avoids
  cross-config bean ordering); the post-start rescan adds them to the chain.
- #42 CsrfFilter gains a CsrfFilterAutoConfiguration (pyfly.security.csrf.enabled)
  and its order is corrected to run before authentication (was -50, after).
- #45 @pre_authorize/@post_authorize now enforce once the auth filter populates
  RequestContext.security_context (integration test added).
- #46 RedisSessionStore round-trips dataclass attributes (SecurityContext) via a
  type-tagged JSON encoder/decoder instead of failing on json.dumps.
- #47 HttpSecurityFilterAutoConfiguration builds the URL-rule filter from a user
  HttpSecurity bean.
- #48 OAuth2 login validates the OIDC id_token against the provider JWKS + nonce
  before trusting claims; #49 surfaces token/userinfo failures as 401 (was a
  silently-stored anonymous session) and wraps httpx transport errors.
- #50 security expression evaluator accepts double-quoted args; #51 fixes the
  session-filter ordering docstring; #52 session cookie gains a configurable
  Secure flag + sliding re-issue.

Full suite 3415 passed; ruff + mypy clean.

* fix(client): error mapping, retry filtering, lifecycle, timeout (audit #12-15,#18)

- #12 (critical) the declarative client never checked HTTP status and returned
  4xx/5xx error payloads as success. New src/pyfly/client/exceptions.py adds a
  ServiceClientException hierarchy + map_http_error (400→Validation, 401/403→
  Authentication, 404→NotFound, 409→Conflict, 422→Unprocessable, 429→RateLimit,
  5xx→Unavailable); the generated impl raises on status >= 400.
- #13 retry now retries only transient failures (429/5xx-mapped, connection,
  timeout) — not 4xx or the circuit-open signal — and the wrapping order is
  fixed to circuit-breaker OUTSIDE / retry INSIDE so an OPEN circuit fails fast.
- #14 HttpClientBeanPostProcessor gains start()/stop(); the context lifecycle
  now closes every per-bean httpx client (was a connection-pool leak).
- #15 the post-processor builds adapters with the configured
  pyfly.client.timeout (declarative clients previously ignored it).
- #18 a declarative method's  param is sent as request headers (for
  per-call headers / auth injection) instead of as a query param.

Remaining client parity features (#16 OAuth2 client-credentials, #17 service
discovery, #19 request dedup, #20 client rate limiting) are net-new subsystems
tracked for a follow-up pass.

Full suite 3419 passed; ruff + mypy clean.

* fix(idp): REST controller, provider selection, adapter bugs (audit #22,#23,#25,#26,#28,#29)

- #22 (critical) the IdpAdapter bean was wired to nothing — no HTTP surface
  existed. New src/pyfly/idp/web.py adds an IdpController (/idp/login, /refresh,
  /logout, /introspect, /admin/users CRUD, /admin/roles) registered in the same
  auto-config as the adapter and mounted by the post-start route rescan.
- #25 provider selection: pyfly.idp.provider chooses internal-db | keycloak |
  cognito | azure-ad and builds the adapter from config (was hardwired to
  internal-db); the bean is now exposed under the IdpAdapter port type.
- #23 Cognito login computes SECRET_HASH = Base64(HMAC-SHA256(secret, user+id))
  when a client secret is configured (auth previously failed for secret clients).
- #26 Keycloak admin token is refreshed on expiry (tracked via expires_in) — it
  was cached forever and broke after the ~60s TTL.
- #28 Cognito login/refresh guard a missing AuthenticationResult and surface a
  clean PermissionError; refresh keeps a rotated refresh token.
- #29 internal-db assign_role populates the role catalogue + adds create_roles
  (list_roles was always empty).

Remaining idp parity (deferred): #24 port capability expansion (MFA/sessions/
scopes/userinfo/register), #27 Azure AD local token parsing + MFA.

Full suite 3424 passed; ruff + mypy clean.

* fix(notifications): wire real providers + delivery correctness (audit #30,#31,#35,#36,#38)

- #30 (critical) auto-config only ever registered Dummy providers and ignored
  any provider-selection config. It now reads
  pyfly.notifications.{email,sms,push}.provider and builds the real adapter
  (SendGrid/Resend/SMTP, Twilio, Firebase) from config, falling back to Dummy;
  providers are exposed under their port types so the services inject the port.
- #31 the SMTP adapter now attaches EmailMessage.attachments (was silently
  dropped); #35 it also adds custom EmailMessage.headers.
- #36 the Default{Email,Sms,Push}Service convert a provider exception into a
  structured FAILED NotificationResult instead of propagating.
- #38 ResendEmailProvider honors a configured default_from sender.

Deferred (net-new subsystems): #32 template-email engine, #33 channel
preferences, #34 notification metrics, #37 FCM batch.

Full suite 3428 passed; ruff + mypy clean.

* fix(cli): add PyFlyApplication.run() so the CLI archetype boots (audit #1)

The generated `cli` archetype's main() does asyncio.run(pyfly.run()), but
PyFlyApplication had no run() — every generated CLI crashed with
AttributeError. run() now starts the app, resolves the ShellRunnerPort
(populated with @shell_command handlers during startup), dispatches the args
(or sys.argv[1:], falling back to an interactive REPL), and shuts down.

Full suite 3431 passed; ruff + mypy clean.

* fix(cache): serializer, putIfAbsent, prefix-evict, stats, health, null-cache (audit #72-80)

- #72 a new cache serializer tolerates datetime/Decimal/UUID/set/Pydantic so
  the Redis put path no longer throws TypeError on framework types.
- #75 put_if_absent added to the protocol + both adapters (Redis SET NX,
  in-memory check-then-set).
- #78 evict_by_prefix added (Redis SCAN+delete, in-memory prefix filter).
- #76 both adapters track hit/miss/eviction counters and report hit_rate.
- #79 RedisCacheAdapter.start() degrades gracefully (logs + marks unavailable)
  instead of aborting application startup when Redis is unreachable.
- #74 new CacheHealthIndicator (put/get/evict probe + latency) registered by
  the cache auto-config so /actuator/health reports cache status.
- #80 @cacheable/@cache distinguish a cached None from a miss via exists()
  (null caching / cache-penetration protection).

Deferred: #73 SmartCacheAdapter (L1/L2 read-through), #77 cache metrics,
#81/#82 CacheManager protocol completeness.

Full suite 3437 passed; ruff + mypy clean.

* fix(cqrs): metrics registry, deterministic cache key, correlation, validation metric (audit #94,#98,#99,#100)

- #94 cqrs_metrics_service now receives the observability MetricsRegistry via
  optional injection, so CQRS metrics are actually recorded (was permanently
  no-op).
- #100 Query.get_cache_key() uses a stable SHA-256 digest instead of the
  process-randomized builtin hash(), so the same query maps to the same key
  across processes/restarts.
- #98 the command bus restores the prior correlation id in a finally block so
  it no longer leaks into the next command on the same task.
- #99 a CqrsValidationException now records the validation-failure metric.

Deferred (involved wiring): #93 EventDrivenCacheInvalidator, #95
@publish_domain_event, #96 CqrsMetricsEndpoint, #97 publisher destination/headers.

Full suite 3439 passed; ruff + mypy clean.

* fix(scheduling/resilience): sync time-limiter, Spring cron, scheduled-failure logging (audit #184,#185,#186)

- #184 the synchronous time_limiter ran the callable in a worker thread and
  waits with a fractional timeout instead of SIGALRM, which truncated
  sub-second timeouts to whole seconds and crashed off the main thread.
- #185 CronExpression accepts Spring-style 6-field (seconds-first) cron and the
  '?' day placeholder (via croniter second_at_beginning + normalization), not
  just standard 5-field cron.
- #186 _invoke logs exceptions, so a failing cron / fixed-rate iteration (whose
  task the loop does not await) is reported instead of vanishing silently.

Full suite 3443 passed; ruff + mypy clean.

* fix(validation): ISO-4217 currency, IBAN length, card-scheme checks (audit #191,#192,#193)

- #191 is_valid_currency_code checks membership of the active ISO 4217 set
  (was: any 3 uppercase letters).
- #193 is_valid_iban enforces the country-specific total length per ISO 13616
  (was: general format + mod-97 only).
- #192 is_valid_credit_card requires a recognized scheme prefix (Visa, MC,
  Amex, Discover, Diners, JCB) before the Luhn check (was: Luhn only).

Full suite 3446 passed; ruff + mypy clean.

* fix(callbacks): SSRF domain allowlist + retry only transient failures (audit #190,#194)

- #190 the dispatcher enforces config.authorized_domains before delivery: a
  target host not matching the allowlist is marked FAILED ("Domain not
  authorized") and no HTTP request is made (SSRF protection).
- #194 retries are limited to transient failures (5xx/408/429 + transport
  errors) with exponential backoff capped at 5 min; a 4xx client error is now
  permanent (was: retry every non-2xx with fixed backoff).

Full suite 3448 passed; ruff + mypy clean.

* fix(data): soft-delete read paths + connection-pool config (audit #103,#107)

- #103 SoftDeleteRepository overrides find_paginated, find_all_by_ids,
  find_all_by_spec and find_all_by_spec_paged to apply the not-deleted
  predicate (incl. the page-total count) — these inherited base readers
  previously leaked soft-deleted rows and miscounted pagination totals.
- #107 the SQLAlchemy engine forwards configured connection-pool settings
  (pool.size/max-overflow/timeout/recycle/pre-ping) to create_async_engine;
  only url and echo were read before.

Full suite 3450 passed; ruff + mypy clean.

* fix(eventsourcing): fail on unhandled events, replay validation, snapshot interval (audit #146,#150,#151)

- #146 AggregateRoot._dispatch raises EventHandlerException when an event has
  no registered handler (or on_<type> method) instead of silently swallowing
  it and corrupting reconstructed state.
- #150 EventSourcedRepository.load validates each replayed envelope's
  aggregate_id / aggregate_type against the loaded aggregate.
- #151 a snapshot is taken when the appended batch CROSSES a multiple of the
  snapshot interval (was: exact 'version % interval == 0', which is missed
  when a batch straddles the threshold).

Full suite 3451 passed; ruff + mypy clean.

* fix(rule-engine): fail on unknown actions, isolate action failures, validate 'not' (audit #215,#216,#222)

- #215 the default evaluator raises NotImplementedError for unsupported action
  types ('call'/'calculate'/typos) instead of silently doing nothing.
- #216 each action runs in isolation: a failing action records its error on the
  EvaluationResult and the remaining actions still execute.
- #222 the 'not' operator requires exactly one child; empty/multiple children
  raise instead of silently using only the first.

Full suite passed; ruff + mypy clean.

* chore: gitignore local .audit/ remediation working files

* fix(eda): @event_listener discovery, publish timing, serializer/consumer config (audit #134,#138,#140,#141)

- #134 @event_listener now stamps discovery metadata and supports a bus-less
  form (@event_listener(["user.*"])); a new ApplicationContext._wire_event_listeners
  pass auto-subscribes decorated methods to the EventPublisher bean during
  startup (mirrors @message_listener) — previously it only worked with a
  hand-wired bus.
- #140 @event_publisher AFTER/BOTH publishes a payload augmented with the
  method result instead of re-publishing the pre-call arguments.
- #138 the EDA auto-config selects the serializer from
  pyfly.eda.serialization-format (json|avro|protobuf) and passes it to the
  Kafka/Redis adapters (Avro/Protobuf remain opt-in stubs).
- #141 the Redis adapter receives the configured consumer-id.

Deferred (cross-adapter dispatch refactor): #131 DLQ routing, #132
ErrorStrategy, #133 circuit-breaker wiring, #135 postgres outbox stall, #136
event filters, #137 metrics, #139 health probe.

Full suite 3457 passed; ruff + mypy clean.

* fix(config): placeholder env overrides + config-client merge order (audit #86,#87,#89)

- #86 ConfigClient applies remote propertySources in reverse (lowest priority
  first) so the highest-priority source wins, matching Spring (was: forward
  order, so the lowest-priority source won).
- #87/#89 inline ${...} placeholder resolution now consults the PYFLY_* relaxed
  env mapping (e.g. ${app.name} → PYFLY_APP_NAME) before the raw file data, so
  env overrides are visible to placeholders and win.

Full suite passed; ruff + mypy clean.

* fix(di): @config_properties classes are injectable beans bound from config (audit #118)

The @config_properties decorator now marks the class injectable
(__pyfly_injectable__), so the scanner registers it; ApplicationContext binds
each registered __pyfly_config_prefix__ class from the active Config via a
factory, making it constructor-injectable by type (Spring
@EnableConfigurationProperties equivalent). Previously these classes were only
usable when a @bean method manually called config.bind().

Full suite green; ruff + mypy clean.

* fix(saga): honor configured compensation_policy (audit #170; #178 already done)

- #170 SagaEngineProperties is now bound from pyfly.transactional.saga.* (was
  built with defaults), SagaEngine stores a default_compensation_policy, and
  execute() falls back to it when a caller does not override — the configured
  YAML compensation_policy was previously inert (engine always STRICT_SEQUENTIAL).
- #178 (scheduled sagas) was already addressed by the OrchestrationBeanPostProcessor
  added in b2d0f4e, which schedules @scheduled_saga beans.

Deferred (compensator/orchestrator internals): #171 compensation-error
abort, #172 idempotency keys, #173 recovery scheduling, #174-177, #179.

Full suite 3461 passed; ruff + mypy clean.

* fix(server/websocket): serve_async honors full config + ws on_disconnect (audit #226,#232)

- #226 a shared UvicornServerAdapter._build_kwargs feeds both serve()
  (uvicorn.run) and serve_async() (uvicorn.Config), so the async path honors
  SSL / keep-alive / backlog / graceful-timeout / concurrency limits that the
  blocking path already did (they were previously dropped from serve_async).
- #232 the websocket endpoint logs unexpected handler exceptions (no longer
  swallowed) and invokes an on_disconnect lifecycle hook when the controller
  defines one.

Full suite passed; ruff + mypy clean.

* fix(web): RFC-compliant required params, CORS auto-config, exception-converter wiring (audit #202/#204/#206)

#206 — Missing required QueryParam/Header/Cookie now raises a 400
  (InvalidRequestException) instead of silently binding None. A param is
  optional only when it has a default or an Optional inner type (str | None).
  Surfaced two latent transactional filter params that were meant to be
  optional; their inner types are now honestly str | None.

#204 — CORS is auto-configured from pyfly.web.cors.* via
  CORSConfig.from_config(), threaded into create_app for both the Starlette
  and FastAPI adapters when no explicit CORSConfig is passed. Secure-by-default
  (disabled unless pyfly.web.cors.enabled), mirroring Spring CorsAutoConfiguration.

#202 — ExceptionConverterService is now wired into global_exception_handler.
  Non-PyFly exceptions are translated via the built-in chain (Pydantic, JSON,
  timeout) plus any user @bean ExceptionConverter, discovered at startup and
  stashed per-app on app.state. Falls back to 500 only when nothing matches.

Tests: tests/web/test_wave_web.py (14). Suite 3462 -> 3476 green; ruff + mypy clean.

* fix(ecm): provider-based storage/e-signature adapter selection + honor delete result (audit #120/#125)

#120 — EcmAutoConfiguration now selects the storage adapter from
  pyfly.ecm.storage.provider (local | s3/aws | azure) and the e-signature
  adapter from pyfly.ecm.esignature.provider (noop | docusign | adobe | logalty),
  reading each provider's own config sub-keys. All producer beans (storage,
  metadata, folders, e-signature) now return their PORT types so DocumentService
  / ESignatureService inject abstractions; the container registers each bean
  under both the concrete type and the port, so port-typed injection resolves.
  Previously the adapter classes existed but were dead — only LocalFilesystem +
  NoOp were ever wired regardless of config.

#125 — DocumentService.delete now returns storage_ok AND metadata_ok instead of
  discarding the storage delete result, so a failed blob delete is surfaced.

Tests: tests/ecm/test_wave_ecm.py (12) incl. a real-ApplicationContext wiring
test that round-trips an upload/download through the auto-wired ports.

Deferred (per-module): #121 DocumentVersionPort, #122 signature lifecycle/proof
ports (net-new subsystems), #126 version refetch, #127/#128/#129 provider get()
polish, #130 folder hierarchy. #124 (enabled-by-default) intentionally NOT
flipped: every sibling optional module (cache/notifications/eventsourcing/
rule-engine/callbacks/idp) is uniformly opt-in via enabled=true; flipping only
ECM would make it the lone default-on module — a deliberate pyfly convention.

Suite 3476 -> 3488 green; ruff + mypy clean.

* fix(observability,actuator): wire span exporter, correct threaddump className, guard prometheus endpoint (audit #153/#161/#162)

#153 — TracingAutoConfiguration.tracer_provider now installs a BatchSpanProcessor
  with an exporter selected from config (pyfly.observability.tracing.exporter =
  otlp | console | none). When unset, OTLP is auto-selected iff an endpoint is
  configured (pyfly.observability.tracing.otlp.endpoint or the standard
  OTEL_EXPORTER_OTLP_ENDPOINT env var), with graceful fallback + a warning if the
  OTLP exporter package is missing; otherwise a single info line is logged so the
  drop is no longer silent. Previously the provider had no processor, so every
  @span trace was recorded and immediately discarded.

#161 — threaddump now reports className as the frame's module (__name__) and
  methodName as the qualified function name (co_qualname), instead of setting both
  to the bare function name. Walks the frame chain so co_filename/co_name/module
  are read per frame.

#162 — prometheus endpoint: enabled now reflects prometheus_client availability,
  and handle() returns a 503 text body instead of raising TypeError when the
  client is absent at request time.

Tests: tests/observability/test_wave_observability.py (4), tests/actuator/test_wave_actuator.py (3).

Deferred (observability wave-2): #154 trace/correlation IDs into log records,
#155 W3C traceparent extraction into OTel context, #157 config-driven health
groups, #158 firefly.health.status gauge, #159 common metric tags, #160 actuator
beans unused by route builder. #156 (default web exposure incl. metrics/prometheus)
intentionally NOT changed — pyfly deliberately mirrors Spring Boot's secure-by-
default exposure (health,info), set in commit #25; auto-exposing metrics would be
a security regression.

Suite 3488 -> 3495 green; ruff + mypy clean.

* fix(i18n,resilience): MessageFormat quote-escaping + unified bulkhead permit accounting (audit #187/#189)

#187 — ResourceBundleMessageSource._substitute now honors java.text.MessageFormat
  quote semantics: '' renders as a literal apostrophe, single-quoted text is
  copied literally (so '{0}' is not substituted), and {n}/{n,type,style} insert
  the positional arg (index parsed; format style is a documented non-locale-applied
  subset). Previously naive str.replace left ''/quoted placeholders wrong.

#189 — Bulkhead now uses a single threading.Lock-guarded permit counter as the
  sole source of truth for BOTH sync and async decorated calls (the divergent
  asyncio.Semaphore is removed). The sync wrapper now goes through the same
  _acquire_slot/_release_slot primitive as the async path, so a Bulkhead shared
  across sync + async can no longer desynchronise its capacity accounting; the
  atomic check-and-increment also closes the async check/acquire TOCTOU.

Tests: tests/i18n/test_wave_i18n.py (8), tests/resilience/test_wave_resilience.py (4).

#188 (i18n MessageSource opt-in vs Spring default-on) intentionally NOT changed —
the finding itself says opt-in is acceptable if intentional; every sibling optional
module is uniformly opt-in via enabled=true (same convention as #124/#156).

Suite 3495 -> 3507 green; ruff + mypy clean.

* fix(plugins): extension-point registration/validation + unload unregisters extensions (audit #218/#219)

#218 — ExtensionRegistry now records extension points: register_extension_point,
  has_extension_point, extension_point_ids. PluginManager.add() scans inner
  @extension_point classes (the decorated class is the point's interface type)
  and registers them BEFORE extensions, so register() validates that each
  contributed extension is an instance of its declared point type and raises
  ValueError otherwise — mirroring Java's DefaultExtensionRegistry. Previously the
  @extension_point decorator's metadata was pure dead code, never read by anything.
  Registration against an id with no declared point type stays lenient
  (backward-compatible) rather than raising on unknown point.

#219 — PluginManager now tracks the (point_id, instance) pairs each plugin
  registers and adds remove(plugin_id) + unload_all(): unloading a plugin runs its
  unload hook, unregisters its extensions from the registry, and forgets it, so
  extensions no longer leak in the registry for the process lifetime after a plugin
  is unloaded (mirrors Java's unloadPlugin -> unregisterPluginExtensions).

Tests: tests/plugins/test_wave_plugins.py (8).

#220 (rule-engine audit trail) deferred — net-new subsystem (AuditTrailService/
entity/repository/controller + evaluate-with-audit); out of scope for this pass,
documented like other net-new subsystem gaps.

Suite 3507 -> 3515 green; ruff + mypy clean.

* fix(orchestration-web): DLQ /count endpoint + in-flight default for GET /executions (audit #167/#169)

#167 — DeadLetterController now exposes GET /api/orchestration/dlq/count, backed by
  a new DeadLetterService.count() and DeadLetterStore.count() (InMemory impl
  returns len). Java's DeadLetterController exposes /count for dashboards; pyfly
  previously 404'd on it and had no service-level count().

#169 — OrchestrationController.list_executions now defaults to in-flight
  (non-terminal) executions when no status filter is given, instead of returning
  the entire store including terminal history — matching Java's findInFlight()
  default. Explicit ?status=<S> still filters exactly. Uses the existing
  ExecutionStatus.is_terminal.

Tests: tests/transactional/test_wave_orchestration_web.py (4).

Deferred (orchestration-web): #163 already done (wave-0 route rescan). #164
WorkflowController 2->14 endpoints + WorkflowEngine cancel/suspend/resume/
find_by_correlation_id/find_by_status (large engine+REST expansion), #165
per-controller rest.enabled/health.enabled gates, #166 orchestration-metrics
actuator endpoint, #168 DLQ retry real re-execution (needs engine re-enqueue).

Suite 3515 -> 3519 green; ruff + mypy clean.

* fix(starters): correct property keys so bundled adapters actually activate (audit #2/#3/#4/#6)

Starter stacks set property keys their auto-configs never read, so the bundled
adapters/services silently never activated (the old keys had ZERO consumers).
Fixed to the keys the conditions actually gate on:

  #2 data/domain: pyfly.relational.enabled  -> pyfly.data.relational.enabled
                  pyfly.document.enabled     -> pyfly.data.document.enabled
  #3 core:        pyfly.eda.enabled          -> pyfly.eda.provider=auto
                  (EdaAutoConfiguration gates on pyfly.eda.provider; 'auto' resolves
                   to the best installed broker, falling back to the in-memory bus)
  #4 application: pyfly.security-jwt.enabled / pyfly.security-password.enabled
                  / pyfly.session-filter.enabled -> pyfly.security.enabled=true
                  (JWT auth WebFilter stays opt-in via pyfly.security.jwt.filter.enabled)
  #6 core/web:    pyfly.actuator.enabled / pyfly.actuator.metrics.enabled
                  -> pyfly.web.actuator.enabled

Scaffold (pyfly.yaml.j2): added pyfly.security.enabled to the security feature
block so generated security apps wire JWTService + the password encoder. Left the
'eda' feature's messaging: block as-is — pyfly.messaging.provider drives the SEPARATE
MessagingAutoConfiguration (MessageBrokerPort), a real distinct subsystem, and is
covered by an existing test; it is not the EDA EventPublisher path.

Updated the existing test_starters.py assertions (old keys) in lockstep.
Tests: tests/starters/test_wave_starter_keys.py (8, functionally proving each
auto-config's conditions now pass via ConditionEvaluator with deps installed) +
1 scaffold security test.

Deferred: #5 test-slice decorators (net-new), #10 testcontainers (net-new),
#11 inert pyfly.web/observability/metrics/tracing/resilience/aop.enabled keys
(deliberate convention: those auto-configs activate on @conditional_on_class, not
property flags).

Suite 3519 -> 3528 green; ruff + mypy clean.

* fix(testing,cli,shell): inject mock_bean, thread wizard package name, honor shell_option type/choices (audit #7/#8/#9)

#7 — PyFlyTestCase.setup() now registers every mock_bean(...) descriptor's
  AsyncMock into the context container keyed on its bean type, so DI-resolved
  collaborators receive the mock. Previously the descriptors produced a mock on
  the test instance but it was never wired into the ApplicationContext, so
  context.get_bean(T) returned the real/absent bean.

#8 — generate_project()/_build_context() accept an explicit package_name; the
  interactive 'pyfly new' wizard's collected package name is now threaded through
  instead of being discarded and recomputed from the project name.

#9 — @shell_option(type=...) / @shell_argument(type=...) overrides are now honored
  by param inference (param_type = explicit type or inferred inner_type), and
  shell_option gained a choices= kwarg that flows onto the resolved ShellParam.

Tests: tests/testing/test_wave_mock_inject.py (2), tests/cli/test_wave_new_package.py (4),
tests/shell/test_wave_shell_option.py (4).

Suite 3528 -> 3538 green; ruff + mypy clean.

* fix(config-server): full overlay propertySources + configurable persistent backend root (audit #85/#88)

#85 — ConfigServer.fetch now emits the standard Spring-Cloud-Config overlay set
  (highest priority first): {app}/{profile}, {app}/default, application/{profile},
  application/default — deduped, skipping absent overlays, returning None only
  when all are absent. Previously it returned a single propertySource, so an app's
  default bundle and shared application config were never delivered.

#88 — ConfigServerAutoConfiguration.config_backend now reads
  pyfly.config-server.backend.root (or .native.search-locations) and persists
  there, falling back to a throwaway tempdir only when nothing is configured.
  Previously every boot used a fresh mkdtemp() that served nothing and lost saves
  on restart. The bean now injects Config (same pattern as the actuator beans).

Tests: tests/config_server/test_wave_config_server.py (7). Existing
test_server_returns_property_sources stays green (single source -> [0] unchanged).

Suite 3538 -> 3545 green; ruff + mypy clean.

* fix(config): relaxed kebab/snake key + placeholder resolution, env-only key injection (audit #90/#92)

#92 — _raw_get() and ${...} config-reference resolution now use relaxed
  (kebab/snake interchangeable) segment matching via a new _dict_get_relaxed
  helper, with an exact-match fast path first. So ${my-prop.sub-key} resolves a
  value stored under my_prop.sub_key (and vice versa), matching bind()'s relaxed
  semantics; previously get()/placeholders required literal key segments.

#90 — effective_section()/bind() now inject env-only keys: a PYFLY_<PREFIX>_*
  environment variable with no corresponding file leaf is materialized into the
  section (scoped to the prefix, treating each '_' as a path separator, only
  adding absent leaves). So an env-only @config_properties field now binds, where
  before get() honored the env var but bind()/effective_section dropped it. The
  rootless ('') prefix is skipped (ambiguous without a section anchor), so the
  broad effective_dict() actuator/admin view is unchanged.

Tests: tests/core/test_wave_config_relaxed.py (9). Full suite green across the
broad _raw_get change.

Suite 3545 -> 3554 green; ruff + mypy clean.

* fix(config-server): mount ConfigServer HTTP routes (audit #83)

The ConfigServer bean was built but never reachable over HTTP, so a config server
served nothing. Added a Starlette adapter (config_server/adapters/starlette.py,
the hexagonal starlette boundary) exposing Spring-Cloud-Config routes
(GET/POST /{application}/{profile}[/{label}], GET /_list), and a
config_server/wiring.py build_config_server_routes(context) that discovers the
ConfigServer bean and mounts them when pyfly.config-server.enabled=true.

Because the bean is only instantiated during ApplicationContext.start() (after
create_app returns), the routes are added in BOTH the eager create_app path (for
an already-started context) AND the post-start _install_dynamic_wiring rescan,
deduped by route key — same keystone pattern as orchestration/admin controllers.
Mirrored into the FastAPI adapter's _install_context_routes. base_path is read
from pyfly.config-server.base-path (default root).

Tests: tests/config_server/test_wave_config_server.py — adapter round-trip +
routes-mounted-when-enabled (real ApplicationContext + TestClient) + absent-when-
disabled. Hexagonal isolation test stays green (starlette only in the adapter).

Suite 3554 -> 3557 green; ruff + mypy clean.

* fix(config): import remote config from a config server at bootstrap (audit #84)

PyFlyApplication.__init__ now invokes ConfigClient when pyfly.cloud.config.uri
(or pyfly.config.import) is set, fetching remote config from a Spring-Cloud-Config
server and deep-merging it as a HIGH-precedence source over local config. The
flat dotted propertySource map is expanded to nested via _merge_dotted; the source
is recorded in loaded_sources.

Runs before the logging adapter/context exist (uses a stdlib logger). Fully
optional and non-fatal by default — a missing httpx, unreachable server, or
non-200 logs a warning and falls back to local config — unless
pyfly.cloud.config.fail-fast=true. Guards against asyncio.run inside an already-
running loop (skips with a warning). No-op (early return) when no uri is set, so
every existing app is unaffected.

Tests: tests/config_server/test_wave_remote_config.py (4, sync so asyncio.run
works): merged-at-bootstrap, no-uri-skips, failure-non-fatal, fail-fast-propagates.

config-server module now fully remediated (#83/#84/#85/#86/#87/#88/#89/#90/#92).
Suite 3557 -> 3561 green; ruff + mypy clean.

* fix(admin): enforce require_auth, TRACE/OFF log levels, mount beans SSE (audit #66/#69/#71)

#66 — AdminRouteBuilder now wraps every {base}/api/* route (data, mutation, SSE,
  instance registry) with an auth guard: when pyfly.admin.require-auth is true, a
  request lacking an authenticated SecurityContext gets 401 and one missing every
  allowed role gets 403 (read from the request-scoped RequestContext). The SPA
  shell + static assets stay public so the dashboard can boot and then surface the
  401s. No-op when require_auth is false (default), so existing behavior is
  unchanged. Routes are now built from a guarded spec list.

#69 — LoggersProvider.set_level resolves TRACE (->5, below DEBUG) and OFF
  (->CRITICAL+1, disables) explicitly; both were advertised as valid levels but
  getattr(logging, 'TRACE'/'OFF') is None, so selecting them silently returned 400.

#71 — the beans SSE generator (admin/api/sse.py beans_stream) is now reachable via
  GET {base}/api/sse/beans; it existed but was never routed.

Tests: tests/admin/test_wave_admin_auth.py (10). Suite admin 115 -> 125 green;
ruff + mypy clean.

* fix(admin): server-mode instance registry, client self-registration, health rescan (audit #67/#68/#70)

#67 — create_app now binds AdminServerProperties and, when
  pyfly.admin.server.enabled=true, builds an InstanceRegistry, seeds it from the
  configured instances via StaticDiscovery, and passes it to AdminRouteBuilder —
  so the /api/instances routes mount and settings.serverMode reports true.
  Previously server mode was permanently off (registry never constructed).

#68 — AdminClientRegistration gained start()/stop() lifecycle methods that honor
  auto_register (now threaded from AdminClientProperties), so the
  ApplicationContext infrastructure lifecycle self-registers the app with the
  remote admin server at startup and deregisters at shutdown. register() swallows
  its own errors, so a down admin server never aborts startup.

#70 — when the actuator is disabled but admin is enabled, the admin-owned
  HealthAggregator now gets a post-start indicator rescan (appended to
  _extra_post_start), so the admin health view reflects HealthIndicator beans
  instantiated during start() instead of a frozen empty pre-startup snapshot.

Tests: tests/admin/test_wave_admin_wiring.py (6). Admin module fully remediated
(#66/#67/#68/#69/#70/#71). Suite 3561 -> 3577 green; ruff + mypy clean.

* docs(release): v26.06.01 — refresh docs to match remediation, bump version

- Bump version 26.06.00 -> 26.06.01 (pyproject 26.6.1, __version__, README badge).
- CHANGELOG: comprehensive v26.06.01 entry covering the ~130-finding parity/wiring
  remediation (web required-params + CORS + exception converters; config relaxed
  binding + env-only keys + remote import; config-server HTTP routes/overlays/root;
  admin auth + server-mode + client registration + log levels + beans SSE;
  tracing exporter; starter property keys; ECM provider selection; plugin
  extension-point validation/unload; orchestration DLQ count + in-flight default;
  bulkhead permit accounting; i18n MessageFormat; shell option type/choices;
  mock_bean injection; pyfly new package name).
- Docs refreshed against current code across web, configuration, config-server,
  admin, observability, actuator, ecm, plugins, resilience, transactional,
  validation, shell, testing, cli, error-handling, web-filters; new module guides
  for i18n and websocket; indexes updated.
- fix(config): remote-config import reads pyfly.app.name (was the inconsistent
  pyfly.application.name), matching the framework-wide key.

Suite 3577 green; ruff + mypy clean.

* style: fix import ordering in 3 wave test files (ruff I001, CI lint)

---------

Co-authored-by: Andrés Contreras Guillén <ancongui@Andress-MacBook-Pro.local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file python Pull requests that update python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant