---
orphan: true
---
# 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
In development0 changes
No unreleased changes.
## 2026.10.03 — 2026-10-15
Stable2 changes1 breaking change
Fixed 1Documentation 1
### Fixed
::::{admonition} Harden static file responses.
:class: edri-changelog-entry edri-changelog-entry-fixed
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:** {doc}`static_files`
3 changed files
::::
### Documentation
::::{admonition} Document static file serving on its own page.
:class: edri-changelog-entry edri-changelog-entry-documentation
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:** {doc}`static_files`
7 changed files
### Fixed
::::{admonition} FilterBuilder negative filters on relationship paths
:class: edri-changelog-entry edri-changelog-entry-fixed
Negative FilterBuilder operators on dotted relationship paths now also match rows that have no related row.
- `not`, `doesNotContain`, `isNoneOf`, `notBetween`, and `isEmpty` on a dotted path negate the positive EXISTS; on to-many and many-to-many paths they mean that no related row matches.
**Documentation:** {doc}`SQLAlchemy integration `
3 changed files
::::
::::{admonition} orm\_validator() on SQLAlchemy 2.1
:class: edri-changelog-entry edri-changelog-entry-fixed
orm_validator() again rejects a column whose type has no known Python type when running on SQLAlchemy 2.1.
**Documentation:** {doc}`SQLAlchemy integration `
1 changed file
### Added
::::{admonition} Add the edri new command.
:class: edri-changelog-entry edri-changelog-entry-added
Add the optional edri command; edri new creates a runnable project skeleton with one placeholder Manager.
**Documentation:** {doc}`getting_started`
2 changed files
::::
### Changed
::::{admonition} At-least-once delivery between Router and Switch
:class: edri-changelog-entry edri-changelog-entry-changed
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
::::
### Fixed
::::{admonition} Cache replay after a Switch outage
:class: edri-changelog-entry edri-changelog-entry-fixed
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
::::
::::{admonition} Run AsyncManagerBase start-up inside the event loop.
:class: edri-changelog-entry edri-changelog-entry-fixed
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:** {doc}`async_manager`
4 changed files
::::
::::{admonition} Document the start order of a persistent Store.
:class: edri-changelog-entry edri-changelog-entry-changed
Document that a persistent Store should be started before the API, Broker, Scheduler and run().
**Documentation:** {doc}`specialized_managers`
1 changed file
::::
### Fixed
::::{admonition} Exclude the health events from gRPC instead of warning.
:class: edri-changelog-entry edri-changelog-entry-fixed
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
::::
::::{admonition} Snapshot updates and propagate persistence startup failures.
:class: edri-changelog-entry edri-changelog-entry-fixed
Snapshot Store persistence updates, invalidate stale data after serialization errors and propagate startup restoration failures to the application.
**Documentation:** {doc}`specialized_managers`
7 changed files
### Fixed
::::{admonition} Treat unset ENVIRONMENT as production.
:class: edri-changelog-entry edri-changelog-entry-fixed
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
### Fixed
::::{admonition} Treat unrecognised ENVIRONMENT values as production.
:class: edri-changelog-entry edri-changelog-entry-fixed
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:** {doc}`Environment variables `
3 changed files