Repository navigation
Releases: alexogeny/wreath
Release list
v0.5.0
What's Changed
- feat: implement recent OAuth, JSONPath, Linkset, and SCIM RFCs by @alexogeny in #22
- perf: index runtime state and remove repeated work by @alexogeny in #23
- feat: bound runtime work and expose static-site builder by @alexogeny in #24
- perf: reduce hot-path instructions and retained memory by @alexogeny in #25
- perf: defer unused imports and allocations by @alexogeny in #26
- feat: add billing, ChatOps, and governed agents by @alexogeny in #27
- feat: add mutation-guided fuzzing and harden security boundaries by @alexogeny in #28
- fix: close security boundary gaps by @alexogeny in #29
- fix: harden adversarial input boundaries by @alexogeny in #30
- perf: reduce runtime work and retained memory by @alexogeny in #31
- release!: ship Wreath 0.5.0 with billing, ChatOps, and governed agents by @alexogeny in #32
Full Changelog: v0.4.0...v0.5.0
v0.4.0
What's Changed
- perf: move repeated framework work off hot paths by @alexogeny in #19
- Accelerate runtime paths and harden regression coverage by @alexogeny in #20
- release!: ship Wreath 0.4.0 with standards-native HTTP by @alexogeny in #21
Full Changelog: v0.3.4...v0.4.0
v0.3.4
What's Changed
- release: ship Wreath 0.3.4 with story-led docs and leaner request paths by @alexogeny in #18
Full Changelog: v0.3.3...v0.3.4
v0.3.3
v0.3.3
Released 2026-08-28.
Wreath 0.3.3 adds first-class request admission and deadline policies, moves the
default test and mutation workflow onto Wreath's native engine, and tightens
the authentication boundaries around audiences, browser sessions, OAuth
clients, and HMAC secrets. Existing applications using those authentication
surfaces need the migrations below; the new HTTP policies remain opt-in.
Breaking changes
wreath testnow uses the native engine by default and refuses unsupported
pytest fixtures, hooks, marks, plugins, or arguments during collection. Use
wreath test --engine pytestwhere that compatibility surface is required,
or--engine dualto compare collection and outcomes between both engines.JwtVerifierandapp.oidc_provider()require an explicit audience. Pass the
service audience, or passNoneonly when another layer performs the audience
check. OIDC issuers must be absolute HTTPS URLs, and provider HTTP clients and
discovered JWKS endpoints must share the issuer origin.- OIDC and SAML login state is now bound to a non-empty browser session. Pass a
stablesession_idtobegin_login()and the matching value at callback;
SAML consumers must also return the exactrelay_stateminted for that login. - Confidential
ClientRegistrationvalues require a client secret of at least
32 bytes. Present it when redeeming authorization codes, using client
credentials, or rotating client-bound refresh tokens. OAuth issuers must use
HTTPS, and configured HMAC signing secrets must also contain at least 32 bytes. - Object URL secrets, webhook HMAC keys, and retired session-cookie secrets now
reject material shorter than 32 bytes. Rotate short development values to
random secrets of at least that length before startup.
Added
ConcurrencyPolicy,DeadlinePolicy, andMaintenancePolicyprovide
fail-fast admission, async handler deadlines, and dynamically controlled
maintenance windows with refusal counters.RequestDecompressionPolicyaccepts one bounded gzip request member, while
SignedRoutePolicyprovides expiring, optionally single-use capabilities
bound to the normalized method, exact path, and original query ordering.SecurityHeadersPolicysupports per-request CSP nonces and report-only mode.
CsrfPolicycan accept an explicitly configured form field while retaining
the header-only fast path.
Changed
- OAuth refresh rotation preserves the original audience, scope, tenant, and
client binding, enforces a configurable lifetime, and refuses attempts to
widen the original grant. - Native test collection is reused by mutation and fuzz work. Pytest remains an
independent compatibility oracle rather than a silent fallback. - File responses no longer hold an executor worker while a slow client drains
the body.HEADrequests stat the same descriptor and emit the correct range
headers without reading file contents, and static lookup admission is bounded
before work enters its executor.
Fixed
- OIDC discovery can no longer redirect JWKS loading across origins or hide
credentials, queries, or fragments in the configured issuer. - SAML RelayState and OIDC state now expire, remain single-use, and cannot be
consumed from another browser session. Pending-login stores have explicit
capacity bounds and reclaim expired entries. - Cache invalidation, MCP subscriptions, room membership, and ORM dirty tracking
use indexed ownership instead of repeated full scans, while cleanup removes
stale subscriptions and descriptors deterministically.
Performance
- On the documented broad default-marker workload, the native test engine used
43.4% fewer retired userspace instructions than pytest and completed the same
work 1.820 times faster across three interleaved warm runs. - On the documented 60-control mutation corpus, native execution preserved all
60 killed verdicts while retiring 97.9% fewer userspace instructions than the
pytest path across seven interleaved runs. - Direct XML canonicalization output, startup-prepared Cedar route facts, and a
shared 1,000-route application image reduced their retained instruction
workloads by 41.89%, 15.95%, and 13.21%, respectively, with exact output
equivalence across seven interleaved runs per comparison.
Docs & internals
- Complexity discovery now fingerprints unchanged source, distinguishes real
nested linear work from set membership and iterator ownership, and reduces
the acknowledged static candidate set from 1,776 shapes to two. - Native operation-local kernels now serve test execution, mutation, duplicate
scanning, source linting, and documentation analysis without adding a
mandatory runtime dependency to the framework core.
v0.3.2
v0.3.2
Released 2026-08-20.
Wreath 0.3.2 adds durable organisation state and reusable application contracts,
ships Wreath's independent format-aware gzip implementation, and shortens the
native compressed-response path. Existing applications keep their current wire
formats and Python call sites unless a client explicitly advertises dcz; the
other new surfaces are opt-in additions.
Breaking changes
- A client that advertises equal-quality
dcz, gzip, zstdnow selects the
prepared-response ladder: exact DCZ first, then prepared-fragment gzip, then
format-aware gzip. To retain the previous zstd-on-tie result, give zstd a
strictly higher q-value or omitdcz.
Added
Contractandcompile_contractcompile a dataclass into a reusable,
transport-neutral validation and native JSON codec with an explicit input and
output size ceiling.ActionTokens,TokenPurpose, and theTokenLedgerprotocol provide bounded,
expiring, purpose-scoped action tokens with key rotation and explicit
single-use replay ownership.MemoryTokenLedgeris included for bounded
single-process use.wreath.emailis now the public import surface for Wreath's existing SMTP,
DKIM, suppression, unsubscribe, and transactional-versus-marketing mail
declarations.FilterField,FilterSet, andListingadd bounded, allow-listed ORM
filtering and reusable filtering/sorting declarations without interpreting
arbitrary lookup suffixes or relationship paths.MessageEnvelopeadds opt-in event identity, versioning, correlation,
causation, and trace context. Plain message payloads retain their existing wire
shape, andMessage.envelope()distinguishes the new envelope from legacy
payloads during rolling deployments.
Changed
- Gzip encode and decode now use Wreath's separate native kernels. The public
gzip encoders accept an optional format or HTTP content-type hint for JSON,
HTML, GraphQL, log-like, and plain-text policy while continuing to emit
standard RFC 1951/1952 streams. - DCZ still requires HTTPS and the client's exact
Available-Dictionaryhash;
a response is never dictionary-compressed merely because the coding was
advertised. All gzip fallbacks remain standard RFC 1952 streams.
Fixed
PostgresOrganizationStoremakes organisations, memberships, invitations,
and consumed invitation state durable across workers and API restarts.
Invitation acceptance consumes the token and writes membership atomically,
and the store contributes its three-table schema during application startup.- Outbound HTTP deadlines in the portable base wheel use CPython's
cross-platform monotonic clock. This removes the direct POSIX
clock_gettime(CLOCK_MONOTONIC, ...)call that prevented the 0.3.1 native
core from compiling with MSVC.
Performance
- On the retained holistic operations-dashboard instruction account,
format-aware Wreath gzip retires 4,690,494 userspace instructions per request.
The exact-dictionary DCZ path retires 2,426,742, 48.26% fewer than that full
Wreath request; the equivalent FastAPI stack retires 93.24 times as many. The
harness verifies decoded response and policy facts before retaining a sample. - A cache-policy sweep across 30 JSON, GraphQL, HTML, text, and log documents
reduced native gzip encode instructions by 4.79%, L1D misses by 12.87%, and
LLC misses by 52.07%. The shipped representative encoder retires 49.04
instructions per input byte with 91.62% L1D and 93.92% LLC hit rates. - Native protobuf, GraphQL parsing, observability, PostgreSQL, SQL, signature,
request, and response kernels received allocation, dispatch, and duplicate-work
cleanup while preserving their public Python APIs.
Docs & internals
- The documentation now has task-oriented capability, cookbook, reference, and
repository maps, plus dedicated reference pages for contracts, email, and
action tokens. - Reproducible instruction artifacts and counter harnesses now retain ranges,
alternating process slopes, A/A controls, decoded-output checks, and the exact
installed comparison stacks. No wall clock, cycles, or IPC enters the headline
compressed-request result.
v0.2.1
v0.2.1
Released 2026-08-13.
Wreath 0.2.1 is a backward-compatible performance release. No existing public
Python name is removed or renamed, and no existing call signature changes, so
applications written against 0.2.0 do not need a migration. The work is
primarily below the Python boundary: repeated collection, wire-format, policy,
and projection work now runs in operation-owned native kernels.
Added
wreath.series.ChartData, an immutable prepared numerical dataset that can
reuse dense cells, presence bits, selection plans, and path buffers across
several chart projections.wreath.temporal.spine_lengths(), which calculates several calendar
cardinalities over one range while sharing the time-zone conversion and
without materializing each spine.
These are opt-in additions. Existing one-shot series and temporal APIs remain
available with their existing signatures.
Changed
- Shared native data kernels now own bounded collection and wire-format walks
used by validation, codecs, recording and replay, logs and metrics,
negotiation, sync snapshots, pagination, temporal and series projection, and
Cedar evaluation. - Request headers stay in request-owned native storage through lookup and
policy evaluation, and are decoded only when the publicRequestAPI reads
them. - Successful Cedar route and batch decisions remain native; Python objects are
materialized for denials, and principal entities are skipped when the active
policy cannot read them. - PostgreSQL sparse-vector codecs and
SparseVectorshare operation-owned
native storage without introducing process-global mutable state. - Prometheus exposition, logging, Flight Recorder data, DNS, SigV4,
JSON/protobuf, ORM hydration, geospatial processing, and related policy paths
avoid repeated Python-side formatting and container walks.
Performance
Retired userspace instructions were measured over repeated, pinned,
process-tree workloads. The deep declarative dashboard fell from 7.923M to
4.137M instructions per request, a 47.79% reduction.
| Re-measured workload | Before | After | Reduction |
|---|---|---|---|
| Prometheus metrics | 649.1k | 322.6k | 50.30% |
| Sync snapshot | 511.3k | 462.9k | 9.47% |
| Enterprise Cedar route | 557.6k | 545.0k | 2.27% |
Across the re-measured metrics, sync, and enterprise-Cedar subset, retired
instructions fell by 6.21% in aggregate. The realistic request trace also
moved from 115 to 114 native calls and from 38 to 37 pre-activation native
calls, while retaining two Python frames.
Verification & internals
- The holistic benchmark now exercises successful declared series, tenancy and
organizations, generated admin, SCIM, sync, workflows, readiness,
Prometheus, OpenAPI, signed webhooks, and persistent WebSocket rooms. - The complexity catalog contains 118 controlled probes, each paired with a
same-size control and with no marked defects. - Focused coverage exercises prepared and one-shot chart projection, temporal
cardinalities, Cedar compilation and batching, request-header retention,
native framing and codecs, ORM storage, pagination, sparse vectors, logging,
Prometheus exposition, and bounded sync snapshots.
v0.2.0
v0.2.0
Released 2026-08-11.
Wreath's first compiled-authority release. The portable framework and server
core now have one implementation: the C code shipped in the wheel. Python is
the public facade where an API needs one, not a second runtime selected by a
request-time branch.
Installation is also explicit. uv add wreath installs the portable native
wheel for Linux, macOS, or Windows. Linux deployments can add the io_uring
reactor with uv add 'wreath[linux]'; HTTP/3 is selected with
uv add 'wreath[h3]' or its http3 alias.
Breaking
- A compiled wheel is required. A damaged installation missing
_core,
_client,_edge,_server, or_postgresnow fails at import and names
the missing component; there is no Python fallback or native/pure selector. wreath.orm.model.ListModelis removed. Generated native model storage is
the model storage implementation.- The remaining public and internal native/pure selection flags, fallback-only
branches, and parity terminology are removed.
Added
- Native wheels for CPython 3.14 on Linux x86-64 and ARM64, macOS Intel and
Apple silicon, and Windows x86-64. Every wheel is installed and serves a real
HTTP request on its native GitHub runner before a release can be created. wreath[linux], a Wreath-owned Linux companion wheel containing the io_uring
reactor and its pinned OpenSSL build; the portable base wheel remains free of
Linux-only code.wreath[h3]andwreath[http3], aliases for the HTTP/3 companion wheel. It
contains Wreath's QUIC extension and bundles pinned OpenSSL, ngtcp2, and
nghttp3 libraries with their license texts.- First-class policy compilation, second-factor authentication, OAuth, SSO,
tenancy and infrastructure controls, workflows, MCP, gRPC, generic protobuf,
temporal and geospatial types, and PostgreSQL extension types including
half-precision and sparse vectors. - Cross-module
wreath portanalysis for models, inheritance, sessions,
queries, migrations, routes, jobs, settings, and foreign API references,
with expanded Flask, Bottle, aiohttp, Pyramid, Tornado, Django,
FastAPI/Pydantic, ormar, and SQLModel recognition.
Changed
- Ed25519 and P-256 arithmetic, signing, DKIM canonicalization, HTTP
signatures, AES-GCM dispatch, and JOSE helpers use fixed-width in-tree C with
no mandatory third-party runtime dependency. - GraphQL parsing, staged projection, relationship layout, and direct result
JSON output are compiled operations. The HTTP path no longer materializes an
intermediate Python result tree. - Protobuf descriptors compile once and drive direct object encoding and
decoding. OTLP traces, metrics, and logs write protobuf directly from
projector state. - ORM model cells and bitmaps use generated C storage. Hydration, identity
deduplication, join assembly, and relationship attachment use
operation-local native state rather than Python working sets. - Flight projection, recording reads, Prometheus rendering, SCIM parsing, gRPC
unframing, multipart streaming, and SQL placeholder renumbering now own their
repeated work and private state in C. - Shared native writers and extension-local HTTP/header units keep the portable
extensions independent of Linux-only reactor code.
Fixed
- PostgreSQL decode and pipeline paths avoid repeated Python work and preserve
response keep-alive decisions through the HTTP client. - Required extensions refuse broken installations at import instead of
allowing a laterNonebranch to fail during a request. - Release publication cannot create a tag until the portable and companion
wheels build, install, import, and serve successfully.
Performance
Retired userspace instructions were measured on repeated pinned workloads, so
the results are not inferred from laptop wall-clock time.
| Workload | Before | After | Reduction |
|---|---|---|---|
| Flight mixed ingest, 192 cells | 14.33M | 0.215M | 98.5% |
| DKIM relaxed body, 276 KiB | 112.12M | 4.78M | 95.7% |
| gRPC unframe, 192 messages | 1.300M | 0.092M | 92.9% |
| OTLP metrics, 128 routes | 16.25M | 1.83M | 88.7% |
| WFR1 read, 4,096 cells | 9.99M | 1.46M | 85.4% |
| GraphQL cold parse, 240 fields | 5.433M | 1.859M | 65.8% |
| Generic protobuf decode, 48 records | 13.371M | 4.881M | 63.5% |
| ORM joined hydration | 3.162M | 1.422M | 55.0% |
| GraphQL projection and JSON | 3.026M | 1.629M | 46.2% |
| TechEmpower Fortunes request | 156.65k | 109.11k | 30.4% |
The already-small static request stayed near its floor, moving from 23.01k to
22.77k instructions. The complete request trace fell from 129 to 115 native
events while retaining two Python frames; all fourteen removed crossings were
handler-phase glue.
Docs & internals
- Complexity contracts cover 50 probes with same-size controls: 12 constant
and 38 linear, with no marked defects. - Native ownership, error-sentinel, GIL, build-freshness, map, and complexity
linters cover the compiled authority boundary. - The default source build remains dependency-free. The OpenSSL/ngtcp2/nghttp3
inputs exist only inside explicitly selected companion wheel builds, are
pinned, and carry their upstream license texts.
v0.1.0a3
v0.1.0a3
Released 2026-07-28.
The first release you can actually follow the quickstart with. v0.1.0a2 installed
cleanly and then failed on the next line: wreath run app:app could not import
app, and on the paths where it did start, the server printed nothing at all, so
a working boot was indistinguishable from a hang.
Added
wreath.server.run()takes areadycallback, invoked once with the running
Serverafter every listener is bound and lifespan startup has finished, and
before the first request is accepted. It fires after the bind so aport=0
listener already knows its port and a failed bind never announces itself; an
exception from the hook tears the server down rather than leaving a bound
listener behind something nobody saw fail.
Fixed
wreath run app:appnow importsapp.pyfrom the directory you are standing
in. A console script starts withsys.path[0]pointing at the virtualenv's
bin, not the working directory, so the command the README and the
getting-started guide both open with failed on a fresh install with
No module named 'app'.runnow prepends the working directory the way
python -mdoes, and leavessys.pathalone when a caller already arranged
for it.wreath devwas never affected — it re-executespython -m wreath,
and that inconsistency is what made this a defect inrun.wreath runprints a startup line. One line naming the version, the
target, the boundscheme://host:port, the protocols, whether requests are
served by the native extensions or the pure-Python reference, the loop, and the
worker count when there is more than one. The address comes from the bound
socket rather than the configuration, so--port 0reports the port the kernel
actually assigned; the tier is read from the same selector the server uses, so
a process that fell back to pure Python cannot claimnative. Under
--workers Nthe supervisor prints once, after every worker signals ready,
instead of N times.
Docs & internals
- The quickstart path is covered by a test that drives the installed console
script in a subprocess withPYTHONPATHscrubbed, and asserts on a served
response rather than a clean start. In-process tests andpython -m wreath
both pass with the fix reverted, which is why neither is used there.
v0.1.0a2
v0.1.0a2
Released 2026-07-28.
A packaging fix. v0.1.0a1 could not be installed by anyone — its source
distribution was missing three C headers, so compiling the native extensions
failed immediately. Nothing about the framework changed; this release is the
same code in a distribution that actually builds.
Fixed
- The sdist now carries every build input. Installing v0.1.0a1 failed with
fatal error: server_request_capi.h: No such file or directory. Without a
MANIFEST.in, setuptools shipped only the sources it could infer — each
extension'ssources=plus whatever itsdepends=happened to name — and that
inference was incomplete twice over:server_request_capi.hand
server_hpack_huffman.hwere listed in nodepends=at all, and the HTTP/3
sources belong to an extension that is only configured under
WREATH_BUILD_HTTP3=1, so a default build omitted them and the optional
extension could not be built from the published sdist either. - A stale
neo_asgi.egg-info/directory, carrying the project's former name, is
no longer shipped.
Docs & internals
- The release workflow validates and orders versions with PEP 440 rather than
a semver regex andsort -V. The regex rejected0.1.0a1outright as invalid,
andsort -Vordered0.1.0 < 0.1.0-alphawhere PyPI orders it the other way
— so the guard meant to prevent publishing the wrong thing disagreed with the
index it was guarding. - A release that fails partway can now be re-run. The tag it had already pushed
used to block its own retry; the guard now distinguishes a reused version
(refused) from an unfinished one (resumed), and prereleases are marked as such
on GitHub instead of taking the "Latest release" badge. - Per-version release notes are published to the documentation site. They were
linked from the index but excluded from the build, so the first release to
follow the documented process failed the docs gate on a dead link.
v0.1.0a1
v0.1.0a1
Released 2026-07-28.
The first public alpha. Wreath is a Python 3.14-first ASGI framework that ships
its own HTTP server, PostgreSQL driver, ORM, migration stack, and documentation
generator, with no mandatory runtime dependencies. It runs behind any conforming
ASGI server; the native pieces are optional accelerations of the same behaviour.
This is an alpha because the server has not yet finished fuzzing, sanitizer,
soak, and security review. The framework API is usable; treat the server tiers
as experimental and pin the version.
Added
- The framework. Routing, binding and validation, dependencies, the
middleware pipeline and its built-ins, OpenAPI and typed client generation —
no Pydantic, no SQLAlchemy, no third-party runtime dependency. - A native HTTP server speaking HTTP/1.1 and HTTP/2, with an optional HTTP/3
build. Available as a deployment tier, not a requirement. - The metal tier (
--loop metal): an io_uring event loop that owns listener
acceptance, receives, sends, signals, timers and generic readiness, with a
native hashed timing wheel in place of asyncio's timer heap. Multi-worker
through--workerson anSO_REUSEPORTlistener group. - PostgreSQL end to end — wreath's own driver, ORM, and a migration stack
generated from the live catalog rather than from authored migration files,
with schema-image diffing, drift detection, artifact verification, and
transactional application under an advisory lock. - Deferred migrations. A conversion is declared beside the model and guarded
by a predicate scan that refuses ordered comparison on a column mid-conversion.
Reverting a completed recode is refused rather than silently reported as done. - Partial indexes,
Index(where=...), round-tripping through the catalog
without spurious drift. - Durable jobs and messaging on PostgreSQL, including long mutations via
jobs.launch— the job id is the task id, seededqueuedso an immediate poll
is not a 404, and only the runner sets terminal state, because only it can tell
a retry from a dead-letter. - Authentication and a built-in Cedar authorizer, with no external
dependency and a pure-Python twin held to byte-for-byte parity. - Calculated views.
SeriesandAggregatedeclare chart data over one
model: bucketed in the reader's timezone, every bucket present, per-measure
fill, stable keys rather than ranks, and ceilings that refuse rather than
truncate. Sealing settles a bucket once late data can no longer change it. wreath.store,wreath.queries, andChunkedPass— one keyed-store
primitive replacing six hand-written ones, and a table walk by keyset ranges
with one transaction per chunk, paced so it does not starve request traffic.- GraphQL, cross-worker cache invalidation, and an N+1 detector behind
wreath doctor. wreath port— a FastAPI codemod that reads by static analysis only, never
importing the application, and reports what it cannot translate rather than
guessing.wreath audit— a zero-dependency WCAG 2.2 A/AA and performance ruleset
over generated HTML, extended to check a live service's own responses.wreath docs— the site generator, building from typed Python config with
no YAML and no third-party theme.
Performance
- Bitset routing is the default; HTTP/2 and HTTP/3 defer building a request
scope until a route is activated. - Every cache on the request path has a ceiling, and native routing memory is
released rather than retained for the process lifetime. - Two io_uring experiments were reverted after measurement — registered ring
descriptors and a transport ablation both failed to earn their keep. Nothing
ships here on the strength of a plausible mechanism alone.
Docs & internals
- Twenty-five architecture decision records, reconstructed from the code that
implements them, plus the delivery-plan archive. - A canonical example — a wildlife camera-trap network exercising every
shipped feature against a real PostgreSQL. Building it is what found most of
the defects closed before this release:validate_schema="error", the default,
had never once completed lifespan startup against a real database. - Complexity probes as a gate: a hot path whose measured complexity class
changes fails the build, so a regression is caught as a shape rather than as a
slow benchmark. - A replay engine proved against its own recordings — three container
formats treated as untrusted input, and fault schedules held to recovery
properties rather than to determinism alone. - The benchmark harness measures the server rather than itself: one load-generator
thread saturated below several of the arms it was measuring, so throughput is
now generated across cores and every arm is held to the same worker count.