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,149 @@
/**
* The AFI fixture, TypeScript side — mirrors `tests/afi/fixture.py` 1:1.
*
* Each function declares the same IR type schema the Python fixture's Pydantic
* Input/Output models imply, so `buildIr()` here emits the same KDL the Python
* `build_ir()` emits from `fixture.py`. The byte-parity test (`ir.test.ts`)
* subprocesses the live Python emitter and asserts equality.
*
* Output structs are declared under their model name (`ProfileOutput`,
* `OrderOutput`, …) and referenced via `{ kind: 'ref' }`; the emitter renames
* them to the canonical `<camel>Output`, exactly as `_collect_named_types`
* renames the Pydantic models.
*/
import { client, ReactContext } from '../src'
import type { NamedType, StructField } from '../src'
const intField = (name: string): StructField => ({
name,
required: true,
shape: { kind: 'primitive', primitive: 'integer' },
})
const strField = (name: string): StructField => ({
name,
required: true,
shape: { kind: 'primitive', primitive: 'string' },
})
const boolField = (name: string): StructField => ({
name,
required: true,
shape: { kind: 'primitive', primitive: 'boolean' },
})
const ProfileOutput: NamedType = { kind: 'struct', fields: [intField('user_id'), strField('name')] }
const OrderOutput: NamedType = {
kind: 'struct',
fields: [intField('id'), intField('user_id'), intField('total')],
}
const UserCtx = new ReactContext('user')
/** Register the AFI fixture functions with the mizan-ts registry. */
export function registerFixture(): void {
// echo — plain function, typed input + struct output.
client(
{
ir: {
input: [strField('text')],
output: { kind: 'ref', name: 'EchoOutput' },
types: { EchoOutput: { kind: 'struct', fields: [strField('message')] } },
},
},
async function echo(text: string) {
return { message: `echo: ${text}` }
},
)
// whoami — no input.
client(
{
ir: {
output: { kind: 'ref', name: 'WhoamiOutput' },
types: {
WhoamiOutput: {
kind: 'struct',
fields: [strField('email'), boolField('authenticated')],
},
},
},
},
async function whoami() {
return { email: 'anon@example.com', authenticated: false }
},
)
// user_profile — context member.
client(
{
context: UserCtx,
ir: {
input: [intField('user_id')],
output: { kind: 'ref', name: 'ProfileOutput' },
types: { ProfileOutput },
},
},
async function user_profile(user_id: number) {
return { user_id, name: 'placeholder' }
},
)
// user_orders — context member, list output, same param (param elevation).
client(
{
context: UserCtx,
ir: {
input: [intField('user_id')],
output: { kind: 'list', inner: { kind: 'ref', name: 'OrderOutput' } },
types: { OrderOutput },
},
},
async function user_orders(_user_id: number) {
return []
},
)
// update_profile — mutation affecting the user context.
client(
{
affects: UserCtx,
ir: {
input: [intField('user_id'), strField('name')],
output: { kind: 'ref', name: 'StatusOutput' },
types: { StatusOutput: { kind: 'struct', fields: [boolField('ok')] } },
},
},
async function update_profile(_user_id: number, _name: string) {
return { ok: true }
},
)
// find_user — optional return.
client(
{
ir: {
input: [intField('user_id')],
output: { kind: 'optional', inner: { kind: 'ref', name: 'ProfileOutput' } },
types: { ProfileOutput },
},
},
async function find_user(_user_id: number) {
return null
},
)
// rename_user — merge target.
client(
{
merge: UserCtx,
ir: {
input: [intField('user_id'), strField('name')],
output: { kind: 'ref', name: 'ProfileOutput' },
types: { ProfileOutput },
},
},
async function rename_user(user_id: number, name: string) {
return { user_id, name }
},
)
}