AFI parity: close all 35 gaps — every adapter wires every AFI-common capability

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>
This commit is contained in:
2026-06-04 13:44:35 -04:00
parent 58d2cb2848
commit 6c5f6f1fba
81 changed files with 9893 additions and 463 deletions

View File

@@ -0,0 +1,145 @@
"""
Forms behavior — the genuine capability behind the `forms` probe.
Proves the Pydantic binding exposes the same schema / validate / submit role
contract as the Django adapter: subclassing `mizanForm` auto-registers
`{name}.schema`, `{name}.validate`, `{name}.submit` with the matching
`_meta["form_role"]`, the schema role emits typed field definitions, validate
returns structured field errors, and submit validates then runs
`on_submit_success` / `on_submit_failure`.
"""
from __future__ import annotations
import pytest
from mizan_core.registry import clear_registry, get_function
from mizan_fastapi.forms import (
FormConfig,
FormSubmitFail,
FormSubmitPass,
FormValidation,
build_form_schema,
get_forms,
mizanForm,
)
@pytest.fixture(autouse=True)
def _clean():
clear_registry()
yield
clear_registry()
def _make_contact_form():
class ContactForm(mizanForm):
mizan = FormConfig(name="contact", title="Contact Us", submit_label="Send")
name: str
email: str
message: str = ""
def on_submit_success(self, request) -> dict:
return {"sent": True, "to": self.email}
return ContactForm
def test_subclassing_registers_three_role_functions():
_make_contact_form()
for role in ("schema", "validate", "submit"):
fn = get_function(f"contact.{role}")
assert fn is not None, f"contact.{role} not registered"
assert fn._meta["form"] is True
assert fn._meta["form_name"] == "contact"
assert fn._meta["form_role"] == role
def test_schema_role_emits_field_definitions():
form_cls = _make_contact_form()
SchemaFn = get_function("contact.schema")
schema = SchemaFn(request=None).call(None)
assert schema.name == "contact"
assert schema.title == "Contact Us"
assert schema.submit_label == "Send"
field_names = {f.name for f in schema.fields}
assert field_names == {"name", "email", "message"}
# `message` has a default → not required; `name`/`email` required
by_name = {f.name: f for f in schema.fields}
assert by_name["name"].required is True
assert by_name["message"].required is False
def test_build_form_schema_maps_types():
class TypedForm(mizanForm):
mizan = FormConfig(name="typed")
count: int
ratio: float
active: bool
label: str
schema = build_form_schema(TypedForm)
by_name = {f.name: f for f in schema.fields}
assert by_name["count"].type == "number"
assert by_name["ratio"].type == "number"
assert by_name["active"].type == "checkbox"
assert by_name["label"].type == "text"
def test_validate_role_passes_clean_data():
_make_contact_form()
ValidateFn = get_function("contact.validate")
ValidateInput = ValidateFn.Input
out = ValidateFn(request=None).call(ValidateInput(data={"name": "Ryth", "email": "r@x.com"}))
assert isinstance(out, FormValidation)
assert out.errors == []
def test_validate_role_reports_field_errors():
_make_contact_form()
ValidateFn = get_function("contact.validate")
ValidateInput = ValidateFn.Input
out = ValidateFn(request=None).call(ValidateInput(data={"email": "r@x.com"})) # missing 'name'
error_fields = {e.field for e in out.errors}
assert "name" in error_fields
def test_submit_role_runs_on_submit_success():
_make_contact_form()
SubmitFn = get_function("contact.submit")
SubmitInput = SubmitFn.Input
result = SubmitFn(request=None).call(
SubmitInput(data={"name": "Ryth", "email": "ryth@example.com", "message": "hi"})
)
assert isinstance(result, FormSubmitPass)
assert result.success is True
assert result.data == {"sent": True, "to": "ryth@example.com"}
def test_submit_role_returns_fail_on_invalid():
captured = {}
class GuardedForm(mizanForm):
mizan = FormConfig(name="guarded")
name: str
def on_submit_failure(self, request, errors) -> None:
captured["errors"] = errors
SubmitFn = get_function("guarded.submit")
SubmitInput = SubmitFn.Input
result = SubmitFn(request=None).call(SubmitInput(data={})) # missing required 'name'
assert isinstance(result, FormSubmitFail)
assert result.success is False
assert any(e.field == "name" for e in result.errors.errors)
# on_submit_failure hook fired with the validation
assert "errors" in captured
def test_get_forms_groups_by_form_name():
_make_contact_form()
forms = get_forms()
assert set(forms.keys()) == {"contact"}
assert len(forms["contact"]) == 3