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:
53
backends/mizan-ts/tests/fixtures/stub-worker.mjs
vendored
Normal file
53
backends/mizan-ts/tests/fixtures/stub-worker.mjs
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Protocol-conformant stub SSR worker — speaks the EXACT same newline-delimited
|
||||
* JSON-RPC the real `workers/mizan-ssr/src/worker.tsx` speaks, but with no React
|
||||
* dependency. It lets `tests/ssr.test.ts` exercise the full SSRBridge subprocess
|
||||
* machinery (ready handshake, id correlation, render reply, ping, error frame)
|
||||
* under plain Node, independent of the real worker's install state.
|
||||
*
|
||||
* `render` echoes the props into a deterministic HTML string so the bridge's
|
||||
* request/response correlation is observable; a file named "*boom*" yields an
|
||||
* error frame to prove the failure path.
|
||||
*/
|
||||
|
||||
function respond(msg) {
|
||||
process.stdout.write(JSON.stringify(msg) + '\n')
|
||||
}
|
||||
|
||||
function handle(msg) {
|
||||
if (msg.method === 'ping') {
|
||||
respond({ id: msg.id, pong: true })
|
||||
return
|
||||
}
|
||||
if (msg.method === 'render') {
|
||||
const { file, props } = msg.params ?? {}
|
||||
if (typeof file === 'string' && file.includes('boom')) {
|
||||
respond({ id: msg.id, error: `cannot render ${file}` })
|
||||
return
|
||||
}
|
||||
respond({ id: msg.id, html: `<div data-file="${file}">${JSON.stringify(props ?? {})}</div>` })
|
||||
return
|
||||
}
|
||||
respond({ id: msg.id, error: `Unknown method: ${msg.method}` })
|
||||
}
|
||||
|
||||
let buffer = ''
|
||||
process.stdin.setEncoding('utf-8')
|
||||
process.stdin.on('data', (chunk) => {
|
||||
buffer += chunk
|
||||
let nl
|
||||
while ((nl = buffer.indexOf('\n')) !== -1) {
|
||||
const line = buffer.slice(0, nl).trim()
|
||||
buffer = buffer.slice(nl + 1)
|
||||
if (line) {
|
||||
try {
|
||||
handle(JSON.parse(line))
|
||||
} catch (e) {
|
||||
respond({ id: -1, error: e.message })
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Ready handshake — identical to the real worker.
|
||||
respond({ id: 0, ready: true })
|
||||
Reference in New Issue
Block a user