Mizan IR: cut over to KDL, delete OpenAPI envelope
Replaces the transitional OpenAPI 3.0 + `x-mizan-*` extensions
substrate with the canonical Mizan IR as KDL, per docs/AFI_ARCHITECTURE.md:
"KDL is the contract; everything else (REST envelopes, OpenAPI
documents, framework idioms) is sediment around it."
End-to-end cutover. No transitional path left on main.
Forward direction:
cores/mizan-python/src/mizan_core/ir.py
build_ir() walks mizan_core.registry, introspects Pydantic
models directly (no JSON-Schema indirection), and emits the
Mizan IR document. The KDL grammar is locked in this file's
module docstring.
Backends emit KDL:
backends/mizan-fastapi/src/mizan_fastapi/ir.py
`python -m mizan_fastapi.ir <module>` — CLI entry point.
backends/mizan-django/.../management/commands/export_mizan_ir.py
`manage.py export_mizan_ir` — Django mgmt command.
Codegen consumes KDL:
protocol/mizan-codegen/Cargo.toml: + kdl = "6"
protocol/mizan-codegen/src/ir.rs: NamedType { Struct/List/Enum/Alias }
+ TypeShape { Primitive/Ref/List/Optional/Enum/Union } sum types,
replacing the JsonSchema sprawl. KDL parser walks the
`kdl::KdlDocument` tree into typed Rust structs.
protocol/mizan-codegen/src/fetch.rs: subprocess command switches
to the new IR-export entry points.
All emit modules (stage1 / react / python / rust / vue / svelte /
channels) port their type-walkers from JsonSchema to the new
sum types — case analysis collapses substantially.
Substrate-honesty wins beyond the moat closure:
- `int | bool` multi-arm unions land as `TypeShape::Union` (was
silently coerced to "string" before).
- `<CamelName>Output = list[T]` returns emit as named alias
types instead of struct-shaped wrappers, so consumer code
`.map()` works directly on the type.
- Pydantic field defaults flow through to `default` properties
in KDL, then back to non-optional shape in every target.
Deleted:
- backends/mizan-fastapi/src/mizan_fastapi/{cli,schema}.py
- backends/mizan-django/.../export_mizan_schema.py
- openapi-bearing half of mizan/export/__init__.py (edge
manifest generator preserved — separate concern).
- tests/afi/schema_normalizer.py
- tests/fixtures/{afi_schema.json, channels_schema.json}
- tests/fixtures/js_* baseline directories.
Verification:
- 20 mizan-codegen unit tests green (IR deserialization,
byte-equivalence parity across stage1/rust/python/react/vue/svelte
against fresh KDL-driven baselines, channels structural).
- tests/rust/run_wire_parity.py: 12/12 probes green driving
the binary end-to-end through KDL.
- Blazr studio-ui typechecks against the regenerated React client.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
10
protocol/mizan-codegen/tests/fixtures/baselines/rust/Cargo.toml
vendored
Normal file
10
protocol/mizan-codegen/tests/fixtures/baselines/rust/Cargo.toml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "fixture_client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
mizan-rust = { path = "../../../frontends/mizan-rust" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1", features = ["rt", "macros"] }
|
||||
3
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/contexts/mod.rs
vendored
Normal file
3
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/contexts/mod.rs
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
pub mod user;
|
||||
29
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/contexts/user.rs
vendored
Normal file
29
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/contexts/user.rs
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use mizan_rust::{MizanClient, MizanError};
|
||||
|
||||
use crate::types::{UserProfileOutput, UserOrdersOutput};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserContextData {
|
||||
pub user_profile: UserProfileOutput,
|
||||
pub user_orders: UserOrdersOutput,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserContextParams {
|
||||
pub user_id: i64,
|
||||
}
|
||||
|
||||
pub async fn fetch_user_context(
|
||||
client: &MizanClient,
|
||||
params: &UserContextParams,
|
||||
) -> Result<UserContextData, MizanError> {
|
||||
let params_value = serde_json::to_value(params).unwrap_or(Value::Object(Default::default()));
|
||||
let raw = client.fetch_context("user", ¶ms_value).await?;
|
||||
serde_json::from_value(raw)
|
||||
.map_err(|e| MizanError::transport(format!("decode user context: {e}")))
|
||||
}
|
||||
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/echo.rs
vendored
Normal file
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/echo.rs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use mizan_rust::{MizanClient, MizanError};
|
||||
|
||||
use crate::types::{EchoOutput, EchoInput};
|
||||
|
||||
pub async fn call_echo(client: &MizanClient, args: &EchoInput) -> Result<EchoOutput, MizanError> {
|
||||
let args_value = serde_json::to_value(args).unwrap_or(Value::Object(Default::default()));
|
||||
let raw = client.call("echo", args_value).await?;
|
||||
serde_json::from_value(raw)
|
||||
.map_err(|e| MizanError::transport(format!("decode echo result: {e}")))
|
||||
}
|
||||
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/find_user.rs
vendored
Normal file
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/find_user.rs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use mizan_rust::{MizanClient, MizanError};
|
||||
|
||||
use crate::types::{FindUserOutput, FindUserInput};
|
||||
|
||||
pub async fn call_find_user(client: &MizanClient, args: &FindUserInput) -> Result<Option<FindUserOutput>, MizanError> {
|
||||
let args_value = serde_json::to_value(args).unwrap_or(Value::Object(Default::default()));
|
||||
let raw = client.call("find_user", args_value).await?;
|
||||
serde_json::from_value(raw)
|
||||
.map_err(|e| MizanError::transport(format!("decode find_user result: {e}")))
|
||||
}
|
||||
6
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/mod.rs
vendored
Normal file
6
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/mod.rs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
pub mod echo;
|
||||
pub mod find_user;
|
||||
pub mod rename_user;
|
||||
pub mod whoami;
|
||||
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/rename_user.rs
vendored
Normal file
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/rename_user.rs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use mizan_rust::{MizanClient, MizanError};
|
||||
|
||||
use crate::types::{RenameUserOutput, RenameUserInput};
|
||||
|
||||
pub async fn call_rename_user(client: &MizanClient, args: &RenameUserInput) -> Result<RenameUserOutput, MizanError> {
|
||||
let args_value = serde_json::to_value(args).unwrap_or(Value::Object(Default::default()));
|
||||
let raw = client.call("rename_user", args_value).await?;
|
||||
serde_json::from_value(raw)
|
||||
.map_err(|e| MizanError::transport(format!("decode rename_user result: {e}")))
|
||||
}
|
||||
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/whoami.rs
vendored
Normal file
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/functions/whoami.rs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use mizan_rust::{MizanClient, MizanError};
|
||||
|
||||
use crate::types::{WhoamiOutput};
|
||||
|
||||
pub async fn call_whoami(client: &MizanClient) -> Result<WhoamiOutput, MizanError> {
|
||||
let args_value = Value::Object(Default::default());
|
||||
let raw = client.call("whoami", args_value).await?;
|
||||
serde_json::from_value(raw)
|
||||
.map_err(|e| MizanError::transport(format!("decode whoami result: {e}")))
|
||||
}
|
||||
8
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/lib.rs
vendored
Normal file
8
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/lib.rs
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
pub mod types;
|
||||
pub mod contexts;
|
||||
pub mod mutations;
|
||||
pub mod functions;
|
||||
|
||||
pub use mizan_rust::{MizanClient, MizanConfig, MizanError};
|
||||
3
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/mutations/mod.rs
vendored
Normal file
3
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/mutations/mod.rs
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
pub mod update_profile;
|
||||
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/mutations/update_profile.rs
vendored
Normal file
14
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/mutations/update_profile.rs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use mizan_rust::{MizanClient, MizanError};
|
||||
|
||||
use crate::types::{UpdateProfileOutput, UpdateProfileInput};
|
||||
|
||||
pub async fn call_update_profile(client: &MizanClient, args: &UpdateProfileInput) -> Result<UpdateProfileOutput, MizanError> {
|
||||
let args_value = serde_json::to_value(args).unwrap_or(Value::Object(Default::default()));
|
||||
let raw = client.call("update_profile", args_value).await?;
|
||||
serde_json::from_value(raw)
|
||||
.map_err(|e| MizanError::transport(format!("decode update_profile result: {e}")))
|
||||
}
|
||||
81
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/types.rs
vendored
Normal file
81
protocol/mizan-codegen/tests/fixtures/baselines/rust/src/types.rs
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
// AUTO-GENERATED by mizan — do not edit
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OrderOutput {
|
||||
pub id: i64,
|
||||
pub user_id: i64,
|
||||
pub total: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EchoInput {
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EchoOutput {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FindUserInput {
|
||||
pub user_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FindUserOutput {
|
||||
pub user_id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RenameUserInput {
|
||||
pub user_id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RenameUserOutput {
|
||||
pub user_id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UpdateProfileInput {
|
||||
pub user_id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UpdateProfileOutput {
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserOrdersInput {
|
||||
pub user_id: i64,
|
||||
}
|
||||
|
||||
pub type UserOrdersOutput = Vec<OrderOutput>;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserProfileInput {
|
||||
pub user_id: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserProfileOutput {
|
||||
pub user_id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct WhoamiOutput {
|
||||
pub email: String,
|
||||
pub authenticated: bool,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user