Return-type branching: one decorator, two paths
@client now handles both RPC and view functions based on return type:
@client(affects=UserContext)
def update_name(request, user_id: int, name: str) -> dict:
... # RPC path: JSON response with invalidate key
@client(affects=UserContext)
def update_profile(request, user_id: int) -> HttpResponse:
... # View path: HttpResponse with X-Mizan-Invalidate header
Detection: isinstance(result, HttpResponseBase) after execution.
RPC path (data return):
- Serialized via Pydantic model_dump()
- Wrapped in {"result": ..., "invalidate": [...]}
- Invalidation in JSON body + X-Mizan-Invalidate header
View path (HttpResponse return):
- Response passed through directly (redirect, HTML, etc.)
- X-Mizan-Invalidate header added automatically
- Cache-Control: no-store added
- No codegen (view_path=True in _meta)
- Registered in invalidation graph (for Edge manifest)
Auto-scoping works on both paths: if mutation args overlap
with context params, invalidation is scoped automatically.
308 Django tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>