v0.28.0
[0.28.0] — 2026-05-31
Sprint 28 — Early Alpha readiness. First release labelled
Early Alpha: the framework now has an externally-audited
readiness deliverable, a soak-tested leak-free posture, and an
EC2-reproducible benchmark cross-check against FastAPI. API may
still break between MINOR versions per ZeroVer; see
docs/ALPHA_READINESS.md for the evidence map
and KNOWN_LIMITATIONS.md for the
explicit "what's not promised yet" list.
Added
docs/ALPHA_READINESS.md— evidence-mapped readiness
checklist (9 categories, ~36 items) with classification, top-3
risks, top-5 missing validations. Linked fromREADME.mdEarly
Alpha banner.KNOWN_LIMITATIONS.md— single consolidated doc covering
RFC 8441 opt-in, HTTP/2 mux overhead, slowloris response shape,
single-host benchmark caveats, RFC-defensible diffs from nginx
in the differential corpus, no DB layer, no HTTP/3, no gRPC.bench/soak/— soak harness (1-hour wrk + tracemalloc +
/proc/<pid>/statussampling, mixed-lane lua script). Two
1-hour soaks (single-worker + 4-worker) across 19.5 M requests
confirmed RSS plateau, FD return-to-baseline, no growing
tracemalloc slab. Artefacts gitignored under
bench/results/soak/.bench/aws/httparena_compare.sh— EC2 c7i.xlarge HttpArena
comparison harness; provisions Docker + liburing 2.9 + gcannon
from source + wrk + h2load + h2spec + Autobahn runner; vendors
bench/httparena/as the framework; trap-EXIT teardown.- CLI
--versionflag — printsblackbull <version>and
exits 0. Reads fromimportlib.metadata.version('blackbull')
so it always agrees with the installed wheel. - HttpArena
/wsecho route +/baseline2(H/2 path) in
bench/httparena/app.py. Closes the WebSocket profile and the
H/2 baseline; previously only H/1.1 was implemented.
Changed
StaticFilesmiddleware now caches small files in memory.
mtime+size-keyed LRU cache (default ≤ 4 MiB per file, 256
entries); cache hits are twosend()calls with no thread-pool
dispatch. Replaces the per-requestasyncio.to_thread(...)
open/seek/read/close chain that exhausted the default
ThreadPoolExecutor (8 workers) at HttpArena's c=1024–6800 load
— first run plateaued at 71-79 r/s and subsequent runs collapsed
to 0 r/s as the dispatch queue saturated. Local back-to-back
c=1024 measurements after the fix: 17,885 / 18,345 / 18,149 r/s
with worker RSS flat at ~33 MB (was 275 → 768 MiB). Files
above the threshold keep the streaming path so per-request peak
memory stays at one chunk regardless of body size.- Default error handler is environment-aware.
_default_error_handler(registered on every HTTP error status
andException) now readsBLACKBULL_ENV:development— surfaces the full Python traceback inline so
users debugging locally see the failure point in the response
body.Accept: text/htmlreturns a styled HTML page;
everything else returns text/plain.production— terse: status code + phrase only. Exception
class and message no longer leak to the network.
SetsContent-TypeandContent-Lengthexplicitly on all
error responses (previously omitted).
bench/httparena/launcher.pynow spawns three workers —
HTTP cleartext on :8080, HTTPS+H1 on :8081, HTTPS+H2 on :8443.
Matches HttpArena'sscripts/validate.shport layout
(PORT=8080,H1TLS_PORT=8081,H2PORT=8443). Closes the 5
json-tlsvalidation failures the previous two-process layout
caused (nothing was bound on :8081). Shape mirrors the
HttpArenaframeworks/fastapi/launcher.pyreference — no
port-readiness gating, no TLS-handshake synchronisation.
Fixed
- Static-file middleware run-2/run-3 collapse to 0 r/s under
HttpArena's high-concurrency wrk passes. Root cause was
asyncio thread-pool exhaustion (see "Changed" above), not a
memory leak — RSS climbed because thousands of in-flight scope
dicts and file descriptors accumulated while waiting on the
shared executor. bench/peers/asgi_app.py+bench/app.py— replaced
status: 200 / 404integer literals withHTTPStatus.OK/
HTTPStatus.NOT_FOUND. Cosmetic; no runtime behaviour
change.
EC2 cross-check (Sprint 28 Task 3 + Task 4 carry-forward)
- HttpArena validate on
c7i.xlarge: 49/49 pass (previous
pass-count 44/5 fail before the launcher fix). Includes
baseline H/1.1, pipelined, limited-conn, json, json-comp,
json-tls, upload, static, baseline-h2, static-h2, echo-ws. - HttpArena benchmark numbers captured for BlackBull and FastAPI
across the validated profiles. Detailed results in the
Sprint 28 internal log; consolidated summary in
bench/CHARACTERIZATION.md ## Sprint history. - Static throughput on EC2 remained the dominant gap pre-cache;
the in-memory cache lands as a 0.28.0 source change but the
EC2 re-measure of static under the new code is a Sprint 29
open carry-forward (no new EC2 spend in Sprint 28).
Methodology
docs/ALPHA_READINESS.mdclassification flipped to
"READY FOR EARLY ALPHA" after Task 2 (soak) and Task 4
(release-shape + EC2 cross-check) closed. Both blocking risks
noted at audit time — no ≥1-hour soak, no externally
reproducible benchmark — are now closed.