The conformance board (tests/afi/test_capability_parity.py) is now fully green: 90 capability cells + 4 meta-locks + 3 codegen byte-parity = 97 passed. The gaps the prose table used to launder as "Django-only" / "out of scope" are wired, against the pinned-spec model (single-authored spec, byte-identical conformance across languages) — never per-language reimplementation. FastAPI — edge_manifest + PSR (logic single-sourced in mizan_core.manifest), WebSocket RPC (/ws/ through the shared dispatch), SSR (the framework-agnostic SSRBridge relocated to mizan_core.ssr; Django rides it from there), Shapes (SQLAlchemy projection, same declaration surface as django-readers), Forms (Pydantic schema/validate/submit). Rust (Axum + Tauri + cores/mizan-rust) — X-Mizan-Invalidate header, auth= enforcement, origin HMAC cache, edge manifest + PSR, WebSocket handler / IPC subscription channel, multipart upload, SSR bridge, Shapes, Forms; JWT/MWT mint+verify and cache-key derivation byte-pinned to the Python reference (cache_keys_pin, token_pin, invalidate_header_pin). TypeScript — a KDL IR emitter byte-identical to the Python build_ir (so a TS backend can feed the codegen — the largest gap), multipart upload, session-init, WebSocket transport, SSR bridge, JWT/MWT mint (pinned to Python), Shapes, Forms. Verified in the merged tree: core 25, fastapi 74, django 353/21-skip, mizan-rust (incl. cross-language pins) green, axum 10, tauri 8, mizan-ts 103/2-skip. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.5 KiB
Mizan
Mizan is an Application Framework Interface (AFI). A single @client decorator on a
server function generates a typed frontend client; cache invalidation and caching are
handled by the protocol.
from mizan import client, ReactContext
UserContext = ReactContext('user')
# Context function — bundled into GET /api/mizan/ctx/user/
@client(context=UserContext)
def user_profile(request, user_id: int) -> UserShape:
return UserShape.query(lambda qs: qs.filter(pk=user_id))[0]
# Mutation — invalidation scoped automatically by matching param name
@client(affects=UserContext)
def update_profile(request, user_id: int, name: str) -> dict:
...
Adapters exist for Django, FastAPI, Rust/Axum, Tauri, and TypeScript. Django is the reference implementation; per-adapter support is inventoried below.
Status: Mizan is not production-tested. It passes its own test suites but has not been run in a production deployment. Treat it as pre-release.
Documentation
docs/— architecture references: AFI, SSR, cache keying, MWT, PSR vs. EdgeROADMAP.md·ISSUES.md— planned work and known gaps
Backend adapters
Every adapter implements the same AFI wire protocol. The matrix below is generated
from the conformance probes in tests/afi/ by make parity-table — it is
output, not prose. A cell goes ✅ only when that adapter wires the capability into its
own dispatch surface; it cannot be set to "supported" or "Django-only" by editing this
file (a hand-edit fails python tests/afi/parity_table.py --check in CI, the same
forcing function the codegen byte-parity tests use).
Every capability in the matrix is AFI-common — each adapter owes a binding, and a
❌ is a gap on the owed-work board, never a "this framework doesn't do that." The line
between AFI-common and genuinely backend-bound lives in
tests/afi/manifest.py: what sits outside the matrix by
design is the allauth integration (a Django-ecosystem package) and the per-stack
bindings of common capabilities (django-readers is Django's Shapes binding; Django
Forms is Django's Forms binding) — the capability is common; the binding is not.
Legend: ✅ wired · ◑ partial (declared/stubbed) · ❌ gap (AFI-common, owed) · — not applicable to this adapter's transport
Every capability below is AFI-common: each adapter owes a binding, and a ❌ is a gap on the owed-work board (tests/afi/), never a category. Backend-specific bindings of common capabilities (django-readers for Shapes, Django Forms for Forms) and genuinely Django-ecosystem features (allauth) are out of this matrix by design — see tests/afi/manifest.py for the line.
Protocol core
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
RPC call dispatch ({result, invalidate}) |
✅ | ✅ | ✅ | ✅ | ✅ |
| Named-context bundle fetch | ✅ | ✅ | ✅ | ✅ | ✅ |
| Invalidation — JSON body | ✅ | ✅ | ✅ | ✅ | ✅ |
Invalidation — X-Mizan-Invalidate header |
✅ | ✅ | ✅ | — | ✅ |
| Invalidation auto-scoping (three-tier) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Function discovery / registration | ✅ | ✅ | ✅ | ✅ | ✅ |
| Codegen IR export (KDL) | ✅ | ✅ | ✅ | ✅ | ✅ |
File uploads (Upload type) |
✅ | ✅ | ✅ | ✅ | ✅ |
Edge, cache & enforcement
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
Auth-guard enforcement (auth=… rejects) |
✅ | ✅ | ✅ | ✅ | ✅ |
| Origin-side HMAC cache | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edge manifest export | ✅ | ✅ | ✅ | — | ✅ |
PSR (render_strategy in manifest) |
✅ | ✅ | ✅ | — | ✅ |
| Session / CSRF init endpoint | ✅ | ✅ | ✅ | — | ✅ |
Extension points
| Capability | Django | FastAPI | Rust / Axum | Tauri | TypeScript |
|---|---|---|---|---|---|
WebSocket transport (websocket= declared) |
✅ | ✅ | ✅ | ✅ | ✅ |
| SSR bridge (subprocess renderer) | ✅ | ✅ | ✅ | ✅ | ✅ |
| JWT auth (access / refresh) | ✅ | ✅ | ✅ | ✅ | ✅ |
| MWT (edge identity token) | ✅ | ✅ | ✅ | — | ✅ |
| Typed query projection (Shapes) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Forms (schema / validate / submit) | ✅ | ✅ | ✅ | ✅ | ✅ |
Notes
- Invalidation —
X-Mizan-Invalidateheader — The header channel is co-equal with the body channel in the spec. IPC transports carry invalidation in the response envelope instead. - Edge manifest export — The manifest configures an HTTP/CDN edge; a desktop IPC shell has no edge.
- MWT (edge identity token) — MWT exists to key an edge cache; without an edge there is nothing to key.
- Typed query projection (Shapes) — The capability is AFI-common; the binding is per-ORM (django-readers on Django, the project's ORM elsewhere).
- Forms (schema / validate / submit) — The capability is AFI-common; the binding is per-framework (Django Forms on Django, Pydantic-or-equivalent elsewhere).
Conformance
Adapter parity is gated by the AFI conformance suite in tests/afi/, at
two layers:
- IR-shape parity (
test_codegen_parity.py) — Django, FastAPI, and the Rust adapter emit byte-identical KDL for the same registered fixture. The IR is the contract; the language that wrote the backend is irrelevant to the codegen-facing artifact. - Capability parity (
test_capability_parity.py) — every(capability, applicable adapter)pair declared inmanifest.pyis probed for its actual wiring (probes.py). A gap is a red test that names the owed binding, not a footnote. The suite is intentionally red wherever a capability is unwired: that redness is the owed-work board, itemized and loud, and a gap turns green by being wired, never by being described. This is the per-capability gate the roadmap previously deferred.
The generated table above is rendered from the capability layer, and the --check
diff keeps the README honest to the probes on every CI run.
License
Mizan is licensed under the Elastic License 2.0 (SPDX: Elastic-2.0). You
may use, copy, modify, and distribute it freely, including in commercial products you
build on top of it. You may not provide Mizan to third parties as a hosted or
managed service that exposes a substantial set of its features.