Changelog¶
Release notes for EDRI, grouped by user-facing impact. Expand the changed-file lists when you need implementation detail.
Note
Versions ending in rcN are release candidates. Their APIs and behavior
may still change before the corresponding stable release.
How this changelog is generated
This page is generated from reachable Git tags, Conventional Commit subjects, and optional Changelog-* metadata. CI regenerates it before each documentation build.
Unreleased¶
2026.10.03 — 2026-10-15¶
Fixed¶
Harden static file responses.
Static files are no longer served as text/html when their type is unknown, carry X-Content-Type-Options: nosniff, and accept only GET and HEAD.
Unknown and compressed (.gz) static files are served as application/octet-stream; CSS, JavaScript, fonts, images, and WebAssembly have a fixed Content-Type on every Python version and host.
Breaking change: Methods other than GET and HEAD on a static file return 405 instead of the file.
Documentation: Static files
3 changed files
- Mdocs/source/static_files.md
- Medri/api/handlers/http_handler.py
- Atests/api/handlers/test_static_assets.py
Documentation¶
Document static file serving on its own page.
A new Static files page explains how unrouted URLs are served from EDRI_ASSETS_PATH, which routes and clients shadow them, what headers are sent, and why everything in the directory is public.
Documentation: Static files
2026.10.02 — 2026-10-13¶
Fixed¶
FilterBuilder negative filters on relationship paths
Negative FilterBuilder operators on dotted relationship paths now also match rows that have no related row.
not,doesNotContain,isNoneOf,notBetween, andisEmptyon a dotted path negate the positive EXISTS; on to-many and many-to-many paths they mean that no related row matches.
Documentation: SQLAlchemy integration
3 changed files
- Mdocs/source/integrations/sqlalchemy.md
- Medri/integrations/sqlalchemy/filter.py
- Mtests/integrations/test_sqlalchemy.py
orm_validator() on SQLAlchemy 2.1
orm_validator() again rejects a column whose type has no known Python type when running on SQLAlchemy 2.1.
Documentation: SQLAlchemy integration
1 changed file
2026.10.01 — 2026-10-12¶
Added¶
Add the edri new command.
Add the optional edri command; edri new creates a runnable project skeleton with one placeholder Manager.
Documentation: Getting Started
2 changed files
- Mdocs/source/getting_started.md
- Atests/cli/test_generated_project.py
Changed¶
At-least-once delivery between Router and Switch
Events are kept by the Switch until the receiving Router acknowledges them, so a Router that reconnects no longer loses events that were still waiting for it. Delivery is at-least-once with de-duplication, and an acknowledgement means the event reached the next process, not that a manager finished handling it.
A replay requested with SendFrom for one router is no longer also sent to every subscriber, which delivered it twice.
Breaking change: The Connector-Switch wire protocol is version 2; a Switch and its Connectors on different versions refuse each other's frames.
Migration: Upgrade the Switch and every Connector together.
15 changed files
- Aedri/protocol/delivery.py
- Medri/protocol/frame.py
- Medri/router/connector/connector.py
- Medri/router/connector/socket.py
- Medri/switch/connection.py
- Medri/switch/forwarder.py
- Aedri/switch/mailbox.py
- Medri/switch/receiver.py
- Medri/switch/sender.py
- Medri/switch/switch.py
- Mtests/router/connector/test_socket.py
- Mtests/router/test_connector.py
- Atests/switch/test_delivery_gaps.py
- Mtests/switch/test_handle_connection.py
- Mtests/switch/test_status.py
Fixed¶
Cache replay after a Switch outage
A Router now replays only the events it produced itself, and still replays what it has cached when the resume point has already expired. Previously the second case replayed nothing.
Events that already left every cache cannot be recovered, and a replay may deliver some events twice.
5 changed files
- Medri/router/cache.py
- Medri/router/router.py
- Atests/router/test_delivery_gaps.py
- Mtests/router/test_router.py
- Atests/test_switch_delivery.py
Run AsyncManagerBase start-up inside the event loop.
AsyncManagerBase runs its start-up, including after_start() and the events received while subscribing, inside the running event loop, so start-up events for async def handlers no longer crash the manager.
Breaking change: In AsyncManagerBase, after_start() now runs inside a running event loop, so calling asyncio.run() or loop.run_until_complete() there raises RuntimeError.
Migration: Make after_start() create tasks or loop-bound resources directly instead of running its own event loop.
Documentation: AsyncManagerBase
4 changed files
- Mdocs/source/async_manager.md
- Medri/abstract/manager/async_manager_base.py
- Medri/abstract/manager/manager_base.py
- Mtests/abstract/manager/test_async_manager_base.py
2026.09.08 — 2026-10-08¶
Added¶
Add opt-in SQLite write-behind persistence.
Add optional SQLite persistence to the KV Store with asynchronous writes, startup restoration and TTL across restarts.
Documentation: Specialized managers
12 changed files
- Mdocs/source/edri_class.md
- Mdocs/source/specialized_managers.md
- Medri/__init__.py
- Aedri/dataclass/persistence_failure_policy.py
- Medri/utility/manager/__init__.py
- Aedri/utility/manager/_store_persistence.py
- Medri/utility/manager/store.py
- Atests/integration/test_store_persistence.py
- Mtests/test_edri_init.py
- Mtests/test_public_api.py
- Mtests/test_public_api_imports.py
- Atests/utility/manager/test_store_persistence.py
Changed¶
Restructure the SQLite persistence section.
Reorganize the Store SQLite persistence documentation into short, scannable subsections.
Documentation: Specialized managers
1 changed file
Document the start order of a persistent Store.
Document that a persistent Store should be started before the API, Broker, Scheduler and run().
Documentation: Specialized managers
1 changed file
Fixed¶
Exclude the health events from gRPC instead of warning.
EdriHealth and EdriReady are now declared as excluded from gRPC, so building the gRPC schema no longer logs a skip warning for each of them. EdriReady is also no longer offered over WebSocket, since its readiness signal is an HTTP 503.
3 changed files
- Mdocs/source/grpc.md
- Medri/events/edri/router/health_check.py
- Mtests/api/grpc/test_schema.py
Keep persistence failures observable and preserve Unicode keys.
Keep Store persistence failures observable, preserve surrogate-containing keys and avoid redundant missing-key deletes.
Documentation: Specialized managers
5 changed files
- Mdocs/source/specialized_managers.md
- Medri/utility/manager/_store_persistence.py
- Medri/utility/manager/store.py
- Mtests/integration/test_store_persistence.py
- Mtests/utility/manager/test_store_persistence.py
Snapshot updates and propagate persistence startup failures.
Snapshot Store persistence updates, invalidate stale data after serialization errors and propagate startup restoration failures to the application.
Documentation: Specialized managers
7 changed files
- Mdocs/source/specialized_managers.md
- Medri/__init__.py
- Medri/utility/manager/_store_persistence.py
- Medri/utility/manager/store.py
- Mtests/integration/test_store_persistence.py
- Mtests/test_edri_init.py
- Mtests/utility/manager/test_store_persistence.py
Preserve retry wakeups and recover batch preparation failures.
Preserve Store persistence retry wakeups, recover batch preparation failures and allow configurable restoration deadlines.
Documentation: Specialized managers
9 changed files
- Mdocs/source/edri_class.md
- Mdocs/source/specialized_managers.md
- Medri/__init__.py
- Medri/dataclass/persistence_failure_policy.py
- Medri/utility/manager/_store_persistence.py
- Medri/utility/manager/store.py
- Mtests/integration/test_store_persistence.py
- Mtests/test_edri_init.py
- Mtests/utility/manager/test_store_persistence.py
Enforce database ownership and recover stopped writers.
Enforce exclusive Store database ownership and recover stopped persistence writers without losing buffered commands.
Documentation: Specialized managers
5 changed files
- Mdocs/source/specialized_managers.md
- Medri/utility/manager/_store_persistence.py
- Medri/utility/manager/store.py
- Mtests/integration/test_store_persistence.py
- Mtests/utility/manager/test_store_persistence.py
2026.09.07 — 2026-10-06¶
Fixed¶
Treat unset ENVIRONMENT as production.
An unset or empty ENVIRONMENT is now treated as production instead of development, so a deployment that omits the variable no longer exposes /edri/docs, /edri/topology and error details.
Breaking change: ENVIRONMENT unset or empty now runs as production instead of development.
Migration: Set ENVIRONMENT=development explicitly for local development.
3 changed files
- Mdocs/source/env.md
- Medri/config/setting.py
- Mtests/config/test_setting.py
2026.09.06 — 2026-10-06¶
Fixed¶
Treat unrecognised ENVIRONMENT values as production.
An unrecognised ENVIRONMENT value such as "prod" is now treated as production instead of development, so /edri/docs, /edri/topology and error details are no longer exposed by a typo. A warning is logged at startup.
Breaking change: An ENVIRONMENT value other than "development", "production" or empty now runs as production.
Migration: Set ENVIRONMENT=development explicitly if the development behaviour is intended.
Documentation: Environment variables
3 changed files
- Mdocs/source/env.md
- Medri/config/setting.py
- Mtests/config/test_setting.py
Older releases¶
209 older releases
2026.09.052026.09.042026.09.032026.09.022026.09.012026.09.01rc62026.09.01rc52026.09.01rc42026.09.01rc32026.09.01rc22026.09.01rc12026.08.03rc22026.08.03rc12026.08.022026.08.02rc42026.08.02rc32026.08.02rc22026.08.02rc12026.08.012026.07.042026.07.032026.07.022026.07.02rc122026.07.02rc112026.07.02rc102026.07.02rc92026.07.02rc82026.07.02rc72026.07.02rc62026.07.02rc42026.07.02rc32026.07.01rc102026.07.01rc92026.07.01rc82026.07.01rc72026.07.01rc62026.07.01rc52026.07.01rc42026.07.01rc32026.07.01rc22026.07.01rc12026.06.012026.06.01rc52026.06.01rc42026.06.01rc32026.06.01rc22026.06.01rc12026.03.032026.03.03rc52026.03.03rc42026.03.03rc32026.03.03rc22026.03.03rc12026.03.022026.03.012026.02.032026.02.022026.02.012025.12.032025.12.03rc12025.12.022025.12.02rc12025.12.012025.12.01rc32025.12.01rc22025.12.01rc12025.11.01rc42025.11.01rc32025.11.01rc22025.11.01rc12025.10.02rc12025.10.012025.10.01rc12025.09.04rc22025.09.04rc12025.09.032025.09.03rc12025.09.022025.09.02rc72025.09.02rc62025.09.02rc52025.09.02rc42025.09.02rc32025.09.02rc22025.09.02rc12025.09.012025.08.03rc42025.08.03rc32025.08.03rc22025.08.03rc12025.08.02rc42025.08.02rc32025.08.012025.07.022025.07.02rc32025.07.02rc22025.07.02rc12025.07.012025.07.01rc42025.07.01rc32025.07.01rc22025.07.01rc12025.06.012025.04.052025.04.042025.04.032025.04.022025.04.012025.04.01rc42025.04.01rc32025.04.01rc22025.04.01rc12025.03.032025.03.03rc72025.03.03rc62025.03.03rc52025.03.03rc42025.03.03rc32025.03.03rc22025.03.03RC12025.03.022025.03.02rc52025.03.02rc42025.03.02rc32025.03.02rc22025.03.02rc12025.03.012025.03.01rc62025.03.01rc52025.03.01rc42025.03.01rc32025.03.01rc22025.03.01rc12025.02.022025.02.012025.01.052025.01.042025.01.032025.01.022025.01.012024.12.082024.12.072024.12.062024.12.052024.12.042024.12.032024.12.022024.12.012024.12.02024.11.152024.11.142024.11.132024.11.122024.11.112024.11.102024.11.092024.11.082024.11.072024.11.062024.11.052024.11.042024.11.032024.11.022024.11.012024.10.162024.10.152024.10.142024.10.132024.10.122024.10.112024.10.102024.10.092024.10.082024.10.072024.10.052024.10.042024.10.032024.10.022024.10.012024.09.132024.09.122024.09.112024.09.102024.09.092024.09.082024.09.072024.09.062024.09.052024.09.042024.09.032024.09.022024.09.012024.06.042024.06.032024.06.022024.06.012024.04.012024.03.112024.03.102024.03.092024.03.082024.03.072024.03.062024.03.052024.03.042024.03.032024.03.022024.03.012024.02.01