Files
mizan/README.md
Ryth Azhur 58d2cb2848 AFI parity: generate the matrix from conformance probes, not prose
The per-adapter parity table was hand-maintained prose. An adapter that
never wired a capability (FastAPI SSR, Axum WebSocket) got its gap
relabelled "Django-only" or "out of scope — use native equivalents," and
nothing went red. The de-scope was crystallized in five mutually-ratifying
sites: the README §Stack-extensions table, the AFI fixture docstring
("channels/forms/shapes aren't AFI-common"), the core registry's
extension-hook framing, the mizan-fastapi __init__ docstring, and a
"CSRF is Django-only" comment in two adapters' session endpoints.

Replace prose-parity with conformance-generated parity:

- tests/afi/manifest.py declares the AFI-common surface as data — one list
  of capabilities, one of adapters. Applicability ("—") is derived from
  transport, never typed.
- tests/afi/probes.py independently inspects each backend's source for the
  artifact a capability requires (comment-stripped, backend-scoped). Green
  means wired; a cell can't be set by editing a word.
- tests/afi/test_capability_parity.py asserts every (capability × applicable
  adapter) pair is wired. 35 unwired gaps are now loud red TFDD tests, each
  naming an owed binding. No xfail/skip.
- tests/afi/parity_table.py generates the README table from the probes;
  `make parity-check` fails CI on any hand-edit, like the codegen byte-parity.

Purge the five de-scope sites. The IR byte-parity gate is unchanged and green.
`make test-afi` is now intentionally red on the 35 gaps — that board is the
owed parity work, itemized; a gap turns green by being wired, never described.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 12:58:03 -04:00

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. Edge
  • ROADMAP.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-Invalidate header — 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 in manifest.py is 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.