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:
149
backends/mizan-ts/tests/ir-fixture.ts
Normal file
149
backends/mizan-ts/tests/ir-fixture.ts
Normal 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 }
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user