Mutation responses now include invalidation directives from the server:
POST /api/mizan/call/
→ {"result": {...}, "invalidate": ["user"]}
The client never hardcodes invalidation targets. The server resolves
affects= metadata and returns what to invalidate. mizan-runtime reads
the invalidate key and triggers refetches automatically.
Context fetch returns raw bundled data (not wrapped):
GET /api/mizan/ctx/user/?user_id=5
→ {"user_profile": {...}, "user_orders": [...]}
Also fixed QueryDict handling (use .dict() not dict() to avoid
list-wrapped values).
267 Django tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
packages/
mizan-runtime/ Framework-agnostic state engine (~150 lines)
Context registry, batched invalidation, fetch primitives
mizan-django/ Django server adapter (was packages/mizan-rpc/adapters/django/)
Codegen moved to mizan-django/generate/
mizan-react/ React adapter (was packages/mizan-csr/adapters/react/)
Removed premature abstractions: mizan-ast, mizan-schema, mizan-rpc,
mizan-csr, mizan-ssr stub packages. The actual architecture is three
concrete packages, not five abstract layers.
mizan-runtime implements the v1 spec: registerContext with params,
scoped invalidation via microtask batching, server-driven invalidation
from mutation responses, mizanFetch for context bundles, mizanCall for
mutations.
264 Django + 33 React tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>