# PLAN.md > Single source of truth for project status. Update at the start and end of > every work session. If this file is stale, nothing else in the repo can > be trusted to reflect reality. ## Current status - **Active phase:** 2.0.8 pre-release hardening — core ✅, AI/inference **unverified** (see honest phase table, 2026-08-06). Wheel built, demo_shop 29/29 passes, pytest 166/166 (+1 pre-existing flake), cargo workspace green on default features (gate fixed 2026-08-06). - **Status:** All post-2.0.7 gaps closed (2026-07-25). **AI / inference / LLM work FROZEN until release 2.0.8** (ADR-067). Focus from 2026-07-25 session: - **HTTP QUERY method (RFC 10008) — end-to-end verified + testable (2026-08-06).** The route chain (Python `app.query()` → native `query()` → Rust router keyed on `justapi_core::query_method()`) already existed; the gaps were test coverage and client plumbing. Added: core `TestClient::query`/`query_with`, PyO3 `JustAPITestClient.query`/`query_with`, `AsyncTestClient.query` (defaults to `Content-Type: application/json` per RFC 10008), plus 3 Python tests (roundtrip, wrong-route 405, missing-Content-Type 400) and 1 Rust test. RFC 10008 requires a Content-Type on QUERY; the handler already enforces it (400). - **Differentiator sprint — one-command agent demo (2026-08-06).** `examples/agent_demo/run_demo.sh` starts the app, exercises all three Rust-owned differentiators (native MCP tools with Rust-inferred schemas, durable sessions, Rust-validated NDJSON streaming), and stops — no manual steps. Verified end-to-end (tools list, `add(5,7)=12` call, 4-step stream, session persistence across requests). `app.py` now accepts a port arg. - **HTTP/3 (QUIC) transport — working module, feature-gated (2026-08-06, ADR-079).** New `http3` feature on `justapi-core` (`h3` + `h3-quinn` + `quinn`, hyperium stack on the existing tokio/rustls base). `crates/justapi-core/src/http3.rs`: `serve_http3()` binds UDP, runs a quinn endpoint + h3 server connection loop, bridges requests into `hyper::Request>` and runs a caller-provided handler; `chain_to_http3_handler()` adapts a `MiddlewareChain>`. End-to-end test (`tests/http3_test.rs`) does a real QUIC handshake with a self-signed cert (rcgen) and a round-trip through the h3-quinn client — **passes**. **Seam closed (ADR-082):** `app.enable_http3(cert, key)` now serves Python handlers over QUIC through the full native pipeline (GIL pool, DI, schema validation) — `make_native_handler` is body-generic, so `run()` builds a second `MiddlewareChain>` from the same app state and spawns `serve_http3` on the same port. Verified e2e: `{"handler":"python","route":"/native"}` over real QUIC. HTTP/3 is the one transport no Python framework ships. - **DB CRUD benchmark re-run on current code (2026-08-06).** Re-ran `benchmarks/run_crud_bench.sh` against HEAD with a release wheel. Findings appended to BENCHMARKS.md: JustAPI native SELECT **181k RPS (×125 vs FastAPI)** — headline claim holds/improves; UPDATE 31.9k / DELETE 37.7k still lead. **Honest regression surfaced:** the Python-handler path measures 16.5k SELECT (was 107k in the 2026-07-26 ledger) and concurrent writes collapse to ~6 RPS at `-c 20` (147 at `-c 1`) — this is the GIL-pool backpressure fix (throttle, not drop), a correctness/throughput tradeoff, not a durability bug. Native path unaffected. Also documented the methodology gotcha: benchmarking must use a release wheel (debug `maturin develop` is ~4× slower). - **Generator dependencies (FastAPI-style `yield` in Depends)** — ✅ complete. `_resolve_kwargs`/`_resolve_dependencies_list` detect `inspect.isasyncgenfunction`/`isgeneratorfunction`, advance generator once, register `gen.aclose()`/`gen.close()` in `request["_dep_cleanup"]`. Handler wrappers run cleanup in `finally` block (LIFO order). 6 tests (async gen, sync gen, cleanup on error, nested, cached, no-cache). - **ORJSON as optional Rust-level serializer** — ✅ complete. `orjson` feature in `justapi-core`/`justapi-py` hard-requires Python `orjson` module when enabled (panics with clear message if missing). `orjson>=3.10` added to pyproject.toml as `[orjson]` extra and included in `[full]`. 7 tests. - **Production panic hotspot audit** — ✅ complete. Fixed 6 categories of `unwrap()` panics on request hot path: CORS `Origin` parse (user-triggerable crash, highest risk), `Bound::new` construction, multipart form `set_item`, `conn_semaphore` acquire, `json_value_to_request` primitive conversions. - **GIL-pool concurrency bug (spurious 404s under load)** — ✅ fixed. `run_python` used `try_send` into a bounded channel (cap 16 for a single GIL worker); a burst of concurrent/pipelined requests overflowed the queue and `handle_request` masked the resulting chain `Err` as an RFC 9457 404 with no log. GIL pool now backpressures via `send().await` (throttles instead of dropping); `handle_request` logs chain errors and returns 500 (real not-found is already `Ok(404)`). Measured before: 4.1M/4.5M responses 404; after: 100% 200, ~110k rps. Regression test `test_sync_handler_no_spurious_404_under_load` (fails on old code). - **PyPI wheel** — built (`manylinux_2_34_x86_64`, 32 MB). Unpublished — blocked on `MATURIN_PYPI_TOKEN`. - **Demo_shop stress test (2026-07-18) — all D1–D4 defects fixed.** All 23 endpoints pass; 29-assertion e2e test passes. Framework gotchas documented in demo_shop/README.md (both resolved in framework). - **Gates (2026-08-06, re-run on current code):** `cargo test --workspace` ✅ green on **default features** (integration-test feature guards fixed — previously `db_bridge`/`edge_cases` failed without `--all-features`); `cargo clippy --workspace --all-features --lib -- -D warnings` ✅; `cargo fmt --check` ✅; pytest **169 passed / 1 skipped / 0 failed** (the long-standing `test_circuit_breaker` flake is FIXED — it was a real fork-safety bug in the GIL pool, ADR-081: a forked child inherited the parent's initialized pool whose worker threads don't exist → every Python request hung → 504s. Pool now tracks its PID and rebuilds after fork); demo_shop `test_app.py` 29/29 ✅. **Write-path defect found + fixed (ADR-080):** Python-handler writes no longer collapse under concurrency (160→3 RPS at c=11 was a pool double-acquire bug; now flat ~150 RPS c=1..50). - **Documentation site (2026-07-25):** docs_site rebuilt to FastAPI-level depth — 141 pages across 13 sections, Astro + Starlight build passes, full-text search with Pagefind. Sections: Getting Started (5), Tutorial (36), Advanced (27), How-To (7), API Reference (17), Deployment (9), Security (4), Observability (4), Inference (4), Reference (6), Resources (3), Contributing (5), Examples (1). - **Blocker:** none. Outstanding: PyPI publish (needs OIDC trusted publisher / `MATURIN_PYPI_TOKEN` at pypi.org) — the single most important remaining item; **AI/inference claims remain unverified on real hardware (Phase 52 frozen)**. ## Mission Build **JustAPI** — a production-grade Python web framework that beats FastAPI on every benchmark while matching or exceeding it on DX, security, and cloud-native readiness. ## Phase table > **Honest status key (2026-08-06):** > - **✅ verified** = passing tests on current code + benchmarked where applicable. > - **🟡 implemented / unverified** = code exists, unit/integration tests pass, but > the *real-world* claim is NOT proven: no real hardware/GPU/weights run, no > production deployment. Do NOT treat as production-ready. > - **🔴 frozen** = deliberately deferred. | # | Phase | Status | Notes | |---|---|---|---| | 0 | Foundations | ✅ verified | Skeleton, CI, skills, baselines | | 1 | Minimal Viable Runtime | ✅ verified | HTTP/1.1, routing, PyO3, CLI; 766k req/s | | 2 | Native Router | ✅ verified | matchit radix trie, route params, 51ns lookup | | 3 | Memory & Zero-Copy Pipeline | ✅ verified | arena+pool, 752k req/s | | 4 | Execution Model & GIL Strategy | ✅ verified | ADR-008: dedicated Python worker thread | | 5 | Middleware Engine + Auth | ✅ verified | CORS, SecurityHeaders, JWT, RateLimiter, 0.18% overhead | | 6 | Serialization | ✅ verified | serde_json (89ns), simd-json feature | | 7 | TLS + HTTP/2 | ✅ verified | rustls, ALPN, 10.7% overhead | | 8 | WebSocket + SSE | ✅ verified | tokio-tungstenite, SSE streaming | | 9 | Static Assets, Caching, Observability | ✅ verified | StaticDir, Prometheus, compression, OTel | | 10 | Native API | ✅ verified | Fully native pipeline — ASGI shim deprecated/removed (2026-08-06) | | 11 | Request Validation & Serialization | ✅ verified | JSON Schema validation, Pydantic bridge | | 12 | Database ORM Integration | ✅ verified | Pool, migrations, query builders, Python bridge. **2026-08-06: write-path saturation bug fixed (ADR-080)** | | 13 | Testing Utilities | ✅ verified | TestClient, async fixtures, snapshot testing | | 14 | Production Observability | ✅ verified | Metrics histograms, structured logging, health checks, alerting, audit, panic recovery | | **15** | **Graceful Degradation & Circuit Breakers** | **✅ verified** | **44 resilience tests, generic B support** | | 19 | Plugin System & Extensibility | ✅ verified | third-party plugin API | | 20 | Benchmark & Optimization (Beat FastAPI) | ✅ verified | ledger in BENCHMARKS.md (native SELECT ×125 vs FastAPI, 2026-08-06) | | 21 | Advanced DX: Signature Parsing & DI | ✅ verified | `Depends()`, auto-extract args | | 22 | True Async & Advanced Web Features | ✅ verified | No-block async, WS/SSE, BackgroundTasks | | 23 | Templating Engine Integration | ✅ verified | Jinja2/MiniJinja support | | 24 | gRPC & Protobuf Support | ✅ verified | Native gRPC via Tonic (compiles + tests; no prod deployment) | | 25 | Ultimate Scale (1M RPS tuning) | 🟡 implemented / unverified | Native fast path hits 430-724k on fixture; **1M RPS never measured — the phase title overclaims** | | 26 | Zero-Copy AI Data Boundary | 🟡 implemented / unverified | Arrow/DLPack via PyO3 buffer protocol; no real-model integration test | | 27 | Adaptive Batching Router | 🟡 implemented / unverified | `adaptive_batch` decorator exists; no real-model throughput proof | | 28 | WASM Middleware Engine | 🟡 implemented / unverified | wasmtime embedded; no real-world workload proof | | 29 | High-Throughput LLM Streaming (SSE 2.0) | ✅ verified | TokenStreamResponse, tests pass (framework-level) | | 30 | Layered Dependency Injection | ✅ verified | Litestar-style DI, tests | | 31 | Class-Based Controllers & Route Composition | ✅ verified | @controller classes, tests | | 32 | Native Enterprise Rate Limiting | ✅ verified | GCRA + Redis | | 33 | Circuit Breakers & Graceful Degradation | ✅ verified | 44 resilience tests | | 34 | Dynamic Configuration (Hot Reloading) | ✅ verified | file watcher + admin API | | 35 | GraphQL & Federation Gateway | 🟡 implemented / unverified | async-graphql wired; "Apollo Federation" never tested against a real gateway | | 36 | Agentic Workflow DAG Engine | 🟡 implemented / unverified | DAG orchestration in Rust, tests pass; no real agent workload proof | | 37 | OTel Distributed Tracing | ✅ verified | OTLP, contextvars, 225 tests | | 38 | Hardware-Accelerated JWT & Security | ✅ verified | RS256/ES256, CORS builder, IpRateLimiter | | 39 | SAST, Fuzzing & Memory Safety | ✅ verified | 6 fuzz targets, miri, SAFETY comments | | 40 | The JustAPI 2.0 Release | 🟡 in progress | **PyPI upload still blocked (no token)** — see Next actions. AI/inference phases 41-52 are 🟡/🔴 (no real GPU run, ADR-067): the release narrative is the **fastest, most complete web framework** (2.4x Granian hello-world, 5.4x JSON echo, native SSE/CRUD/DB-awaits, HTTP/3, free-threaded wheels) — NOT unproven LLM-serving claims. | | 41 | Native Inference Engine Foundation | 🟡 implemented / unverified | Candle CPU; `Engine`/`Model` traits, 24 tests. **No real-weights run (MockModel only)** | | 42 | KV-Cache Manager (PagedAttention, Rust) | 🟡 implemented / unverified | `KvBlockPool`, `PrefixCache`; unit tests only, no real model | | 43 | Continuous-Batching Scheduler | 🟡 implemented / unverified | `Scheduler` prefill/decode interleave; **CPU MockModel only, 0.4% of naive on instant-forward (scheduler sleep dominates)** | | 44 | OpenAI-Compatible API Server | 🟡 implemented / unverified | `/v1/*` wired to inference (GIL-free); exercised with MockModel only | | 45 | Quantization + Multi-LoRA | 🟡 implemented / unverified | AWQ/GPTQ/FP8 + LoRA registry, feature-gated `real`; **never run with real weights** | | 46 | LLM Control Plane | 🟡 implemented / unverified | model registry, KV-aware routing, autoscaling; plumbing only | | 47 | FastAPI Parity (model-deploy essentials) | ✅ verified | ApiKeyAuth + OAuth2Password + multipart + Form/Cookie/Header + JsonResponse (248 tests) | | 48 | Production Hardening for AI | 🟡 implemented / unverified | speculative decoding + disaggregated P/D + structural benchmarks; **structural = MockModel ratios, NOT real-GPU tokens/sec** | | 49 | Tree-based Speculative Decoding | 🟡 implemented / unverified | Medusa/EAGLE-style tree verification; acceptance-rate proof on MockModel only | | 50 | RadixAttention Prefix Caching | 🟡 implemented / unverified | `RadixPrefixCache` wired into Scheduler; unit-tested, no real model | | 51 | Scheduler Serving Integration | 🟡 implemented / unverified | `SchedulerEngine` bridges Engine+Scheduler; **CPU fixture with instant-forward MockModel** | | **52** | **GPU Benchmark Gate** | **🔴 frozen** | **The only honest status for "LLM performance": no CUDA driver, no real-weight run (ADR-067). The claim "beats vLLM" is UNTESTED.** | --- ## Phase 0 — Foundations (completed 2026-07-03) - [x] Repository skeleton (workspace Cargo.toml, 4 crates, python/ package) - [x] `PLAN.md`, `AGENTS.md`, `DECISIONS.md`, `BENCHMARKS.md` created - [x] Seed skills: `rust-ffi-safety`, `benchmark-harness` - [x] CI green on skeleton, baseline benchmarks recorded vs Uvicorn/FastAPI + Granian --- ## Phase 1 — Minimal Viable Runtime (completed 2026-07-03) - [x] tokio+hyper HTTP/1.1 server, PyO3 embedding, `/hello` + `/echo` routes - [x] `justapi serve` CLI, unit + integration tests, proptest fuzz corpus - [x] **Benchmark:** 766k req/s vs Granian 314k — 2.4x faster --- ## Phase 2 — Native Router (completed 2026-07-03) - [x] `matchit` radix trie, `Router` with route params + catch-all - [x] 9 router tests, 51ns avg lookup on 500-route table --- ## Phase 3 — Memory & Zero-Copy Pipeline (completed 2026-07-03) - [x] `RequestArena` bump allocator, `SharedArena`, `BufferPool` (4 buckets) - [x] 7 memory tests, 752k req/s (no regression) --- ## Phase 4 — Execution Model & GIL Strategy (completed 2026-07-03) - [x] ADR-008: dedicated Python worker thread (zero GIL contention) - [x] `py-nogil` feature flag for PEP 703 free-threaded CPython --- ## Phase 5 — Middleware Engine + Auth (completed 2026-07-03) - [x] `Middleware` trait, `MiddlewareChain`, Cors, SecurityHeaders, JwtAuth, RateLimiter - [x] 12 middleware tests, 0.18% overhead --- ## Phase 6 — Serialization (completed 2026-07-03) - [x] `serialize.rs` — `to_json_string`/`to_json_vec`, serde_json default, simd-json feature - [x] serde_json: 89ns/op, 11.2M ops/sec --- ## Phase 7 — TLS + HTTP/2 (completed 2026-07-03) - [x] rustls 0.23, ALPN h2+http/1.1, `Server::with_tls(TlsConfig)` - [x] TLS overhead: 10.7% (under 15% target) --- ## Phase 8 — WebSocket + SSE (completed 2026-07-03) - [x] tokio-tungstenite echo WS, SSE `/events`, TCP-peek WS upgrade - [x] 37 tests, clippy + fmt clean --- ## Phase 9 — Static Assets, Caching, Observability (completed 2026-07-05) - [x] Compression (Gzip/Deflate/Brotli/Zstd), StaticDir (ETag, 304, 206), Metrics (Prometheus), OTel tracing, health endpoints - [x] 82 tests (70 unit + 12 integration), 5 feature combos tested --- ## Phase 10 — ASGI Shim + Native API (completed 2026-07-05) > **Deprecation note (2026-08-06):** the Tier A ASGI shim was **removed**. JustAPI > is now a fully native runtime — routing, middleware, validation, and > serialization all run in Rust with no ASGI/Starlette dependency. Tier A below > is historical record only; the native API (Tier B) is the sole supported path. ### Tier A — ASGI Shim (historical) - [x] `Server::with_handler()`, `MiddlewareChain::set_handler()` - [x] ASGI worker thread with persistent asyncio event loop, `serve_with_app()` - [x] Lifespan protocol, streaming response via `ResponseEvent` bridge ### Tier B — Native API - [x] `JustAPIApp` pyclass: `Router`, `get`/`post`/`put`/`delete` registration - [x] Dedicated Python worker thread (ADR-008), `NativeJob` → `oneshot` dispatch - [x] `JustAPIApp.run(addr)`: `py.detach()` + tokio runtime - [x] Python helper: auto async detection, JSON-wrapping - [x] Graceful shutdown: `Server::with_shutdown(CancellationToken)`, Ctrl+C handler - [x] 5/5 Python integration tests passing ### Exit criteria - [x] 81 tests (70 unit + 11 integration), clippy + fmt clean - [x] Python end-to-end test: path params, POST echo, 404 routing --- ## Phase 11 — Request Validation & Serialization *(completed 2026-07-05)* **Goal:** Match FastAPI's Pydantic experience — type-safe request/response contracts with automatic validation, serialization, and error messages. **Actual implementation:** Rust-native JSON Schema validation via `jsonschema` crate (fast path, zero Python GIL), with Python `Schema` class and Pydantic bridge for schema definition. Error format RFC 9457. ### Deliverables - [x] **JSON Schema validation** — `validate_json_schema()` validates JSON bytes against JSON Schema entirely in Rust, zero GIL round-trips - [x] **Python `Schema` class** — `__init_subclass__` generates JSON Schema from type annotations (`str`, `int`, `float`, `bool`, `bytes`, `list[T]`, `dict[str, V]`, `Optional[X]`) - [x] **Pydantic bridge** — `pydantic_schema()` extracts `model_json_schema()` (v2) or `schema()` (v1); Rust-side `resolve_schema_json()` auto-detects type - [x] **Native API integration** — `post()`/`put()` accept `schema` parameter; validation runs in Rust **before** Python dispatch; 422 for invalid requests with zero Python context switch - [x] **`format` keyword enforced on the live HTTP path** — `justapi_core::validate` `build_validator` registers email/uri/uuid/date-time/date/hostname/ipv4 checkers + `should_validate_formats(true)`, so both one-shot and precompiled (`CompiledValidator`) validators assert `format`. Previously only the in-process `validate_value` path enforced `format`; the server path silently accepted violations. Regression test: `test_schema_hardened.py::test_server_path_enforces_format`. - [x] **Error format — RFC 9457** — structured `ValidationError` responses matching Problem Details for HTTP APIs ### Tests - [x] 4 Rust unit tests for `validate_json_schema` (valid, missing field, wrong type, invalid JSON body) - [x] 9 Python integration tests (Schema class valid/missing/wrong-type, Pydantic bridge, raw JSON Schema string, invalid JSON body) - [x] Backward-compatible: existing `body_schema` Python-callable path preserved ### Exit criteria - [x] 97 tests (86 unit + 11 integration), clippy + fmt clean - [x] JSON Schema validation in Rust with zero Python GIL round-trips --- ## Phase 12 — Database ORM Integration *(completed 2026-07-05)* **Goal:** Built-in async database integration — SQL migrations, connection pooling, query building — without the cognitive load of SQLAlchemy. ### Deliverables - [x] **Connection pool manager** — `AnyPool` enum (Pg/Sqlite/MySql), `DatabaseConfig`, `PoolManager` with `init()`/`get()`/`default()`/`health_check_all()`, `DbKind::from_url()` auto-detection; 2 unit tests - [x] **Migration system** — `Migration` struct with `parse_filename()`/`parse_content()`/`from_file()`, `Migrator` with `discover()`/`run()`/`rollback_one()`/`ensure_tracking_table()`/`get_applied_versions()`/`record_migration()`; `_justapi_migrations` tracking table with per-DB SQL; 5 unit tests - [x] **Query builder** — `Select`/`Insert`/`Update`/`Delete` builders with `build()` methods; `Select::build_count()`; 9 unit tests - [x] **Model trait** — `Model` trait with `table_name()`/`pk_column()`/`count()` defaults; 16 total db unit tests - [x] **Python `Database` class** — stores URL/max_connections, `set_database()` on `JustAPIApp` accepts Database or URL string - [x] **Pool initialization in `run()`** — pool auto-initialized inside tokio runtime before server start - [x] **CLI migration commands** — `justapi db migrate`, `justapi db rollback`, `justapi db init` - [x] **Transaction middleware** — auto-begin for POST/PUT/DELETE, commit on 2xx, rollback on error; `db_url` passed to Python handlers via request dict ### Design decisions - `sqlx` v0.8 with `runtime-tokio` + `postgres` + `sqlite` + `mysql` + `migrate` features - `AnyPool` enum over trait objects — match dispatch avoids dynamic dispatch overhead - Feature-gated behind `db` flag in `justapi-core` - Migrations as plain SQL in `migrations/` directory (no DSL lock-in) ### Exit criteria - [x] Full CRUD app running with PostgreSQL. Migrations up/down working. `justapi db` CLI subcommands functional. 30+ tests. --- ## Phase 13 — Testing Utilities *(completed 2026-07-05)* **Goal:** Developer experience parity with FastAPI's `TestClient` — write tests the same way, but they run faster. ### Deliverables - [x] **`TestClient`:** Rust test client using tokio duplex + hyper HTTP/1.1 parser (no TCP socket, sub-ms test latency), `TestResponse` with status/headers/body - [x] **JustAPITestClient pyclass:** wraps Rust `TestClient` — GIL-free, no dedicated worker thread, `OnceLock` for helper module caching - [x] **AsyncTestClient:** async context manager wrapping `JustAPITestClient` with `async get/post/put/delete` methods, sync/async setup/teardown hooks - [x] **Assertion helpers:** `assert_ok`, `assert_status`, `assert_json`, `assert_header` — composable response assertions - [x] **Database test helpers:** `ManagedDb` async context manager, `test_db()` factory, `db_client()` helper with seed SQL, `transaction_test_db()` for transactional rollback - [x] **Snapshot testing:** `Snapshot` class with `assert_match`/`assert_response`/`assert_body`, `.snap` files in `__snapshots__/`, `SNAPSHOT_UPDATE=1` for auto-accept, unified diff on mismatch - [x] **Transaction middleware in test client:** auto-begin for POST/PUT/DELETE, commit on 2xx, rollback on error - [x] **Coverage:** 43 Python integration tests, 114 Rust tests, clippy + fmt clean ### Design decisions - Test client calls handler directly (no TCP stack) for sub-millisecond test latency — tokio duplex + hyper HTTP/1.1 parser - Full middleware chain runs — same behavior as production - Python `JustAPITestClient` wraps Rust test client via PyO3 — no worker thread, GIL acquired via `Python::try_attach` - Snapshot testing custom implementation (not `insta`) — tighter Python integration, caller detection via stack frame walk ### Exit criteria - [x] Test client usable from both Rust and Python. 43 integration tests for test utilities. Benchmark shows 5x+ vs FastAPI TestClient. --- ## Phase 14 — Production Observability *(completed 2026-07-05)* **Goal:** Production-grade observability — structured logging, enhanced metrics, health checks, alerting, audit logging, panic recovery — with observability overhead < 5% p99 latency. ### Deliverables - [x] **Enhanced Metrics:** Bucket-based latency histograms (Prometheus-compatible: 1ms–10s, 13 buckets), status-code tracking (2xx/3xx/4xx/5xx), `record_status()`, `record_latency()`, `percentiles()` (p50/p95/p99/p999), `snapshot()`, `RequestTimer`. Backward-compatible with existing `Metrics` API. - [x] **Structured Logging:** `LoggingConfig` with `LogFormat::Text`/`Json`, `FileRotation::Daily`/`Hourly`/`Never`, configurable log level via env-filter. `init_logging()`, `init_json_logging()`, `init_file_logging()`. Uses `tracing-subscriber` json feature + `tracing-appender` for rolling file output. - [x] **Health Check System:** `HealthCheck` trait, `HealthRegistry` with `register()`/`register_fn()`/`check_all()`/`health_response()`. `HealthStatus::Healthy`/`Degraded`/`Unhealthy`. Returns 200 (all healthy) or 503 (any unhealthy). `DbHealthCheck` (feature-gated on `db`). Per-component JSON output. - [x] **Alerting:** `AlertingConfig` with webhook URL, severity filter, channel type (Slack/PagerDuty/Generic). Payload builders for Slack attachments, PagerDuty Events API v2, and generic JSON. HTTP-only POST dispatcher via `tokio::net::TcpStream`. Severity filtering (Info/Warning/Critical). Logs locally when webhook not configured. - [x] **Audit Logging:** `AuditLogging` middleware with `AuditRule` (filter by method + path prefix). `wrap_handler()` returns wrapped `HandlerFn` emitting `tracing::info!` with `audit=true`, method, path, status, duration_us. Default rule captures POST/PUT/DELETE/PATCH on all paths. - [x] **Panic Recovery:** `with_panic_recovery()` wraps `HandlerFn` with `std::panic::catch_unwind` + `FutureExt::catch_unwind`. Custom panic hook logs panic message + location via `tracing::error!(panic=true)`. Returns 500 JSON response on panic; converts `anyhow::Error` to 500. - [x] **Server wiring:** Both HTTP and TLS service functions call `metrics.record_status(status)` and `metrics.record_latency(ms)` on every request. - [x] 121 Rust unit tests, 43 Python integration tests, clippy + fmt clean. ### Design decisions - `tracing` as the foundation — structured, async-aware, ecosystem compatible. JSON output via `tracing-subscriber` json feature, file rotation via `tracing-appender`. - Bucket-based latency histograms over HDR Histogram — avoids new crate dependency, 13 Prometheus-compatible buckets with `AtomicU64`, zero-allocation record path. Percentiles computed from bucket distribution. - Health checks as a composable system — `HealthRegistry` aggregates per-component checks, `health_response()` generates HTTP response. Backward-compatible with existing static `/health` endpoint. - HTTP-only webhook dispatcher over `tokio::net::TcpStream` — avoids `reqwest` dependency. HTTPS not supported; users can proxy through local HTTP gateway. - `std::panic::catch_unwind` over tokio task abort for panic recovery — wraps `BoxFuture` directly via `FutureExt::catch_unwind`, avoiding tokio task lifecycle complexity. - Audit logging as a `HandlerFn` wrapper (not Middleware trait) — designed to be the last wrapper before the middleware chain, ensuring it captures final status after all middleware processes the request. ### Exit criteria - [x] Full observability stack: enhanced metrics, structured logging, health checks, alerting, audit logging, panic recovery. 121 Rust tests, 43 Python integration tests. Overhead < 5%. --- ## Phase 15 — Graceful Degradation & Circuit Breakers *(completed 2026-07-05)* **Goal:** Resilience patterns — when dependencies fail, JustAPI degrades gracefully instead of crashing. ### Deliverables - [x] **Circuit breaker middleware:** wraps external calls with configurable thresholds, `Closed`/`Open`/`HalfOpen` state machine, `try_acquire()`/`record_success()`/`record_failure()`, returns 503 with `Retry-After` when open - [x] **Bulkhead pattern:** `tokio::sync::Semaphore`-based concurrent request limiter, configurable `max_concurrent` + `max_wait`, returns 503 when limit exceeded - [x] **Retry with backoff:** `RetryPolicy` utility struct with exponential backoff, configurable `max_retries`/`base_delay`/`max_delay`/`jitter`, `retryable()` for idempotent operations. **Not middleware** (blocked by `Incoming` body consumption) - [x] **Timeout middleware:** per-route request timeouts via `tokio::time::timeout`, returns 504 `GATEWAY_TIMEOUT` with descriptive JSON - [x] **Rate-limit backpressure:** `RateLimiter` (Phase 5) improved with governor `DefaultClock::now()` for correct `Retry-After` header computation - [x] **Graceful degradation strategies:** `FallbackPolicy` with path-prefix matching + default fallback, `FallbackMiddleware` returns cached response on 5xx or handler error - [x] **Startup dependency check:** `HealthRegistry` passed to `Server`, `/ready` endpoint checks registered health probes (falls back to simple `{"ready":true}` when no checks registered) - [x] **Chaos testing harness:** `ChaosMiddleware` with configurable latency injection, error injection, and enable/disable toggle - [x] **Generic body type support:** all resilience middleware now `impl Middleware` (not tied to `Incoming`), enabling direct unit testing with `Full` body. `MiddlewareChain` implements `Clone` for test ergonomics ### Design decisions - Circuit breaker is custom (3 states, `Arc>`, 24 lines) — no new dependency (`failsafe` avoided) - Bulkhead via `tokio::sync::Semaphore` — already in dependency tree - RetryPolicy as utility (not middleware) — `Incoming` body can't be cloned/replayed - Resilience middleware generic over `B` — enables `TestBody` in unit tests without duplicate `impl Middleware` blocks - `/ready` uses `HealthRegistry` only when checks are registered — backward-compatible with existing deployment expectations - ChaosMiddleware gated by `ChaosConfig::enabled` flag — zero overhead when disabled ### Exit criteria - [x] Circuit breaker opens on failures, recovers to half-open, reopens on half-open failure - [x] Timeout middleware returns 504 on deadline, passes fast requests - [x] Bulkhead limits concurrent requests, returns 503 when full - [x] Fallback returns cached response on 5xx and handler errors - [x] Chaos middleware injects configurable latency spikes and error responses - [x] Startup dependency check integrated with Server + HealthRegistry - [x] 44 resilience unit tests (41 middleware tests + 3 config default tests) - [x] All 167 workspace tests pass - [x] `cargo clippy --workspace -- -D warnings` and `cargo fmt --check` clean --- ## Phase 16 — Multi-Cloud / Kubernetes Support *(completed 2026-07-05)* **Goal:** Deploy JustAPI apps to any cloud — GKE, EKS, AKS, DigitalOcean, Railway, Fly.io — with first-class Kubernetes support. ### Deliverables - [x] **Dockerfile:** multi-stage build (rust:slim → python:slim), `< 200MB` (PyO3 embeds Python), `HEALTHCHECK` configured, stripped binary, non-root user - [x] **Docker Compose:** `docker-compose.yml` with services: `justapi` (build), `db` (postgres:16-alpine), `redis` (7-alpine), `jaeger` (all-in-one). Health checks, volumes, env vars - [x] **Helm chart:** full chart at `helm/justapi/` — `Chart.yaml`, `values.yaml`, `templates/` (deployment, service, ingress, hpa, configmap, secret, serviceaccount, helpers) - [x] **Health check probes:** K8s `livenessProbe` (`/live`), `readinessProbe` (`/ready`), `startupProbe` (`/live`) — configurable thresholds and delays - [x] **Graceful shutdown:** already implemented (SIGTERM → drain connections → stop) - [x] **Horizontal Pod Autoscaler:** HPA template with CPU (70%) and memory (80%) utilization targets, configurable min/max replicas - [x] **K8s ingress config:** NGINX Ingress template with TLS (cert-manager + Let's Encrypt), `ssl-redirect` annotation - [x] **Environment-based config:** `.env.example` with all config vars, ConfigMap + Secret K8s templates, env var injection in deployment - [x] **CI/CD pipeline:** GitHub Actions `docker` job — Buildx + GHCR push, multi-tag (branch, semver, SHA), GHA cache layer. Runs on main push and `v*` tags - [x] **Cloud-specific examples:** deploy guides for GKE, EKS, AKS, Fly.io, Railway in `deploy/clouds/` - [x] **Benchmark:** K8s overhead vs bare metal documented in `BENCHMARKS.md` (8.4% throughput overhead) ### Design decisions - `python:3.12-slim-bookworm` as runtime base (PyO3 embeds CPython — can't use distroless) - Two-stage build: Rust builder stage → Python runtime stage (keeps final image under 200MB) - Helm as primary deployment mechanism — NGINX ingress with cert-manager for TLS - Config via environment variables with env var injection from ConfigMap + Secrets - Health probes use existing `/live`, `/ready`, `/health` endpoints (already implemented) - GitHub Actions `docker/build-push-action` with Buildx + GHCR + GHA cache layer ### Exit criteria - [x] Dockerfile builds and produces a functional image - [x] Docker Compose starts all services (justapi, postgres, redis, jaeger) - [x] Helm chart installable with `helm install justapi helm/justapi` - [x] CI pipeline builds and pushes Docker image on main/tag pushes - [x] Cloud-specific deployment guides for GKE, EKS, AKS, Fly.io, Railway - [x] Benchmark: K8s overhead vs bare metal documented --- ## Phase 17 — Zero-Day / SAST / Security Hardening *(completed 2026-07-05)* **Goal:** Security-first by default — SAST scanning, dependency auditing, fuzz testing, and proactive vulnerability management. ### Deliverables - [x] **SAST (Static Application Security Testing):** `cargo-audit` + `cargo-deny` jobs in CI (blocking gate), `.github/dependabot.yml` for weekly dependency updates - [x] **Fuzz targets:** 5 `cargo-fuzz` targets in `fuzz/` — `fuzz_jwt` (malformed tokens, algorithm confusion), `fuzz_headers` (header name/value parsing, URI, method), `fuzz_query_params` (url-encoded query strings), `fuzz_body` (JSON + JSON Schema validation, deeply nested payloads), `fuzz_file_paths` (path traversal, percent-decoding, MIME guessing), `fuzz_router` (matchit path matching with edge-case paths) - [x] **Dependency vulnerability scanning:** `cargo audit` job in CI (blocks on advisories), Dependabot for weekly cargo + GHA updates - [x] **Supply chain security:** `deny.toml` configured with allowed license list (MIT/Apache/BSD/ISC/Zlib/Unicode-DFS/CC0-1.0/OpenSSL), vulnerability denial, multiple-versions warn, unknown-registry deny - [x] **Security middleware audit:** `SecurityHeaders` enhanced with builder pattern (`with_hsts_preload()`, `with_csp_directive()`, `without_xfo()`, `without_csp()`), CSP nonce-compatible directive model, configurable HSTS preload, configurable X-Frame-Options and CSP on/off - [x] **Rate limiting enhancement:** `IpRateLimiter` — per-IP rate limiter using governor's keyed rate limiter with `HashMapStateStore`, extracts client IP from `req.extensions().get::()`; `per_second()` convenience constructor - [x] **Input sanitization:** SQL injection prevention via parameterized queries in `sqlx` (Phase 12), XSS prevention via `X-XSS-Protection: 0` + CSP, MIME sniffing prevention via `X-Content-Type-Options: nosniff` - [x] **Secrets management:** `secrets.rs` module — `Secret` (Env/File/Inline sources), `SecretsRegistry` with `register()`/`resolve()`/`resolve_all()`, no-logging of resolved values, lazy resolution (not at startup), eager validation via `resolve_all()` - [x] **HTTP security hardening:** HSTS preload flag, CSP directive builder (nonce-compatible `CSP` serves multiple directives separated by `; `), X-Frame-Options: DENY, X-Content-Type-Options: nosniff - [x] **Security documentation:** `.well-known/security.txt` (canonical security policy endpoint), `SECURITY.md` (root-level pointer), `docs/security/policy.md` (full disclosure policy with response timeline, scope, hall of fame), `docs/security/owasp-checklist.md` (OWASP Top 10 2021 — 27/35 controls checked, 8 planned) - [x] **Penetration test guidelines:** `docs/security/pentest-guide.md` — attack surface map, 9 test scenario categories (auth, input validation, session mgmt, rate limiting, TLS, info disclosure, security headers, fuzzing, supply chain), tool reference (cargo-fuzz, cargo-audit, cargo-deny, curl, oha, nmap, testssl.sh, jwt_tool, sqlmap, nikto), CVSS 3.1 report template ### Design decisions - SAST in CI as gating check (not optional) — `cargo-audit` and `cargo-deny` are blocking jobs - Fuzz targets use `cargo-fuzz` / `libfuzzer` for Rust paths (5 targets covering JWT, headers, query params, body/JSON Schema, file paths, router) - JWT parsing fuzzed with edge cases (malformed, algorithm confusion, arbitrary key bytes) - Secrets management uses synchronous reads (no tokio dependency for file I/O) — `std::fs::read_to_string` with `trim()` for trailing newlines - OWASP Top 10 2021 as the security requirements baseline; checklist tracks implemented vs. planned controls - `secrets.rs` uses `Arc>` for concurrent access — not performance-critical (resolved at startup or on config reload) ### Exit criteria - [x] `cargo-audit` job added to CI (blocks on vulnerabilities) - [x] `cargo-deny` job added to CI (blocks on license/advisory violations) - [x] 5 fuzz targets created (JWT, headers, query params, body, file paths, router) - [x] Security documentation complete (security.txt, policy, OWASP checklist, pentest guide) - [x] Per-IP rate limiter implemented (`IpRateLimiter`) - [x] SecurityHeaders enhanced with builder pattern (CSP nonce support, HSTS preload) - [x] 7 secrets module tests passing - [x] 175 total workspace tests passing (158 unit + 11 integration + 6 secrets) - [x] `cargo clippy --workspace -- -D warnings` and `cargo fmt --check` clean --- ## Phase 18 — DX Tooling **Goal:** Developer experience that rivals or exceeds FastAPI — automatic OpenAPI docs, hot reload, CLI productivity. ### Deliverables - [x] **OpenAPI generation:** auto-generate OpenAPI 3.1 spec from route handler signatures (types, docstrings, validation schemas) — `openapi.rs` with full spec types, builder, registry - [x] **Swagger UI + ReDoc:** serve interactive API docs at `/docs` and `/redoc` — registered in `Server::new()` and `serve()` - [x] **Hot reload:** file watcher + graceful restart on code changes (via `notify` crate + `JustAPIApp.reload()`) - [x] **`justapi routes`:** CLI command to list registered routes with methods and paths — reads OpenAPI spec via `--spec-file` or lists built-in routes - [x] **`justapi doctor`:** diagnostic command checking environment, dependencies, config validity - [x] **`justapi profile`:** performance profiling command with flamegraph generation - [x] **`justapi new`:** project scaffolding — `justapi new myapp` creates a complete project structure - [x] **`justapi check`:** type-check and validate all routes without running server - [x] **`justapi gen openapi`:** generate and save OpenAPI spec to file via `OpenApiBuilder` - [x] **`justapi gen client`:** generate a typed Python or TypeScript client from any OpenAPI 3.1 spec (`justapi gen client -s spec.json -o out/ [--language python|typescript]`). Parses `OpenApiDocument` (now `Deserialize`), emits a `requests`-based Python `Client` and a `fetch`-based TS `Client` with one method per path+verb. Path/query/header params are typed from the spec, header/param names are sanitized to valid identifiers while preserving original wire names, and path templating uses the spec's `{param}` placeholders. Verified end-to-end against a mock server; unit tests in `gen_client.rs`. - [x] **Error messages:** rich, colored error output with suggestions (like Rust compiler or Elm) - [x] **Benchmark:** time from `justapi new` → `curl localhost:8080` < 5 seconds ### Design decisions - OpenAPI spec generated from TypeScript-style type system on Rust types - Hot reload via `notify` + SIGTERM to existing process + delayed restart - CLI built with `clap` (already in workspace) — subcommands with completions - Project scaffolding via built-in templates (not external cookiecutter) ### Exit criteria Full OpenAPI 3.1 generation working end-to-end. Swagger UI at `/docs`. Hot reload working for Python file changes. `justapi new`, `justapi routes`, `justapi doctor` functional. 40+ tests. --- ## Phase 19 — Plugin System & Extensibility *(completed 2026-07-05)* **Goal:** Third-party plugin ecosystem — anyone can extend JustAPI with custom middleware, serializers, database backends, and deployment targets. ### Deliverables - [x] **Plugin trait:** `Plugin` trait with `build()` lifecycle hook for modifying the server pipeline - [x] **Plugin registry:** compile-time plugin registration via `inventory` crate or link-time - [x] **Python plugin API:** Python-declared plugins that register middleware, routes, or startup/shutdown hooks - [x] **Plugin configuration:** typed config per plugin, merged into app config - [x] **Plugin marketplace documentation:** documented process for publishing plugins - [x] **Example plugins:** caching (Redis), auth (OAuth2), rate limiting (advanced), compression (custom) - [x] **Plugin isolation:** plugin failures don't crash the server (panic boundaries) - [x] **Benchmark:** plugin overhead < 1% with no active plugins ### Design decisions - Plugin trait with hook points: `pre_route`, `post_route`, `on_startup`, `on_shutdown` - Python plugins via `JustAPIApp.use(plugin)` method - Plugins run in the Rust middleware chain for performance - Plugin config as serde-deserializable structs ### Exit criteria - [x] 3 example plugins working. Plugin overhead benchmarked. Plugin documentation published. 30+ tests. --- ## Phase 20 — Benchmark & Optimization (Beat FastAPI) *(completed 2026-07-05)* **Goal:** Prove JustAPI beats FastAPI on every measurable dimension — throughput, latency, memory, startup time, test speed, and deployment size. ### Deliverables - [x] **Comprehensive benchmark suite:** automated benchmarking against FastAPI + Uvicorn, FastAPI + Granian, and Starlette on: - Hello world throughput (req/s) - JSON echo throughput with varying payload sizes - Route lookup latency (100, 500, 1000 routes) - Middleware chain overhead - Memory usage under load - Startup time (cold + warm) - Test suite execution time (JustAPITestClient vs TestClient) - Docker image size - Tail latency (p99, p999 under load) - [x] **Profile-guided optimizations:** use `perf` + `flamegraph` to identify bottlenecks - [x] **Custom allocator evaluation:** `mimalloc` vs `jemalloc` vs default allocator - [x] **Zero-copy request path audit:** identify remaining copies in the pipeline - [x] **Tokio tuning:** thread count, event loop strategy, IO vs CPU balance - [x] **Serialization optimization:** evaluate `rkyv` / `flatbuffers` for internal serialization - [x] **Connection pooling optimization:** benchmark keep-alive vs per-request connection - [x] **Static file throughput:** optimize `sendfile` / `splice` usage - [x] **Benchmark documentation:** repeatable, hardware-documented, time-series results in BENCHMARKS.md - [x] **Targets:** - Throughput: 2x FastAPI on hello-world, 3x on JSON echo - Latency p99: < 0.5ms on hello-world (FastAPI ~2ms) - Memory: 2x more requests per MB than FastAPI - Startup: < 10ms cold start (FastAPI ~300ms) - Docker image: < 50MB (FastAPI ~200MB with Python) - Test speed: 5x faster than FastAPI TestClient ### Design decisions - All benchmarks run on the same hardware fixture (documented in BENCHMARKS.md) - Benchmark harness in `justapi-bench` crate (already exists) - `oha` for load generation (already baseline tooling) - Results versioned and appended — never overwritten - Re-architected native integration using `tokio::task::spawn_blocking` and PyO3 0.29 `Python::attach()` to ensure worker threads do not starve while waiting for Python execution. - [x] **Beat FastAPI on every benchmark.** If any benchmark shows FastAPI faster, that's a blocking bug that must be fixed before Phase 20 is complete. All results published in BENCHMARKS.md with hardware fixture, tool versions, and raw data. --- ## Phase 21 — Advanced DX: Signature Parsing & DI **Goal:** Provide the exact same developer experience as FastAPI with automatic signature parsing and Dependency Injection (`Depends()`). ### Deliverables - [x] Auto-extract `path_params`, `query_params`, headers, and request body directly into function arguments based on type hints. - [x] Implement `Depends()` for Dependency Injection (supporting both sync and async dependencies). - [x] Support complex return types (Pydantic models, custom Schema objects) natively serialized by the framework. --- ## Phase 22 — True Async & Advanced Web Features **Goal:** Achieve true non-blocking async execution in Tier B and expose advanced web features (WebSockets, SSE, BackgroundTasks). ### Deliverables - [x] Evaluated PyO3 native futures: decided to retain `tokio::task::spawn_blocking` combined with `loop.run_until_complete()` as it maximizes Tokio scalability while easily bypassing the GIL for asyncio execution. - [x] Implement `@app.websocket()` and `@app.sse()` decorators in the Python API. - [x] Implement `BackgroundTasks` for deferred execution after response. - [x] Python-level custom exception handlers and middleware. - [x] Implement `@app.websocket()` and `@app.sse()` decorators in the Python API. --- ## Phase 23 — Templating Engine Integration *(completed 2026-07-05)* **Goal:** Built-in template rendering. ### Deliverables - [x] Integration with a fast templating engine (`Jinja2Templates` integration). - [x] `TemplateResponse` helper for returning rendered HTML. --- ## Phase 24 — gRPC & Protobuf Support *(completed 2026-07-05)* **Goal:** Expose high-performance gRPC endpoints natively in JustAPI. ### Deliverables - [x] Rust-backed gRPC server (using `tonic`) running alongside the HTTP server. - [x] Python decorators for defining gRPC services seamlessly. - [x] Auto-generate Python stubs/types from protobuf schemas. --- ## Phase 25 — Ultimate Scale (1M RPS Tuning) *(completed 2026-07-05)* **Goal:** Hyper-optimize the framework to handle 1 Million RPS on modest hardware. ### Deliverables - [x] Extreme tuning of Tokio event loop, `io_uring` adoption (if beneficial). - [x] Lock-free data structures across the board. - [x] Network offloading and bypassing Python overhead for static/cached responses. - [x] Native async bridging using `.call_method0("result")` and concurrency scaling (tested seamlessly up to 1000 concurrent Python futures). --- ## Summary: JustAPI vs FastAPI feature matrix | Feature | FastAPI | JustAPI (target) | |---|---|---| | Routing | ✅ Starlette | ✅ matchit (51ns lookup) | | Request validation | ✅ Pydantic | ✅ Phase 11 (Rust-native, 10x faster) | | OpenAPI docs | ✅ auto | ✅ Phase 18 (auto-generate) | | Async support | ✅ asyncio | ✅ tokio + Rust async | | WebSocket | ✅ | ✅ Phase 8 | | SSE | ✅ | ✅ Phase 8 | | Background tasks | ✅ | ⬜ Phase 15 | | Dependency injection | ✅ | ⬜ Phase 11 | | Database ORM | ❌ (third-party) | ✅ Phase 12 (built-in) | | Testing utilities | ✅ TestClient | ✅ Phase 13 (5x faster) | | TLS | ✅ (uvicorn) | ✅ Phase 7 (rustls) | | Kubernetes support | ❌ (third-party) | ✅ Phase 16 (Helm + docs) | | Hot reload | ✅ (uvicorn) | ✅ Phase 18 | | Metrics | ❌ (third-party) | ✅ Phase 14 (built-in Prometheus) | | Distributed tracing | ❌ (third-party) | ✅ Phase 14 (OTel) | | Circuit breakers | ❌ | ✅ Phase 15 | | Security scanning | ❌ | ✅ Phase 17 (SAST + fuzzing) | | Plugin system | ❌ | ✅ Phase 19 | | Performance | baseline | **target: 2-5x faster on every benchmark** | --- ## Decision log pointer See `DECISIONS.md` for the reasoning behind any deviation from plan. Don't duplicate that reasoning here — just reference the entry. ## Next actions 0. **[DONE — 2026-08-07] Honesty cleanup (item #5):** AI phases 41-52 remain 🟡/🔴 (no real GPU). The release narrative is the web-framework story (benchmarked); LLM claims stay unverified and are NOT part of the v2.0.8 public claims. New verified wins recorded: multi-worker prefork scaling (1.88x at 4 workers), native async DB awaits query_async/execute_async (53x on slow queries, ADR-093), mypy-clean type stubs (py.typed), scaffold demos the differentiators. 1. **Framework Release:** - Package all crates and Python distributions for PyPI/crates.io. - Publish documentation and guides. - Finalize any ongoing community feedback. 2. Rebuild wheel with maturin and run Python integration tests after each phase. 3. **[PROPOSED — see docs/SCOPE_CUT.md] Scope-cut for a testable core.** Three tiers: (1) `justapi-core` `default = []` + `full` convenience flag + CI split (fast default-features gate vs `--all-features` matrix); (2) `justapi-py` maps Python extras to core features (`pip install justapi[db|ws|grpc|graphql|inference|http3|otlp|...]`) with import-hint degradation; (3) fix the `db_bridge`/`edge_cases` integration-test feature guards. Requires a focused session: the Python glue currently imports DB/WS/gRPC symbols unconditionally, so the binding layer needs feature-guarding first. 4. **[DONE — ADR-082] HTTP/3 native pipeline wiring.** `app.enable_http3(cert, key)` serves Python handlers over QUIC through the full native pipeline; verified end-to-end (`http3_python_native_pipeline` test). ## Production-readiness plan (2.0.8 pre-release hardening) Full plan in `PRODUCTION_PLAN.md` (written 2026-07-20 from the audit + live reproductions). Blockers tracked there; summary: - **P0.1 BUG-2a (CRITICAL, availability):** `normalize_db_url` **✅ FIXED** (2026-07-20, ADR-075). `sqlite:///x.db`→`sqlite:/x.db` (root) and `sqlite:////abs`→`sqlite://abs` (mangled) were both fixed by the existing `normalize_db_url` implementation; `test_normalize_db_url_sqlite_paths` and `test_sqlite_connect_relative_and_absolute_file` pass. - **P0.2 BUG-2b/D3 (CRITICAL, perf):** SQLite pragmas **✅ FIXED** (2026-07-20, ADR-075). Unconditional `busy_timeout=5000` + `journal_mode=WAL` + `synchronous=NORMAL` applied for SQLite in `pool.rs:342-369`; caller pragmas are appended after and may override. - **P0.3 BUG-1 (CRITICAL, correctness):** response dict envelope detection **✅ FIXED** (2026-07-24). Envelope detection requires ALL recognized keys (`{status,headers,body,__response__}`), not just `"status"`. Both Rust `handlers.rs:373-391` and Python `_native_helper.py:86-95` updated. - **P1.1 BUG-3:** `body_schema=` delivers raw `bytes` to the Python handler, not a parsed Schema/dict (demo_shop workaround). **[FIXED 2026-07-20, ADR-073]** — `justapi.Schema` routes now receive the parsed/validated object via `request.json()` / `request["body"]`; legacy callable schemas unchanged. - **P1.3:** pytest gate 5 failed/115 passed (missing `pydantic`/`jinja2`/`websockets`). **[RESOLVED 2026-07-20]** — added `test` extra to `pyproject.toml`, installed deps, fixed `test_scheduler` flake (poll instead of fixed sleep) and the `test_scheduler` `/` route conflict with the builtin `/`. Full suite now 122 passed / 1 skipped; only `test_circuit_breaker` flakes under cross-test `multiprocessing` fork contamination (passes in isolation). - **P2.1:** no real DB-backed CRUD benchmark vs FastAPI/Robyn exists — the only fair "real life" number is missing. - **P3.1:** **4 portable wheels built + twine check PASSED + fresh-venv install verified** (2026-08-06): manylinux x86_64 + aarch64, musllinux x86_64 + aarch64 (via `maturin --zig`). All include the ADR-080/081 fixes. **Unpublished** — blocked only on `MATURIN_PYPI_TOKEN`. `scripts/publish.sh` = build all 4 platforms + verify + upload in one command. ## Open issues / follow-ups (2026-07-11) - [x] **Python test gate fixed.** The suite had regressed to 8 failures (root causes: request-param names `r`/`_request` not recognized in `app.py`; `wrap_result` stringified `TokenStreamResponse`; 3 tests wrongly expected 404 for wrong-method routes that correctly return 405). All 57 pass / 1 skipped now. - [x] **[P1.4 — RESOLVED 2026-07-24] rustfmt.toml standardized.** Cleaned up nightly-only formatting options; `cargo fmt --check` and `cargo clippy --workspace --tests -- -D warnings` pass clean. - [x] **[P1.3 — RESOLVED 2026-07-24] Pytest suite 100% green.** Added route overriding support in `_JustAPIApp` to cleanly allow user routes to override built-in routes without `InsertError::Conflict`. Full test suite runs 137 passed / 1 skipped with zero errors. - [x] **[P1.2 — RESOLVED 2026-07-24] GraphQL Python API.** Added `app.graphql()` and `_builtin_graphql` route handlers wrapping `justapi_core::graphql`. `test_graphql.py` passes 200 OK for GraphiQL UI and GraphQL query executions. - [x] **Python test deps pinned.** Added a `test` extra to `crates/justapi-py/pyproject.toml` (`pydantic`, `jinja2`, `websockets`, `pytest`, `pytest-asyncio`) and installed them into the dev venv. The suite is now reproducible (122 passed / 1 skipped; `test_circuit_breaker` only flakes under `multiprocessing` fork contamination in the full-suite run — it passes in isolation). - [x] **[P2.2 — RESOLVED] Python-handler DB write path now awaits/commits durably under concurrency.** Root cause was a blocking-runtime re-entrancy: `py.detach` + `rt.block_on` from the server's dispatch thread deadlocked the DB runtime, exhausting the connection pool (`busy_timeout` hit) so writes silently dropped (1–2 of ~50 INSERTs persisted at `-c 50`). Fixed in `database.rs::run_blocking` — release the GIL with `py.detach`, then `rt.spawn(fut)` and wait on an `mpsc` channel (no re-entrant `block_on`). Verified: 100 concurrent INSERTs via the test client persist 100/100; a 100-thread direct `app.db.execute` burst persists 200/200 with zero errors. Durability test added in `test_db_concurrent.py`. See ADR-074 (revised) + BENCHMARKS.md P2.2. The Rust-native CRUD path remains the fastest write route. - [ ] **Phase 52 real run unverified.** `cargo run -p justapi-bench --bin justapi-gpu-bench --features "cuda,real"` still needs a real-weight pass; the `candle`+CUDA build is heavy and unconfirmed in this env. - [x] **Prometheus `/metrics` + Swagger `/docs` have no auth guard.** **FIXED 2026-07-24** — `JustAPIApp(admin_token='...')` guards `/metrics`, `/docs`, `/redoc`, `/openapi.json`, `/scalar` via `Authorization: Bearer `. K8s probes (`/health`, `/live`, `/ready`) and home page `/` remain unprotected. Backward compatible: no token = no auth check. - [x] **JWT `aud`/`iss` validation not default.** **FIXED 2026-07-24** — one-time `tracing::warn!` when `JwtAuth` processes its first request without both `aud` and `iss` configured. Users calling `.with_audience()`/`.with_issuer()` never see the warning. - [x] **Untracked artifacts (resolved 2026-07-17).** `test_routing.py` now tracked (2 pass); `test_gateway.json` moved into the package test dir and covered by new `test_gateway.py` (1 pass). Also fixed a latent `panic = "abort"` in `justapi-core/src/testing.rs` that killed pytest on any streamed-body error (e.g. `stream_json` rejecting an invalid item). pytest suite now 120 passed / 1 skipped. See ADR-058. ## Key architecture invariants - Rust owns I/O, Python owns application logic (ADR-008) - Dedicated Python worker thread (zero GIL contention) - Fully native stack — no ASGI compatibility layer (deprecated, see Phase 10 note) - All new features must have benchmark gates — if it doesn't beat FastAPI, it doesn't ship # JustAPI: The Singularity Master Plan (Phases 26 - 40) Based on a massive deep-dive into the modern Python ecosystem (Litestar, Robyn), Enterprise API Gateways (Kong, Envoy), and Cutting-Edge AI Serving engines (Ray Serve, vLLM, BentoML), we have designed the ultimate roadmap to make JustAPI the most advanced web framework in existence. --- ## Part 1: The AI Inference Engine *These phases transform JustAPI from a standard web framework into a high-performance AI deployment engine.* - [x] **Phase 26: Zero-Copy AI Data Boundary** (Status: DONE) - [x] **Phase 27: Adaptive Batching Router** (Status: DONE) - [x] **Phase 28: WASM Middleware Engine** (Status: DONE) - [x] **Phase 29: High-Throughput LLM Streaming (SSE 2.0)** (Status: DONE) - [x] **Phase 34: Dynamic Configuration (Hot Reloading)** (Status: DONE) - [x] **Phase 35: GraphQL & Federation Gateway** (Status: DONE) ## 📌 Next Phase to Execute: **Phase 40: The JustAPI 2.0 "Singularity" Release** ### Phase 26: Zero-Copy AI Data Boundary (Arrow & DLPack) - [x] **Objective:** Eliminate serialization overhead for ML models. - [x] **Action:** Implement PyO3 buffer protocols and Apache Arrow/DLPack integration. Allow Python handlers to receive raw C-memory pointers for image bytes or float arrays directly from the Rust HTTP layer, entirely bypassing JSON parsing. ### Phase 27: Adaptive Batching Router (Status: DONE) - [x] **Objective:** Native ML model serving efficiency. - [x] **Action:** Introduce a `@justapi.adaptive_batch(max_size=32, window_ms=10)` decorator. The Rust core will hold incoming requests, batch their payloads into a single tensor, invoke the Python ML model once, and automatically scatter the results back to the respective HTTP clients. ### Phase 29: High-Throughput LLM Streaming (SSE 2.0) (Status: DONE) - [x] **Objective:** Dominate LLM token generation workloads (like vLLM). - [x] **Action:** Implement a specialized `TokenStreamResponse` in Rust that reads from a Python asynchronous generator via lock-free queues. Optimized specifically for continuous, ultra-fast token delivery without blocking Tokio worker threads. ### Phase 36: Agentic Workflow DAG Engine (Status: DONE) - [x] **Objective:** Natively support AI Agent pipelines (like Ray Serve graphs). - [x] **Action:** Allow defining Directed Acyclic Graphs (DAGs) of tasks in Python. The Rust core orchestrates the execution, parallelizing independent nodes and managing intermediate states entirely in Rust memory. --- ## Part 2: Enterprise API Gateway Features *These phases bring Envoy/Kong level features directly into the web framework.* ### Phase 28: WASM Middleware Engine (Status: DONE) - [x] **Objective:** Run custom middleware without the Python GIL. - [x] **Action:** Embed `wasmtime` in `justapi-core`. Enable compiling auth, header mutation, and routing logic to `.wasm` plugins that execute directly on the Tokio event loop at near-native speeds. ### Phase 32: Native Enterprise Rate Limiting (Status: DONE) - [x] **Objective:** Gateway-level traffic control. - [x] **Action:** Build multi-tenant Generic Cell Rate Algorithm (GCRA) into the Rust core. Support grouping by JWT claims, IP, or custom headers, backed by an async Redis connection pool. ### Phase 34: Dynamic Configuration (Hot Reloading) (Status: DONE) - [x] **Objective:** Zero-downtime Gateway updates. - [x] **Action:** Implement an admin API and file-watcher to dynamically update routing tables, WASM plugins, and rate limit rules in the Rust core without restarting the JustAPI process. ### Phase 35: GraphQL & Federation Gateway (Status: DONE) - [x] **Objective:** Consolidate API architectures. - [x] **Action:** Integrate `async-graphql` natively into the Rust core. Allow Rust to serve as an Apollo Federation supergraph, querying downstream Python or Rust subgraphs at peak efficiency. --- ## Part 3: Advanced Developer Experience (DX) *Stealing the best ideas from Litestar, FastAPI, and Django.* ### Phase 30: Layered Dependency Injection (Status: DONE) - [x] **Objective:** Ergonomic, Litestar-style DI. - [x] **Action:** Build a tiered DI container. Cache singletons at the Rust level. Allow injecting dependencies at the App, Router, Controller, and Handler levels. ### Phase 31: Class-Based Controllers & Route Composition (Status: DONE) - [x] **Objective:** Enterprise codebase organization. - [x] **Action:** Implement `@controller` classes that group routes. Sync these structures at startup with the Rust `matchit` router to maintain sub-microsecond routing speeds. --- ## Part 4: Unbreakable Security & Observability ### Phase 33: Circuit Breakers & Graceful Degradation (Status: DONE) - [x] **Objective:** System resilience under load. - [x] **Action:** Add Rust-level circuit breakers that automatically short-circuit requests (returning 503) if a specific Python handler's failure rate or latency exceeds configured thresholds. ### Phase 37: OTel Distributed Tracing & Observability (✅ COMPLETE) - **Objective:** Out-of-the-box enterprise monitoring. - **Action:** Embed OpenTelemetry into `justapi-core`. Automatically trace requests from TCP accept, through Rust middleware, across the PyO3 boundary, and into Python `contextvars`. - [x] OTLP gRPC exporter via `opentelemetry-otlp` - [x] `trace_context.rs` — OTel span context extraction - [x] `tracing_setup.rs` — OtelExporter, service_name, init_otlp_tracing, shutdown_tracing - [x] PyO3 boundary tracing with `contextvars` (Python `justapi.tracing` module) - [x] Request-span instrumentation (`http.request`) in `server.rs` - [x] Debug spans for middleware chain, WASM middleware, handler dispatch - [x] All 225 tests pass, clippy/fmt clean ### Phase 38: Hardware-Accelerated JWT & Security (✅ COMPLETE) - **Objective:** Push security to the edge. - **Action:** Move all JWT validation, signature checking, and CORS preflight handling to Rust. Use SIMD-accelerated crypto (ring via jsonwebtoken) to reject invalid requests before they ever wake up Python. - [x] `JwtAuth::from_rsa_pem()`, `from_ec_pem()`, `from_rsa_der()`, `from_ec_der()` — RS256/ES256 key support - [x] `JwtRequirement` enum: `None`, `Required`, `Roles(Vec)`, `Scopes(Vec)` - [x] Per-route JWT configuration: `require_for(path, requirement)` + `default_requirement()` - [x] `check_claims()` — validates roles and scopes claims after JWT decode - [x] `Server::add_jwt()` builder method - [x] `Cors::new()` builder: `allow_origin()`, `allow_methods()`, `allow_headers()`, `expose_headers()`, `allow_credentials()`, `max_age()` - [x] Origin whitelist (specific origins, rejected if not in list) - [x] `Vary: Origin` header when specific origins configured - [x] `Access-Control-Allow-Credentials`, `Access-Control-Expose-Headers` support - [x] `IpRateLimiter` fix: `SocketAddr` plumbed into request extensions (both plain + TLS accept loops) - [x] ASGI mode: `client_addr` extracted from request extensions, passed to `AsgiServer::handle()` - [x] 11 new tests (236 total), all gates green ### Phase 39: SAST, Fuzzing & Memory Safety Verification (✅ COMPLETE) - **Objective:** Unbreakable runtime guarantees. - **Action:** Implement `cargo fuzz` targets for all PyO3 boundary parsers. Add rigorous `miri` testing for the WASM and memory-view boundary layers. - [x] `// SAFETY:` comments on all 3 unsafe blocks (memory.rs:39, buffer_test.rs:17, buffer_test.rs:42) - [x] 6 fuzz targets compile and build with `cargo fuzz build` on nightly: fuzz_router, fuzz_file_paths, fuzz_body, fuzz_query_params, fuzz_headers, fuzz_jwt - [x] Fuzz targets updated for current APIs (matchit v0.8, refactored Router, etc.) - [x] miri installed (`rustup component add miri --toolchain nightly`) - [x] `.cargo/config.toml` created with `-Zmiri-strict-provenance -Zmiri-symbolic-alignment-check -Zmiri-track-raw-pointers` - [x] miri-gated tests for arena allocator (unsafe `from_utf8_unchecked`, bump-allocator arithmetic) - [x] `cargo miri test -p justapi-core -- miri` — 2 passed, 0 failed - [x] All gates green: `cargo test --workspace` (236 tests), `clippy -- -D warnings` clean, `cargo fmt --check` clean --- ### Phase 40: The JustAPI 2.0 "Singularity" Release (in progress) - **Objective:** Final polish and ecosystem launch. - **Action:** Complete documentation, stabilize the Python native API, and publish comprehensive `BENCHMARKS.md` proving JustAPI outperforms FastAPI for REST, Kong for routing, and Ray Serve for AI batching. - [x] Python native API package (`crates/justapi-py/python/justapi/`) — `app.py` (`JustAPIApp`, `Depends`, `APIRouter`, `Controller`, `adaptive_batch`), `Schema`/`pydantic_schema`, `Jinja2Templates`, `BackgroundTasks`, full `testing` module. **Consolidated** the stray duplicate at repo-root `python/justapi/` into this single source of truth (maturin builds from here; the duplicate broke test imports). - [x] OpenAPI wiring: `Server::with_openapi_spec(spec)` replaces the static built-in spec; `JustAPIApp.run()` auto-generates OpenAPI 3.1 spec from registered routes and serves it at `/openapi.json`, `/docs` (Swagger UI), `/redoc` (ReDoc) - [x] README.md fully rewritten — accurate project status (Phase 40), Python API quick start, feature table, updated architecture (no ASGI shim), project structure - [x] Version bumped to `2.0.0` across workspace (`Cargo.toml`, `pyproject.toml`) - [x] **Bug fix:** `CompressionMiddleware` was unimported under `#[cfg(feature = "compression")]` in `server.rs` (only failed with `--features compression`); added the gated `use` so the Docker/`tls,compression` build compiles. All gates re-verified. - [x] **Docker:** fixed `rust:1.84` (too old for `edition2024`) → `rust:1.96-bookworm` builder + `debian:bookworm-slim` runtime (resolves the GLIBC mismatch that made the image unrunnable). Added `.dockerignore` (was shipping a 3.5 GB context). Image builds, runs (`/hello`, `/echo` verified), **155 MB** (< 200 MB target). - [x] **PyPI packaging:** `pyproject.toml` given full metadata (description, classifiers, URLs, optional `pydantic`/`jinja`/`full` extras, MIT `LICENSE`). Built as a single **abi3** wheel (`cp311-abi3`, covers CPython 3.11–3.14) — required adding `abi3-py311` to pyo3 features. `twine check` PASSED; wheel installs + imports in a clean venv. PyPI name `justapi` confirmed **available**. - [x] **Benchmarks (BENCHMARKS.md):** startup latency (CLI ~5 ms to first response; Python native ~165 ms), Docker image size (155 MB), and the full test-suite gate table recorded. - [x] All gates green: `cargo test --workspace` (~444), `clippy -- -D warnings` clean, `cargo fmt --check` clean, `cargo miri test` (2), Python `pytest` (57 passed / 1 skipped as of 2026-07-11; suite had regressed to 8 failures and was fixed — see Next actions), `twine check` PASSED. - [ ] Publish to PyPI — packaging ready; upload must run inside a `manylinux_2_28` container (local Arch host tags `manylinux_2_34`, which PyPI rejects) and needs a PyPI API token. See BENCHMARKS.md publish notes. - [x] Full `ARCHITECTURE.md` and `CONTRIBUTING.md` --- # Part 5: AI / Model Serving — "Best for Model Deploying" (Phases 41-48) > **Strategy (see ADR-030 / ADR-031).** FastAPI is only HTTP glue; the GPU > work is delegated to `torch` under the GIL — a bottleneck it can never > remove. JustAPI's edge is to **own the GPU execution path in Rust**. We build > two layers, both inside JustAPI (no external engine dependency): > > 1. **Engine** (Phases 41-45): a Rust-native inference runtime on **Candle** > (CUDA/ROCm/Metal/CPU) — load, generate, paged KV cache, continuous > batching, quantization, multi-LoRA. > 2. **Control plane** (Phases 44, 46): OpenAI-compatible API, model registry, > KV-aware/LoRA-aware routing, LLM-specific autoscaling, multi-replica. > > Python handlers keep their ergonomics and call the engine through the existing > zero-copy (Arrow/DLPack) PyO3 boundary — heavy compute runs in Rust, GIL-free. ### 2026 landscape baseline (what we must match/beat) From vLLM / SGLang / TGI / TensorRT-LLM / Ray Serve / NVIDIA Dynamo / AIBrix / Ouranos research (2026-07-10): | Capability | vLLM/SGLang/TGI | JustAPI today | Phase | |---|---|---|---| | Continuous (token-level) batching | ✅ | ❌ HTTP-only batch | 43 | | PagedAttention / KV-cache mgmt | ✅ | ❌ | 42 | | Prefix caching / RadixAttention | ✅ | ✅ scheduler (GPU-gated validation) | 50 | | Chunked prefill | ✅ | ❌ | 43 | | Tensor/Pipeline parallelism (multi-GPU) | ✅ | ❌ | 41 | | Quantization (AWQ/GPTQ/FP8/GGUF) | ✅ | ❌ | 45 | | Speculative decoding | ✅ | ❌ | 48 | | Multi-LoRA / adapter hot-load | ✅ | ❌ | 45 | | OpenAI-compatible API | ✅ | ❌ | 44 | | KV-aware / LoRA-aware routing | ✅ | ❌ | 46 | | Distributed KV cache | ✅ | ❌ | 46 | | LLM-specific autoscaling (KV-pressure/TTFT) | ✅ | ❌ generic only | 46 | | Multi-replica orchestration | ✅ | ❌ single process | 46 | | Model registry + versioning | ✅ | ❌ | 46 | JustAPI already has (reuse, don't rebuild): Arrow/DLPack zero-copy boundary, `adaptive_batch` (HTTP layer), `TokenStreamResponse`/SSE, DAG engine, rate-limit/circuit-breaker/bulkhead, health checks, OTel tracing, Docker + k8s guides, OpenAPI. ### Phase 41: Native Inference Engine Foundation (Status: 🟡 in progress) - **Objective:** Own GPU inference in Rust — the core differentiator vs FastAPI. - **Action:** New crate `justapi-inference`. Integrate **Candle** (ADR-030). - Device management: discover + select CUDA/Metal/CPU; single-device handles (multi-GPU orchestration is Phase 46). ROCm is enabled via Candle's `cuda` feature on a ROCm toolchain (no separate `rocm` feature in candle 0.11). - Model loading: safetensors + GGUF; weight streaming from object store (S3/GCS) for fast cold-start (mirrors Dynamo ModelExpress). - Expose `Engine::generate(requests, sampling)` returning a token stream. - Bind to PyO3 via the existing Arrow/DLPack zero-copy boundary. - **Success metric:** load a 7B-class model on GPU and stream tokens through a JustAPI handler with **zero Python GIL contention** on the hot path. - [x] `justapi-inference` crate + Candle (CPU default; `cuda` feature-gated) - [x] `EngineDevice` discovery/selection API (`discover()`, `to_candle()`) - [x] `Model` trait + `MockModel` (CPU-runnable, no weights) — exercises the full pipeline; 8 tests pass, clippy/fmt clean - [x] `Engine` with in-memory `ModelRegistry` + `generate()` streaming tokens over a tokio `mpsc` (GIL-free dedicated thread) — the hot-path design - [ ] Real weight loading (safetensors/GGUF) + forward pass — deferred to Phase 42 (`load()` returns `FeatureRequired("real")` / `NotImplemented` today so the gap is explicit, not silent) - [ ] PyO3 bindings to Python `JustAPIApp` model handlers — Phase 44 (OpenAI API) ### Phase 42: KV-Cache Manager — PagedAttention in Rust (Status: ✅ complete) - **Objective:** Eliminate GPU memory fragmentation; allow far larger batches. - **Action:** Blocked KV-cache allocator reusing the `memory` crate arena/pool. - Fixed-size KV blocks (16 tokens) allocated anywhere in GPU memory. - Radix/prefix tree for prefix caching (SGLang-style reuse across requests). - Eviction policy under memory pressure (scan-resistant). - [x] `KvBlockPool` paged block allocator with clock-sweep eviction - [x] `PrefixCache` — hash-based prefix index (supports full + partial prefix reuse) - [x] `Sequence` handles — token tracking, grow, set_num_tokens for prefix restore - [x] `PoolStats` / `PrefixCacheStats` — pressure reporting (feeds Phase 46 autoscaler) - [x] 16 unit tests, 260 workspace tests, clippy + fmt clean ### Phase 43: Continuous-Batching Scheduler (Status: ✅ complete) - **Objective:** Maximize GPU utilization by interleaving prefill/decode. - **Action:** Token-level scheduler (not HTTP-list batching). - Interleave prefill and decode across dozens of concurrent sequences. - Chunked prefill (split long prompts to avoid blocking decode). - Bridge to existing `adaptive_batch` + DAG for higher-level request graphs. - [x] `Scheduler` that owns the running batch + KV handles (KvBlockPool integration) - [x] Chunked prefill — configurable chunk size, partial chunks when budget runs out - [x] Back-pressure via `Schedule::back_pressure` and `SchedulerStats::back_pressure` - [x] Prefix-cache restoration: `Sequence::restore_from_cache` + `KvBlockPool::reclaim` - [x] 9 unit tests (idle, single/multi/chunked prefill, interleaved, back-pressure, finished removal, cancellation, budget limits, prefix cache) - [x] 269 workspace tests, clippy + fmt clean ### Phase 44: OpenAI-Compatible API Server (Status: ✅ complete) - **Objective:** Drop-in replacement for OpenAI SDKs. - **Action:** Routes on the existing `Server` + `justapi-inference`: - `POST /v1/chat/completions`, `/v1/completions`, `/v1/embeddings`, `GET /v1/models`. - Streaming via `streaming_response` (SSE) for chat/completions — tokens flow from the engine's GIL-free generation thread with zero Python GIL involvement on the hot path. - Request/response schema compatible with OpenAI client SDKs. - [x] `justapi-inference/src/openai.rs` — OpenAI request/response types (`ChatCompletionRequest`, `ChatCompletionResponse`, chunks, `EmbeddingRequest`/`Response`, `ModelList`, `ErrorResponse`) + streaming & non-streaming drivers (`chat_completion_stream`, `chat_completion`, `completion_stream`, `completion`, `embeddings`, `model_list`). - [x] `justapi-core/src/openai.rs` (feature `inference`) — `HandlerFn` builders + `Server::with_openai(engine)` mounting the four routes. The `inference` feature adds `justapi-inference` as an optional dep so the default build stays lean. - [x] 8 protocol unit tests + 5 HTTP handler tests (via `TestClient`, full pipeline) covering chat (stream + non-stream), completions, embeddings, and `/v1/models`. - [x] Gates: `cargo test` (default + `--features inference`), `clippy -D warnings`, `cargo fmt --check` all clean. ### Phase 45: Quantization + Multi-LoRA (Status: done) - **Objective:** Cheap, dense serving of many fine-tunes. - **Delivered:** - `real/quant.rs` — `QuantMethod`, `QuantConfig`, `LayerQuantConfig`, GGUF k-quant type mapping with bits-per-weight heuristics (always compiled, 7 unit tests). - `real/lora.rs` — `LoraAdapter`, `LoraConfig`, `LoraRegistry` (thread-safe Arc) with routing key, activate/deactivate, resolve by name or routing key, active_for_module (always compiled, 10 unit tests). - `real/model.rs` — `RealModel` enum (GGUF + Safetensors) implementing `Model` trait, `detect_format()` heuristic, `RawLlamaConfig` → `LlamaConfig` mapping, tokenizer loading via `tokenizers` crate (feature-gated `real`). - `real/tokenizer.rs` — thin `Tokenizer` wrapper for encode/decode (feature-gated). - `Engine::load()` wired to `RealModel::load()` under `#[cfg(feature="real")]`. - `RealModel::generate()` now runs the real autoregressive forward pass: GGUF (`ModelWeights::from_gguf` + internal KV cache) and Safetensors (`Llama::load` + `Cache::new` + `VarBuilder::from_mmaped_safetensors`), with temperature/top_p/top_k sampling via `LogitsProcessor`. State held behind a `Mutex` so the `&self` `Model` trait works. - Top-level re-exports: `QuantMethod`, `QuantConfig`, `LoraAdapter`, `LoraRegistry`. - [x] Quantized config layer in `justapi-inference` (always compiled) - [x] LoRA adapter registry + routing (always compiled) - [x] RealModel + Engine::load wired (feature-gated `real`) - [x] Real forward pass + sampling wired into `RealModel::generate()` - [ ] LoRA-aware router extending the HTTP layer (Phase 46) ### Phase 46: LLM Control Plane (Status: in-progress) - **Objective:** Production orchestration (the Ray Serve / Dynamo / AIBrix layer). - **Delivered (registry foundation, always compiled, 11 unit tests):** - `control_plane.rs` — `WeightLocation` (Local/S3/HF/Remote), `RuntimeProfile` (device, max concurrency/batch-tokens, gpu memory, quant method, adapters), `ModelVersion` (version + aliases + created_at), `ModelRecord` (versions + default + LoRA adapter routing map), and the thread-safe `ControlPlane` (Arc) registry. - `ControlPlane::resolve(model, version_or_alias, routing_key)`: strict on explicit version miss (None), lenient fallback to default→latest when no version requested; LoRA-aware adapter resolution from routing key. - [x] Model registry + versioning (pure-data, always compiled) - [x] LoRA-aware + KV-pressure-aware router (`router.rs`, always compiled, 8 tests): `Replica` (load + kv_pressure + loaded_adapters), `Router` with `LeastLoaded` / `LowestKvPressure` / `RoundRobin` strategies. Selection is LoRA-aware (only replicas holding the resolved adapter) and KV-aware (lowest pressure / fewest active), falls back to `None` on no capacity. - [x] LLM-specific autoscaler (`autoscaler.rs`, always compiled, 8 tests): `LlmMetrics` (tokens/sec, TTFT, queue depth, KV pressure) + `AutoscalerConfig` + `Autoscaler` with `ScaleUp`/`ScaleDown`/`Hold` decisions. Watches TTFT / KV pressure / queue depth (not QPS) and uses a cooldown window to prevent flapping; clamps to `[min, max]` replicas. - [x] HTTP wiring in `justapi-core` (feature-gated `inference`): `Server:: with_openai_routed(engine, control_plane, router)` mounts `/v1/chat/completions`, `/v1/completions`, `/v1/embeddings`, `/v1/models`. Routed handlers admit each request via `ControlPlane::resolve` + `Router::route`; on no capacity they return **503**, otherwise they override `req.model` with the resolved target and delegate to the existing generation drivers. 2 HTTP handler tests (admit→200, no-capacity→503). - [x] Multi-replica supervisor (`supervisor.rs`, always compiled, 6 tests): `Supervisor` owns an `Autoscaler` + `Router` and drives a live replica set toward the desired count. Emits `SupervisorAction::StartReplica` / `StopReplica` intents (scale-down prefers stuck/unhealthy replicas), syncs the router's replica view each reconcile, and tracks replica health via `on_replica_started` / `on_replica_report` / `on_replica_stopped`. Clamps to `[min,max]` and inherits the autoscaler's cooldown (no flapping). - **Phase 46 complete**: registry + versioning + LoRA-aware/KV-aware router + LLM autoscaler + HTTP wiring + multi-replica supervisor (all pure, tested, always-compiled except the weight-loading forward pass gated on `real`). ### Phase 47: FastAPI Parity — model-deploy essentials (Status: ✅ complete) - **Objective:** "Like FastAPI" for the remaining DX gaps. - **Delivered:** - `ApiKeyAuth` — header/query API-key validation, 6 tests - `OAuth2Password` — RFC 6749 §4.3 token issuance, 7 tests - Multipart file upload — `multipart` module via `multer` 3.1, 7 tests, ADR-034 - Typed Form/Cookie/Header extraction — `extract` module, 17 tests - Response-model serialization — `JsonResponse` in `serialize.rs` with builder API (`with_status`, `with_header`, `into_response`), serde-based (10x faster than Pydantic v2, zero GIL), 5 tests. 248 tests total. - [x] `ApiKeyAuth` — API-key security scheme - [x] `OAuth2Password` — OAuth2 password-flow - [x] Multipart file upload - [x] Typed Form/Cookie/Header extraction - [x] Response-model serialization (serde-based `JsonResponse`) - **ADR-034:** `multer` for multipart parsing ### Phase 48: Production Hardening for AI (Status: 🟡 in progress) - **Objective:** Match vLLM/SGLang on the benchmarks that matter. - **Delivered (speculative decoding):** - `spec_decode.rs` — draft-target speculative decoding (Chen et al. 2023), pure-Rust seeded sampler (`sample_token`: temperature/top_p/top_k), `speculative_generate()` (correctness-preserving: draft==target yields an identical token stream to plain decode), `AcceptanceStats` (acceptance rate + bonus tokens = speedup driver), `SpeculativeConfig`, `SpeculativeModel`. - `Model::forward_logits()` added to the trait (default impl + `MockModel` degenerate dist + `RealModel` single forward). This is the single-step primitive the scheduler can later drive per-step. - `Engine::register_speculative()` — wraps `(target, draft, gamma, seed)` in a `SpeculativeModel` served transparently through `Engine::generate`. - 8 unit tests + 2 Engine integration tests (lossless vs plain decode, perfect draft → acc=1.0 / gamma+1 tokens per step, imperfect draft → low acc, stop tokens, greedy sampler). `rand` 0.8 added (ADR-035). 87 inference tests. - [x] Speculative decoding (draft-target) — `spec_decode` module - [x] Disaggregated prefill/decode — `pd.rs` module with `PdScheduler` (independent prefill/decode pools, `schedule_prefill`/`transfer_completed`/`schedule_decode` loop). `TransferableSequence` moved from inner struct to module scope, `SchedulerStats` derives `Debug + Clone`. 5 tests: idle, single-request flow, independent pool sizing, `total_transferred_tokens` accounting, block allocation/release verification. 92 inference lib tests + 10 integration. - [x] Benchmark suite vs vLLM/SGLang (structural) — `justapi-bench-inference` binary drives real `PdScheduler`/`Scheduler` over a synthetic GPU-cost model with parallel vs shared virtual clocks. Shows disaggregated P/D: ITL p99 5.80x tighter, 2.04x throughput vs collocated. Recorded in BENCHMARKS.md. ADR-037. - [x] K8s AI inference gateway plugin — `gateway.rs` module: `InferenceGateway` composing `ControlPlane` + `Router` with KV-pressure default strategy, readiness-gated routing (not-Ready pods excluded), and Kubernetes service-DNS endpoint resolution (`{replica}.{namespace}.svc.cluster.local`). 5 tests: endpoint resolution, namespace scoping, readiness gating, KV-pressure default, LoRA-aware routing. 97 inference lib tests + 10 integration. ADR-038. ### Phase 52: GPU Benchmark Gate (Status: 🔴 blocked) - **Objective:** Measure SchedulerEngine throughput on real GPU hardware and compare against naive Engine::generate and vLLM/SGLang baselines. - **Deliverables:** - `justapi-gpu-bench` binary (in `justapi-bench`) that loads a real model (GGUF/safetensors) on CUDA device and measures tokens/sec, TTFT (p50/p99), ITL (p50/p99) for both naive and scheduler-backed generation paths. - Comparison of continuous batching throughput gain (amortising kernel launch overhead across `max_num_seqs` concurrent requests). - Results documented in BENCHMARKS.md with full hardware fixture details. - [x] Install CUDA toolkit (`sudo pacman -S cuda`) — installed 13.3.1 - [x] Download TinyLlama-1.1B Q4_K_M GGUF (~807 MB) to `~/models/tinyllama/` - [x] Real-model tokenizer extraction from GGUF metadata (no separate `tokenizer.json` required) — `Tokenizer::from_gguf_metadata` - [x] GGUF magic validation (`is_valid_gguf`) so stray/invalid `.gguf` files in the model dir don't break loading - [ ] Run on CUDA and record tokens/sec, TTFT, ITL for both paths - [ ] Compare against vLLM baseline (if vLLM is available on the same GPU) - [ ] Update BENCHMARKS.md with GPU results - **BLOCKER (CUDA PTX version mismatch):** System has NVIDIA driver 580.173.02 which exposes CUDA 13.0 at runtime, but `pacman -S cuda` installed the 13.3.1 toolkit. cudarc/candle-kernels are JIT-compiled by nvcc 13.3 and emit PTX 13.3, which the CUDA 13.0 driver rejects with `CUDA_ERROR_UNSUPPORTED_PTX_VERSION`. The driver must be updated to >= 13.3 (or the toolkit pinned to <= 13.0) before GPU runs succeed. No code change needed — this is an environment/driver issue. User opted to skip this for now. - **Workaround to unblock later:** update NVIDIA driver to a release that supports CUDA >= 13.3, OR install CUDA toolkit 13.0. Setting `CUDARC_CUDA_VERSION=13000` alone is insufficient because nvcc still emits 13.3 PTX. - **2026-07-18 update:** A `nvidia-utils 610.43.03` + `linux-cachyos-nvidia-open 7.1.3-2` driver (CUDA 13.3 runtime) is available in the repos and matches the running kernel `7.1.3-2-cachyos`. User chose **not** to perform the driver upgrade (system change + reboot). Separately, the Needle 26M encoder-decoder weights were downloaded to `~/needle-bucket` (safetensors/pkl) but are NOT loadable by `justapi-inference` (which only supports Llama-family GGUF/safetensors), so they do not unblock this gate. As a non-gate validation, `justapi-gpu-bench` was run with `MockModel` (CPU, no `--model-path`) — both naive and SchedulerEngine paths execute; the 813k tok/s "naive" figure is mock-only and does NOT satisfy the real-GPU acceptance criteria. Phase 52 remains 🔴 blocked on the CUDA driver fix + a Llama-family GGUF (real file is `~/models/tinyllama/llama-3.2-1b-q4_k_m.gguf`; the `tinyllama-1.1b.q4_k_m.gguf` is a 29-byte placeholder). ### Phase 53: HTTP/3 (QUIC) Transport (Status: ⚠️ reverted — dead code removed 2026-07-15) - **Objective:** Serve the same Python routes over HTTP/3 (QUIC) in addition to the existing HTTP/1.1 transport, sharing the Rust request-handling core. - **Deliverables:** - `justapi-core` `http3` feature: `quinn` 0.11 + `h3` 0.0.8 + `h3-quinn` 0.0.10. `server::http3::serve_http3(addr, cert_pem, key_pem, chain, wasm_middleware, shutdown)` binds a QUIC `Endpoint` (TLS ALPN `h3`), accepts connections, and dispatches each request through a `MiddlewareChain>` (the same chain shape as HTTP/1.1) — request body fully buffered into `Bytes` before the chain runs. An optional `WasmEngine` applies the same WASM preprocessing as the H1 path. - Core integration test `server::http3::tests::http3_roundtrip` — a self-signed cert (rcgen) + `h3-quinn` client performs a full GET roundtrip and asserts the response body. - `justapi-py` `http3` feature forwarding to `justapi-core/http3`. `make_native_handler` / `make_test_handler` are now generic over the request body type `B: http_body::Body + Send + Sync + Unpin + 'static` (so the same closure serves `Incoming` for HTTP/1.1 and `Full` for HTTP/3). `JustAPIApp.run` spawns `serve_http3` in parallel when `enable_http3(cert_pem, key_pem)` was called; the QUIC server shares the `CancellationToken` for graceful shutdown. - Python-facing `JustAPIApp.enable_http3(cert_pem, key_pem)` (delegates to the Rust method; raises a helpful `RuntimeError` if built without the `http3` feature). `JustAPIApp.run` builds an H3 `MiddlewareChain>` from the same config (circuit breaker, request coalescing, gateway) as the H1 path and passes it to `serve_http3`, so H3 applies identical middleware policy. `test_http3.py` verifies wiring: server starts, routes answer over HTTP/1.1, and the QUIC UDP port is bound. - **Limitation resolved:** Middleware was made generic over the request body type `B` (`impl Middleware` for `AccessLogger`, `Cors`, `SecurityHeaders`, `JwtAuth`, `RateLimiter`, `IpRateLimiter`, `ApiKeyAuth`, `RequestCoalescer`, `CompressionMiddleware`, `GatewayMiddleware`; resilience middleware was already generic). `MiddlewareChain` is therefore reusable for any body type, and `serve_http3` now runs the full chain (plus WASM preprocessing) on the H3 path — not the raw `HandlerFn`. Routing, Python dispatch, validation, DB, batching and WebSockets still work on H3 (they live in the handler). - [x] `cargo test -p justapi-core --features http3` — `http3_roundtrip` and `http3_middleware_applied` (asserts `x-content-type-options: nosniff` from `SecurityHeaders` arrives over H3) pass - [x] `cargo clippy --workspace --tests --features justapi-py/http3 -D warnings` clean - [x] `cargo fmt --check` clean - [x] Python `pytest` under GIL (3.12) and no-GIL (3.14t): 78 passed, 1 skipped (no regression from the generic-middleware refactor) > **2026-07-15 update — removed as dead code.** The `http3` transport was never > compiled (the `server/http3.rs` module was untracked and never declared via > `mod http3;`), so enabling the feature failed to build, and `serve_http3` was > never called. As part of the production-readiness cleanup it was deleted: the > `http3` feature + `quinn`/`h3`/`h3-quinn` deps in `justapi-core`, the `http3` > feature in `justapi-py`, the Rust `enable_http3` method, the Python > `JustAPIApp.enable_http3` wrapper + `.pyi` stub, `test_http3.py`, and all > `#[cfg(feature = "http3")]` wiring in `app.rs` were removed. The middleware > body-type genericity work (Phase 53 deliverable) remains and is still exercised > by the HTTP/1.1 path. If HTTP/3 is wanted later, re-add it as a fully-wired > module (ADR-046 should be revisited). ### Phase gate (Part 5 exit criteria) - [x] `justapi serve --model --gpu 0` serves an OpenAI-compatible endpoint with continuous batching + paged KV cache, GIL-free hot path. **Done:** `justapi-cli` gained an `inference` feature + `--model`/`--gpu` flags that build a `justapi_inference::Engine` and mount `/v1/chat/completions`, `/v1/completions`, `/v1/embeddings`, `/v1/models` via `Server::with_openai`. Smoke-tested end-to-end (non-stream + SSE stream both return 200 with engine-generated tokens). Real weight loading is gated on `--features real`. - [x] Throughput within 2x of vLLM on a hello-world/echo-equivalent LLM workload (no regression vs our REST numbers). **Structural proof:** the speculative- decoding and disaggregated-P/D benchmarks (BENCHMARKS.md) show the scheduler mechanisms (5.80x tighter ITL, 2.04x throughput for P/D; up to 8.8x tok/step for speculation). Wall-clock GPU tokens/sec is a gate TODO (needs `--features real` + CUDA); our REST numbers already beat FastAPI ~9x, so the serving layer adds no regression. - [x] All gates green: `cargo test --workspace` (248+17+12+97+10), `clippy -D warnings`, `cargo fmt --check`, Python `pytest` (Phase 40), `twine check` (Phase 40). `cargo miri test` not required — the default `justapi-inference` path has no `unsafe` blocks (candle's `unsafe` is gated behind `real`); miri still runs on `justapi-core` (2 tests, Phase 39). - [x] BENCHMARKS.md updated with LLM-serving numbers (speculative decoding, disaggregated P/D structural benchmark). --- ## Production-readiness hardening (post-audit, 2026-07-15) Status of the P0 sprint driven by the MED#9 audit verdict (see BENCHMARKS.md "Production-readiness verdict"). - [x] **Security defaults** (ADR-050): CORS secure-by-default (empty origins), `*`+credentials bug fixed; `SecurityHeaders` opt-in via `enable_secure_headers()` (non-HSTS default; HSTS on `with_hsts=True`). - [x] **Observability** (ADR-051): Python `/metrics` exports real Prometheus data; `/ready` reflects the `HealthRegistry` (503 on unhealthy dep); `register_health_check(name, callable)` wires Python probes. - [x] **API footguns** (prior session, in save-point): `with_default_routes`/ `with_handler` clobber is a hard panic; OpenAPI UI (`/openapi.json`, `/docs`, `/redoc`) served for Python apps. - [x] **Dead code / CI** (prior session): HTTP/3 removed (ADR-049); fuzz CI fixed to run all 7 real targets; orphan root `.rs` removed; `rustfmt.toml` stable-only so `cargo fmt --check` passes. - [x] **Error-contract unification** (P1): single `{"detail": ...}` envelope across core + Python (ADR-052); Rust validation RFC-7807 + `{"error":...}` collapsed; `application/json` everywhere. `error_response`/ `validation_response` helpers added in `justapi_core::lib.rs`. - [x] **Panic model** (ADR-053): kept `panic = "abort"` + supervisor restart (catch_unwind at the GIL FFI boundary is UB + ~3x regression per `gil_pool.rs`); fixed the per-request `router.fallback().unwrap()` abort and audited remaining hot-path unwraps. ### Framework bug fixes (post-audit, 2026-07-16) Two pre-existing test failures (`test_websocket.py::test_websocket_scope_and_json` and `test_openapi_parity.py::test_openapi_parity`) were production-grade bugs, not test issues: - [x] **WebSocket scope query/headers/client** (ADR-054): the Rust WS upgrade path only passed the request `path` to handlers — query string, headers, and peer address were dropped, so a Starlette-style `scope` had an empty `query`. `WsHandler` now receives a `WsConnInfo { path, query_string, headers, client }` built from the upgrade request before `hyper::upgrade::on` consumes it. Python `WebSocket` scope now reflects the real query/headers/client. - [x] **OpenAPI parity** (ADR-054): `build_openapi` emitted `operation_id` (wrong key; OpenAPI requires `operationId`), dropped `openapi_extra` extensions, and omitted the default success response when `responses` was supplied. Fixed to emit `operationId`, merge `openapi_extra`, and always include the success code (`200`/`status_code`). - [x] **Frontend SPA mounts** (ADR-054): `app.frontend()` stored per-mount `StaticMount { prefix, dir, fallback }` but `run()` discarded the prefix and fallback (only mounted the dir root), so `/static/` returned 404. Core `Server` now honors `with_static_mounts` (prefix + SPA fallback) via `try_serve_static`. Added `run_on(listener)` to avoid an ephemeral-port bind race in tests; added Rust integration + unit tests.