Phase 2C: generate the SDK wire types from a Rust emitter#559
Conversation
There was a problem hiding this comment.
Pull request overview
Phase 2C of the versioning remediation: this PR eliminates the remaining “drift surface” between the Rust wire model, the generated JSON schema, and the SDK TypeScript wire types by generating sdk/src/generated/wire.ts via a hand-written Rust emitter (invoked as mxc_schema_gen --ts) and enforcing conformance in CI and unit tests.
Changes:
- Add a Rust TypeScript emitter (
wxc_common::ts_emit) and expose TS emission viamxc_schema_gen --ts. - Add a compile-time conformance oracle test in the SDK plus a CI codegen gate to prevent
wire.tsdrift. - Retire the legacy hand-maintained
0.5.0-alpha-strictstable schema view and update docs accordingly.
Show a summary per file
| File | Description |
|---|---|
| src/tools/mxc_schema_gen/src/main.rs | Adds --ts mode and refactors output handling for schema vs TS emission. |
| src/core/wxc_common/src/wire.rs | Factors out shared schema_value() and adds generate_sdk_types_ts() entrypoint for TS emission. |
| src/core/wxc_common/src/ts_emit.rs | New Rust emitter that walks the schema Value and emits deterministic wire.ts. |
| src/core/wxc_common/src/lib.rs | Exposes ts_emit behind the schema-gen feature. |
| sdk/tests/unit/wire-conformance.test.ts | New compile-time (tsc) conformance oracle between public SDK types and generated wire types. |
| sdk/src/generated/wire.ts | New generated drift-oracle TypeScript wire types (committed output). |
| sdk/README.md | Removes references to the retired 0.5.0-alpha-strict schema view. |
| sdk/package.json | Adds the new wire conformance unit test to the unit test run list. |
| scripts/versioning/check-sdk-types-codegen.js | New CI gate to regenerate wire.ts and diff against committed output (with CRLF/LF normalization). |
| schemas/stable/mxc-config.schema.0.5.0-alpha-strict.json | Deletes the hand-maintained strict stable schema view. |
| docs/schema-codegen.md | Documents the new generated SDK wire-types drift oracle and updated roadmap. |
| .github/workflows/Versioning.Checks.Job.yml | Wires the new SDK wire-types codegen gate into Versioning Checks. |
| .github/copilot-instructions.md | Updates repo conventions to reflect removal of -strict stable schemas and addition of generated SDK wire types. |
Copilot's findings
- Files reviewed: 12/13 changed files
- Comments generated: 2
|
Addressed both review comments in 74a22c0 (doc/label accuracy, no behavior change):
|
|
To generate typescript types from the rust types should we be using https://crates.io/crates/ts-rs ? |
74a22c0 to
122aa69
Compare
122aa69 to
c2fa61b
Compare
This PR changes the SDK's wire TypeScript types to be generated from the Rust wire model by a hand-written emitter (no third-party generator), guarded by a conformance test and a CI gate so they cannot drift, and retires the hand-maintained 0.5.0-alpha-strict stable schema view. This closes the third versioning drift surface: a wire-model change ripples to the Rust model, the JSON schema, and the SDK types, or it fails CI. Details: - Add wxc_common::ts_emit, a Rust emitter that walks the generated schema value and emits TypeScript (string-union enums, closed/open objects, $ref, anyOf [T, null], arrays, scalars). Refactor wire.rs so the JSON-schema renderer and the new generate_sdk_types_ts() share a schema_value() helper; the JSON schema output stays byte-for-byte identical. - Add a --ts mode to mxc_schema_gen that emits the committed sdk/src/generated/wire.ts (an internal drift oracle, not public API). - Add sdk/tests/unit/wire-conformance.test.ts: compile-time assertions that sdk/src/types.ts conforms to the generated wire shape - bidirectional and exact (public/wire field rename/removal, wire-only field additions, and enum narrowing and widening), at the root and every leaf, with each intentional divergence pinned to a documented allow-list. - Add scripts/versioning/check-sdk-types-codegen.js, a CI gate that runs the emitter and diffs the committed wire.ts (mirrors check-schema-codegen.js); wire it into the Versioning Checks job. No new npm or cargo dependency. - Retire schemas/stable/mxc-config.schema.0.5.0-alpha-strict.json and update the doc references (sdk/README.md, docs/schema-codegen.md, copilot-instructions.md). Tests: - cargo test --workspace; cargo fmt --all -- --check; cargo clippy --workspace --all-targets -- -D warnings; ts_emit unit tests. - Schema codegen, SDK wire-types codegen, and config corpus (169/169) gates. - cd sdk && npm test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Generated-with: claude-opus-4.8
c2fa61b to
ab4b36b
Compare
| @@ -1,250 +0,0 @@ | |||
| { | |||
| "$schema": "http://json-schema.org/draft-07/schema#", | |||
There was a problem hiding this comment.
note: we'll need to update the sdk readme
Line 60 in e1d1e4c
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| // SDK wire-types codegen gate (Phase 2C, option C): the committed |
There was a problem hiding this comment.
note: we should probably remove mentions of the phases and options from the comments.
| * WSL container backend config. | ||
| */ | ||
| wslc?: Wslc | null; | ||
| [k: string]: unknown; |
There was a problem hiding this comment.
question: what's this for?
| The SDK's wire TypeScript types are generated too — by a **Rust emitter**, with | ||
| no third-party generator. `mxc_schema_gen --ts` walks the same generated schema |
There was a problem hiding this comment.
question: I'm still wondering why we can't have a third party generator? Wouldn't that ease our maintenance burden here? To be honest thinking about it, it makes a lot of sense if the types we expose in type script are generated from the wire rust code. I'm trying to think of a reason why we wouldn't want to do that but can't. Would be great if us devs only need to run a script to update the typescript types and then check in the changes.
side note: I wonder if we should have just used flatbuffers for our schema. It allows json conversion between the flatbuffer schema and json. Just wondering since that would have done the work for us in generating both rust types and typescript types without us making anything new.
Summary
Phase 2C of the versioning remediation. Closes the third drift surface - the Rust wire model, the generated JSON schema, and the SDK TypeScript types - by emitting the SDK wire types from a hand-written Rust emitter (
wxc_common::ts_emit, exposed viamxc_schema_gen --ts) with no new npm or cargo dependency, asserting the hand-written public types conform to them, and retiring the hand-maintained0.5.0-alpha-strictstable schema view.A wire-model change now ripples to all three surfaces or fails CI; it cannot drift silently.
What changed
src/core/wxc_common/src/ts_emit.rswalks the generated schema value and emitssdk/src/generated/wire.ts(an internal drift oracle, not public API).wire.rsis refactored to share aschema_value()helper; the JSON schema output stays byte-for-byte identical.mxc_schema_gen --tsmode emits the committed TS; the existing schema mode is unchanged.sdk/tests/unit/wire-conformance.test.tsasserts (attsctime) thatsdk/src/types.tsconforms to the generated wire shape - bidirectional and exact: catches public/wire field rename/removal, wire-only field additions the SDK forgot to expose, and enum narrowing and widening, at the root and every leaf. Every intentional divergence is pinned to a documented allow-list.scripts/versioning/check-sdk-types-codegen.jsruns the emitter and diffs the committedwire.ts(mirrorscheck-schema-codegen.js); wired into the Versioning Checks job.schemas/stable/mxc-config.schema.0.5.0-alpha-strict.jsonand updates the three doc references.Review
Converged through two independent, model-diverse adversarial review loops (GPT-5.3-Codex and GPT-5.5) before this PR; the bidirectional/exact conformance design is the result of findings from both.
Verification
cd sdk && npm test-> 181 pass (incl. the conformance oracle)cargo test -p wxc_common --features schema-gen ts_emit-> 3 pass; clippy + fmt cleannode scripts/versioning/check-sdk-types-codegen.js-> OKnode scripts/versioning/check-schema-codegen.js-> OK (schema byte-identical)node scripts/versioning/validate-configs.js-> 169/169Follow-up (non-blocking)
A companion conformance block for the state-aware public types (
sdk/src/state-aware-types.tsvs theIsolationSession*wire defs), flagged by both reviewers.Microsoft Reviewers: Open in CodeFlow