Skip to content

Phase 2C: generate the SDK wire types from a Rust emitter#559

Open
MGudgin wants to merge 1 commit into
user/gudge/versioning_phase2bfrom
user/gudge/versioning_phase2c_optC_rustemit
Open

Phase 2C: generate the SDK wire types from a Rust emitter#559
MGudgin wants to merge 1 commit into
user/gudge/versioning_phase2bfrom
user/gudge/versioning_phase2c_optC_rustemit

Conversation

@MGudgin

@MGudgin MGudgin commented Jun 24, 2026

Copy link
Copy Markdown
Member

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 via mxc_schema_gen --ts) with no new npm or cargo dependency, asserting the hand-written public types conform to them, and retiring the hand-maintained 0.5.0-alpha-strict stable schema view.

A wire-model change now ripples to all three surfaces or fails CI; it cannot drift silently.

What changed

  • Rust emitter src/core/wxc_common/src/ts_emit.rs walks the generated schema value and emits sdk/src/generated/wire.ts (an internal drift oracle, not public API). wire.rs is refactored to share a schema_value() helper; the JSON schema output stays byte-for-byte identical.
  • mxc_schema_gen --ts mode emits the committed TS; the existing schema mode is unchanged.
  • Conformance test sdk/tests/unit/wire-conformance.test.ts asserts (at tsc time) that sdk/src/types.ts conforms 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.
  • CI gate scripts/versioning/check-sdk-types-codegen.js runs the emitter and diffs the committed wire.ts (mirrors check-schema-codegen.js); wired into the Versioning Checks job.
  • Retires schemas/stable/mxc-config.schema.0.5.0-alpha-strict.json and 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 clean
  • node scripts/versioning/check-sdk-types-codegen.js -> OK
  • node scripts/versioning/check-schema-codegen.js -> OK (schema byte-identical)
  • node scripts/versioning/validate-configs.js -> 169/169

Follow-up (non-blocking)

A companion conformance block for the state-aware public types (sdk/src/state-aware-types.ts vs the IsolationSession* wire defs), flagged by both reviewers.

Microsoft Reviewers: Open in CodeFlow

Copilot AI review requested due to automatic review settings June 24, 2026 19:00
@MGudgin MGudgin requested a review from a team as a code owner June 24, 2026 19:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 via mxc_schema_gen --ts.
  • Add a compile-time conformance oracle test in the SDK plus a CI codegen gate to prevent wire.ts drift.
  • Retire the legacy hand-maintained 0.5.0-alpha-strict stable 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

Comment thread src/core/wxc_common/src/ts_emit.rs Outdated
Comment thread .github/workflows/Versioning.Checks.Job.yml Outdated
@MGudgin

MGudgin commented Jun 24, 2026

Copy link
Copy Markdown
Member Author

Addressed both review comments in 74a22c0 (doc/label accuracy, no behavior change):

  • ts_emit.rs module doc reworded so the serde_json::Value is described as built from the MxcConfig wire model (the same value generate_config_schema_json renders to JSON text), not produced by that String-returning function.
  • Versioning Checks step renamed to ...in sync with the Rust wire model... to match the sibling schema-codegen step and reflect that the gate regenerates wire.ts from the wire model via mxc_schema_gen --ts.

@bbonaby

bbonaby commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

To generate typescript types from the rust types should we be using https://crates.io/crates/ts-rs ?

@MGudgin MGudgin force-pushed the user/gudge/versioning_phase2c_optC_rustemit branch from 74a22c0 to 122aa69 Compare June 25, 2026 04:17
@MGudgin MGudgin changed the base branch from main to user/gudge/versioning_phase2b June 25, 2026 04:17
@MGudgin MGudgin force-pushed the user/gudge/versioning_phase2c_optC_rustemit branch from 122aa69 to c2fa61b Compare June 25, 2026 14:19
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
@MGudgin MGudgin force-pushed the user/gudge/versioning_phase2c_optC_rustemit branch from c2fa61b to ab4b36b Compare June 25, 2026 16:49
@@ -1,250 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: we'll need to update the sdk readme

| `0.5.0-alpha` (strict) | Stable, non-experimental surface only | [`schemas/stable/mxc-config.schema.0.5.0-alpha-strict.json`](https://github.com/microsoft/mxc/blob/main/schemas/stable/mxc-config.schema.0.5.0-alpha-strict.json) |
to remove the link to this file.

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

// SDK wire-types codegen gate (Phase 2C, option C): the committed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: we should probably remove mentions of the phases and options from the comments.

Comment thread sdk/src/generated/wire.ts
* WSL container backend config.
*/
wslc?: Wslc | null;
[k: string]: unknown;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: what's this for?

Comment thread docs/schema-codegen.md
Comment on lines +107 to +108
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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants