Repository navigation
Complete V1.Dev exact-JSON SDK APIs - #1412
Gudge (MGudgin) wants to merge 1 commit into
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
32b5ee3 to
60a7dbc
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved timeout handling can hang captured execution or misreport PTY outcomes.
Review effort: Balanced
Findings: 2
Open (5)
Close output readers when isolation execution times out · New Timeout leaves output collectors waiting indefinitely · New Route historical appcontainer alias through wxc-exec · New Preserve timeout outcomes for executor-backed processes · New Prevent cleanup errors from masking output read failures · New
What changed in this PR
Adds V1.Dev exact-JSON APIs alongside the typed Rust, .NET, and Node SDKs, preserving caller-declared contract versions and separate experimental authorization.
Changes:
- Adds capture, pipe, PTY, lifecycle, and validation operations.
- Routes Node ProcessContainer PTY requests through
wxc-execunchanged. - Adds tests and documents signatures, ownership, and platform limitations.
| File | Description |
|---|---|
| src/mxc-sdk/tests/state_aware.rs | Checks public Rust dev signatures and routing. |
| src/mxc-sdk/src/lib.rs | Exports the versioned dev module. |
| src/mxc-sdk/src/dev/state_aware.rs | Adds lifecycle and existing-container APIs. |
| src/mxc-sdk/src/dev/one_shot.rs | Adds one-shot execution APIs. |
| src/mxc-sdk/src/dev.rs | Defines exports and invocation options. |
| src/mxc-sdk/README.md | Introduces Rust exact-JSON APIs. |
| sdk/node/tests/unit/v1-dev.test.ts | Tests forwarding, validation, and capture. |
| sdk/node/tests/unit/state-aware-binding.test.ts | Tests missing native responses. |
| sdk/node/tests/unit/process-container-pty.test.ts | Tests unchanged JSON transport. |
| sdk/node/tests/integration/dev.test.ts | Checks native contract rejection. |
| sdk/node/tests/integration/dev-api.ts | Checks packaged dev signatures. |
| sdk/node/src/v1/dev/index.ts | Implements Node dev operations. |
| sdk/node/src/bindings/streaming.ts | Adds raw-JSON pipe spawning. |
| sdk/node/src/bindings/state-aware.ts | Rejects missing response JSON. |
| sdk/node/src/bindings/run.ts | Adds raw-JSON capture binding. |
| sdk/node/src/bindings/pty.ts | Adds raw-JSON PTY binding. |
| sdk/node/src/bindings/process-container-pty.ts | Accepts original JSON for executor launches. |
| sdk/node/README.md | Introduces Node dev APIs. |
| sdk/node/package.json | Exports dev APIs and registers tests. |
| sdk/dotnet/README.md | Introduces .NET dev APIs. |
| sdk/dotnet/Microsoft.Mxc.Sdk/V1/Dev/MxcLifecycle.cs | Adds lifecycle and existing-container APIs. |
| sdk/dotnet/Microsoft.Mxc.Sdk/V1/Dev/MxcContainer.cs | Adds one-shot execution APIs. |
| sdk/dotnet/Microsoft.Mxc.Sdk/V1/Dev/JsonOptions.cs | Defines authorization and PTY options. |
| sdk/dotnet/Microsoft.Mxc.Sdk/V1/Dev/DevJsonRequest.cs | Checks phases and encodes requests. |
| sdk/dotnet/Microsoft.Mxc.Sdk.Tests/DevEntryPointTests.cs | Tests dev validation and signatures. |
| docs/versioning.md | Explains exact-JSON version selection. |
| docs/reference/rust/v1/README.md | Links Rust dev reference. |
| docs/reference/rust/v1/dev.md | Documents Rust dev APIs. |
| docs/reference/rust/v1/api.md | Distinguishes typed and dev surfaces. |
| docs/reference/README.md | Links cross-SDK dev references. |
| docs/reference/node/v1/README.md | Links Node dev reference. |
| docs/reference/node/v1/dev.md | Documents Node APIs and executor limitations. |
| docs/reference/node/v1/api.md | Distinguishes typed and dev surfaces. |
| docs/reference/dotnet/v1/README.md | Links .NET dev reference. |
| docs/reference/dotnet/v1/dev.md | Documents .NET APIs and cancellation behavior. |
| docs/reference/dotnet/v1/api.md | Distinguishes typed and dev surfaces. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The cross-SDK API expansion involves native interop, PTY routing, and lifecycle ownership that warrant final human review.
Review effort: Balanced
Findings: 2
Open (6)
Timeout leaves output collectors waiting indefinitely Close output readers when isolation execution times out Set JSON inspection MaxDepth to match native parser limit · New Prevent cleanup errors from masking output read failures Preserve timeout outcomes for executor-backed processes Route historical appcontainer alias through wxc-exec
60a7dbc to
1687a1d
Compare
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Cross-SDK native-handle ownership and unresolved Windows timeout capture require platform-specific maintainer validation.
Review effort: Balanced
Findings: 1
Open (1)
Resolved since last review (6)
Timeout leaves output collectors waiting indefinitely Close output readers when isolation execution times out Set JSON inspection MaxDepth to match native parser limit Prevent cleanup errors from masking output read failures Preserve timeout outcomes for executor-backed processes Route historical appcontainer alias through wxc-exec
1687a1d to
25604e2
Compare
25604e2 to
15dd178
Compare
15dd178 to
3d92de7
Compare
| ExecutionResult RunJson(string json, JsonOptions? options = null); | ||
| Task<ExecutionResult> RunJsonAsync(string json, JsonOptions? options = null, | ||
| CancellationToken cancellationToken = default); | ||
| MxcProcess SpawnJson(string json, JsonOptions? options = null); |
There was a problem hiding this comment.
I'm trying to reason over the overall design.
Is it a normal SDK pattern to have a complete a ::dev:: namespace that duplicates the API surface for active development?
Could it be something like,
- "dev" namespace just contains a request object (new
ContainerRequestDevthat just holds the json string) - Change the real
SpawnAPI to accept an interface,IContainerRequest
?
There was a problem hiding this comment.
that way there's only one Spawn function and it's easier for consumer to migrate code from "dev" to stable
There was a problem hiding this comment.
Thanks for raising the migration ergonomics. The separate V1.Dev surface is intentional: typed V1 Spawn(ContainerRequest) emits the SDK-owned published contract with no experimental opt-in, while SpawnJson preserves the caller-authored exact version and takes backend authorization separately. An IContainerRequest overload would mix those contracts in the stable facade, and it would not address lifecycle calls whose JSON owns the phase/id and whose response can contain evolving metadata. The one-shot result and process-handle types are already shared. Moving a promoted feature to typed V1 still requires converting the request fields; sharing the Spawn name would not remove that step. I would keep explicit *Json operations in this PR and consider a cross-SDK convenience surface separately if migration friction warrants it.
|
consider: adding a sample to /samples/ folder |
3d92de7 to
e5265e4
Compare
e5265e4 to
4f1c892
Compare
4f1c892 to
a44a4fb
Compare
a44a4fb to
3bee51e
Compare
3bee51e to
a2073a3
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Node’s phase guard permits duplicate declarations to reach native dispatch, contrary to the stated phase-before-dispatch behavior.
9 open findings
Reject duplicate phase keys before native dispatch · New Use create-and-run execution terminology in API reference · New Use container lifecycle operations terminology · New Use contract parser terminology in consumer documentation · New Use container lifecycle support terminology · New Use create-and-run terminology in .NET documentation · New Use create-and-run execution terminology in public JSDoc · New Use create-and-run execution terminology in README · New Use create-and-run execution terminology in Rust documentation · New
🧠 Review effort: Balanced
| if (!isRecord(request)) { | ||
| throw new MxcError('malformed_request', `${name} requires a JSON object`); | ||
| } | ||
| if (phase === undefined ? Object.hasOwn(request, 'phase') : request.phase !== phase) { |
| workload to exit. The Node ProcessContainer one-shot PTY route | ||
| passes the original UTF-8 JSON through `wxc-exec --config-base64`, including |
| The separate [V1.Dev exact-JSON API](dev.md) accepts caller-authored requests | ||
| for one-shot execution and state-aware lifecycle operations. |
| takes a second container ID. Invalid versions, unknown fields, and malformed | ||
| JSON are rejected by the exact contract parser. |
|
|
||
| Capture uses pipe-backed execution: a backend without piped execution | ||
| rejects this mode with `UnsupportedContainment` even when experimental | ||
| access is authorized. PTY and state-aware support also depend on the |
|
|
||
| namespace Microsoft.Mxc.Sdk.V1.Dev; | ||
|
|
||
| /// <summary>One-shot caller-authored exact-JSON entry points.</summary> |
| }); | ||
| } | ||
|
|
||
| /** Capture a one-shot request. */ |
| V1.Dev runs caller-authored exact-version requests in-process. It provides | ||
| one-shot and existing-container capture, pipe and PTY spawns, lifecycle | ||
| operations, and dry-run validation. Lifecycle calls return the complete |
| /// Run a caller-authored exact-version one-shot request to completion and capture its output. | ||
| /// | ||
| /// The registered `version` and one-shot request root are parsed by the engine | ||
| /// without stamping or reserializing the input. `options.experimental` only | ||
| /// authorizes an experimental backend; it does not select a contract version. |
|
should we take in these last copilot comments? They look like good doc updates |
a2073a3 to
d04e12f
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Successful Dev execution and lifecycle flows still need real-backend functional coverage in the scheduled SDK validation suites.
10 open issues
Reject duplicate phase keys before native dispatch Add successful V1.Dev lifecycle scenarios to scheduled SDK suites · New Use create-and-run execution terminology in Rust documentation Use create-and-run execution terminology in README Use create-and-run execution terminology in public JSDoc Use create-and-run terminology in .NET documentation Use container lifecycle support terminology Use contract parser terminology in consumer documentation Use container lifecycle operations terminology Use create-and-run execution terminology in API reference
Review effort: Balanced
| const proc = await spawnStateAwareBindingSandboxProcessAsync( | ||
| json, options.experimental === true, timeoutMs, | ||
| ); |
This PR adds caller-authored exact-JSON execution and lifecycle APIs in the Rust, .NET, and Node SDKs. Requests retain their declared contract version while authorization and operation selection remain separate. Captured operations return partial output on timeout instead of waiting for inherited output pipes to close. Details * Publish capture, pipe, PTY, lifecycle, and validation entry points with native exact-contract routing and versioned SDK references. * Close timed-out .NET capture readers; settle Node captures without waiting for native stream close and reject read failures during process wait. * Preserve the original capture error if disposal fails; route the historical appcontainer PTY alias and accept deep annotations in .NET requests. * Keep .NET Dev options sealed and independent with reflection-free JSON and Native AOT smoke coverage. * Document and test exit-only timeout reporting for executor-backed PTYs. Tests * From src: cargo fmt --all -- --check; cargo clippy --workspace --all-targets -- -D warnings; cargo test -p mxc-sdk --lib dev::; cargo test -p mxc-sdk --test state_aware (passed). * From sdk\node: npm run typecheck --silent (passed); npm test --silent (458 passed, 21 skipped), including pending-read capture coverage. * .NET AOT smoke ran reflection-free; Native AOT publish and run passed; DevEntryPointTests and V1ApiSurfaceTests passed (12 total). Host-dependent IsolationSession workloads were skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f136b563-7d18-4c2e-8f86-43af66889e6a Generated-with: gpt-6-sol
d04e12f to
7906c27
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Successful V1.Dev execution and lifecycle scenarios still need host-backed functional coverage wired into scheduled CI.
11 open issues
Add CI-wired successful V1.Dev SDK lifecycle scenarios · New Reject duplicate phase keys before native dispatch Add successful V1.Dev lifecycle scenarios to scheduled SDK suites Use create-and-run execution terminology in Rust documentation Use create-and-run execution terminology in README Use create-and-run execution terminology in public JSDoc Use create-and-run terminology in .NET documentation Use container lifecycle support terminology Use contract parser terminology in consumer documentation Use container lifecycle operations terminology Use create-and-run execution terminology in API reference
Review effort: Balanced
| pub fn run_json(json: &str, options: JsonOptions) -> Result<ExecutionResult, Error> { | ||
| crate::__ffi::run_json(json, options.experimental) |



This PR adds caller-authored exact-JSON execution, lifecycle, and validation
APIs under V1.Dev in Rust, .NET, and Node. Each API retains the declared
contract version, keeps experimental authorization separate, and checks
lifecycle phases before dispatch.
Details
execution, plus lifecycle and dry-run validation. Existing V1 result and
handle ownership semantics are retained.
wxc-execwith the original JSON.Lifecycle and validation return the full native response JSON.
Node ProcessContainer PTY resolves when
wxc-execstarts, before its policyvalidation completes; its terminal channel cannot expose structured warnings
or output metadata. Node and .NET captured output is lossy UTF-8 text through
the existing ABI; Rust capture retains bytes.
Tests
src:cargo fmt --all -- --check(passed);cargo check -p mxc-sdk --lib --features isolation_session,wslc --quiet(passed);
cargo clippy --workspace --all-targets -- -D warnings(passed).src:cargo test -p mxc-sdk --lib dev:: --quiet(93 passed,1 host-gated);
cargo test -p mxc-sdk --test state_aware --quiet(16 passed);
cargo test -p mxc-sdk --lib --features isolation_session,wslc dev:: --quiet(93 passed, 1 host-gated).sdk\node:npm run typecheck(passed);npm test --silent(448 passed, 21 skipped).dotnet build sdk\dotnet\Microsoft.Mxc.Sdk.Tests\Microsoft.Mxc.Sdk.Tests.csproj --no-restore --nologo -v:q(passed);dotnet build sdk\dotnet\Microsoft.Mxc.Sdk.AotSmokeTest\Microsoft.Mxc.Sdk.AotSmokeTest.csproj --no-restore --nologo -v:q(passed).& sdk\dotnet\Microsoft.Mxc.Sdk.Tests\bin\Debug\net8.0\Microsoft.Mxc.Sdk.Tests.exe -class Microsoft.Mxc.Sdk.Tests.DevEntryPointTests(7 passed).& sdk\dotnet\Microsoft.Mxc.Sdk.Tests\bin\Debug\net8.0\Microsoft.Mxc.Sdk.Tests.exe -class Microsoft.Mxc.Sdk.Tests.V1.V1ApiSurfaceTests(3 passed).