Skip to content

Use wxc-exec --probe for MXC host support; bump mxc-sdk to 0.7.0 - #776

Merged
shanselman merged 6 commits into
openclaw:masterfrom
bkudiess:bkudiess/fictional-chainsaw
Jun 21, 2026
Merged

Use wxc-exec --probe for MXC host support; bump mxc-sdk to 0.7.0#776
shanselman merged 6 commits into
openclaw:masterfrom
bkudiess:bkudiess/fictional-chainsaw

Conversation

@bkudiess

@bkudiess bkudiess commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Why

We were pinned to @microsoft/mxc-sdk@0.6.1 and gating MXC sandbox availability with a hardcoded Windows build/UBR table (build == 26300 && UBR >= 8289) — the one carrying a TODO: this is all temporary; feature gate this correctly ASAP. That table was already producing false negatives on current Windows builds (verified: build 26632 was wrongly rejected, even though wxc-exec --probe reports it fully supported at the best base-container tier).

The SDK already ships the right answer: the native wxc-exec --probe command returns {"tier", "needsDaclAugmentation", "warnings"} with exit 0 when the host can run the sandbox. This PR switches to that, bumps the SDK, and adopts the renamed config schema field.

What changed

  • Probe-based availability. MxcAvailability.Probe() resolves wxc-exec.exe, runs wxc-exec --probe, and parses the JSON to decide support — replacing the build/UBR table (and removing the stale TODO + registry read). So newer Windows builds light up with no code change.
  • Bump @microsoft/mxc-sdk ^0.6.1 -> ^0.7.0 + refreshed lockfile.
  • Rename config wire key appContainer -> processContainer to match the 0.7.0 schema (old name is now a deprecated alias). Updated the config model, builder, executor log, the 4 golden fixtures, and tests.
  • Off-UI-thread probe. SandboxPage probes on a background thread (renders a neutral "Checking…" state) and the failure-mode branch no longer string-matches reason text.

Robustness (incorporates three review passes: code-review, GPT-5.5 rubber-duck, and a dual-model Opus+Codex adversarial review)

  • Probe error vs. unsupported host. Probe attempts are classified WxcProbeStatus {Completed, TimedOut, LaunchFailed} and outcomes MxcProbeOutcome {Supported, UnsupportedHost, ProbeError}. A transient error (timeout / failed launch / garbled output) is distinguished from a definitive "host unsupported" verdict, and surfaced as MxcAvailability.ProbeErrored.
  • Self-healing without pinning uncontained. Definitive verdicts are cached for the process lifetime; a transient error is re-probed. DirectAppContainerExecutor resolves availability lazily per call (a frozen snapshot would pin a startup glitch to uncontained for the executor's lifetime even after recovery).
  • No blocking probe under a lock. NodeService.GetOrProbeMxcAvailability runs the ~15s probe via a single-flight shared task and waits on it outside the availability lock; capability registration uses a non-blocking peek so it never stalls on _capabilitiesLock. The retry window opens only after a probe completes (no back-to-back re-probe when timeout > retry interval).
  • Bounded probe spawn. RunWxcExecProbe bounds the stdout/stderr drain with the remaining timeout budget (not just process exit), so a handle-inheriting descendant (the SDK ships sandbox daemon/guest helpers) can't hang the probe; abandoned reads are observed on the kill path.
  • Degraded isolation tier. IsolationTier / NeedsDaclAugmentation / IsDegradedContainment are exposed. A weaker tier (appcontainer-dacl) is accepted-but-flagged (the Sandbox page shows a "limited containment" caution) rather than blocked — refusing would drop the host to fully uncontained, which is strictly worse.
  • Sandbox page never gets stuck. A probe error shows "Couldn't verify sandbox availability" with a Retry; an unexpected probe fault is caught and re-rendered so the page can't hang in "Checking…".

Validation

  • ./build.ps1 — all projects incl. WinUI (0.7.0 restored, wxc-exec ship-validated)
  • Shared tests — 2064 passed / 0 failed (probe status/outcome classification, ProbeErrored, degraded-tier, lazy-executor recovery, bounded-probe)
  • Tray tests — 958 passed / 0 failed

🤖 Authored with Copilot CLI.

Copilot and others added 3 commits June 17, 2026 15:48
Replace the hardcoded Windows build/UBR support gate (build 26300,
UBR 8289) in MxcAvailability with the native `wxc-exec --probe`
result, so newer Windows builds light up without a code change. The
old table was already producing false negatives on current builds
(e.g. 26632).

- MxcAvailability.Probe resolves wxc-exec, runs `wxc-exec --probe`,
  and parses the JSON {tier, needsDaclAugmentation, warnings} to
  decide support. Adds a test seam (Probe(logger, probeRunner)), a
  pure ParseProbeOutput, and a bounded RunWxcExecProbe.
- RunWxcExecProbe bounds the stdout/stderr drain with the remaining
  timeout budget (not just process exit) so a handle-inheriting
  descendant cannot hang Probe(); abandoned reads are observed on kill.
- SandboxPage probes off the UI thread and shows a neutral "checking"
  state until it resolves; the Windows-vs-setup branch no longer
  string-matches reason text.
- Bump @microsoft/mxc-sdk ^0.6.1 -> ^0.7.0 and refresh the lockfile.
- Rename the config wire key appContainer -> processContainer to match
  the 0.7.0 schema (old name is a deprecated alias); update goldens.

Validated: build.ps1, Shared tests (2052), Tray tests (958).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Follow-ups to the probe-based availability change, addressing two
review concerns.

#2 Probe error vs. unsupported host:
- ParseProbeOutput now classifies into MxcProbeOutcome {Supported,
  UnsupportedHost, ProbeError}. A negative exit (our timeout/launch
  sentinel) or exit 0 with no usable output is a transient ProbeError;
  a positive non-zero exit is a definitive UnsupportedHost.
- MxcAvailability exposes ProbeErrored. NodeService caches definitive
  verdicts for the process lifetime but re-probes (throttled, 5s) after
  a transient error, so a momentary glitch self-heals instead of pinning
  the whole process to uncontained execution. Keeps the issue openclaw#494
  fall-back-to-host policy. SandboxPage likewise re-probes an errored
  cache on next init.

#3 Degraded isolation tier:
- MxcAvailability exposes IsolationTier, NeedsDaclAugmentation, and a
  derived IsDegradedContainment (true for appcontainer-dacl, DACL
  augmentation, or an unrecognized tier). Any non-empty tier is still
  accepted as contained — refusing would drop the host to fully
  uncontained, which is strictly worse — but SandboxPage now surfaces a
  "limited containment" caution.

Adds unit coverage for outcome classification, ProbeErrored propagation,
and degraded-tier detection. Validated: build.ps1, Shared (2062), Tray (958).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses a GPT-5.5 rubber-duck pass on the probe-error/tier changes.

- Fix self-heal bug (#1): DirectAppContainerExecutor took a frozen
  MxcAvailability snapshot, so a transient startup probe error pinned
  system.run to uncontained for the executor's lifetime even after the
  host recovered (the re-probe updated the runner's gate but not the
  executor, which then threw SandboxUnavailableException on every call).
  The executor now resolves availability lazily via Func<MxcAvailability>.

- Explicit probe status (#3): WxcProbeInvocation carries a WxcProbeStatus
  {Completed, TimedOut, LaunchFailed} instead of overloading exit code -1
  as a sentinel. ParseProbeOutput only inspects the exit code for a
  Completed run, so a real native (possibly negative) exit code can't be
  misread as our timeout/launch sentinel.

- Serialize probing (#2): NodeService.GetOrProbeMxcAvailability is now
  guarded by a lock and sets the retry timestamp before probing, so
  concurrent system.run calls can't spawn a storm of wxc-exec --probe
  processes during a slow/timeout probe.

- SandboxPage (openclaw#7): a transient probe error is no longer mislabeled as
  "your Windows version doesn't support sandboxing" — it shows
  "Couldn't verify sandbox availability" with a Retry that re-probes.
  Added an in-flight guard so refresh can't start overlapping probes.

Tests: lazy-resolution recovery (errored -> recovered picks up), status
classification (timeout/launch ignore exit code; completed-nonzero =
unsupported), updated injected-probe and golden tests. Validated:
build.ps1, Shared (2064), Tray (958).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@clawsweeper

clawsweeper Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed June 21, 2026, 2:57 AM ET / 06:57 UTC.

Summary
The branch replaces hardcoded MXC Windows build/UBR availability with wxc-exec --probe, bumps @microsoft/mxc-sdk to 0.7.0, renames the generated config key to processContainer, defers probing off UI/locks, and expands MXC tests.

Reproducibility: yes. from source inspection: current main rejects every Windows build other than 26300 before consulting the native SDK probe. I did not reproduce the Windows host behavior in this Linux checkout.

Review metrics: 3 noteworthy metrics.

  • Changed Surface: 20 files, +985/-149. The diff spans runtime sandbox probing, npm dependency state, WinUI availability UX, and tests, so upgrade behavior matters before merge.
  • Runtime Dependency Bump: 1 direct npm dependency updated. @microsoft/mxc-sdk supplies the copied wxc-exec.exe binary, so restore freshness affects runtime behavior.
  • Related MXC Work: 3 open related items. The open tracking issue and validation/proof PRs mean maintainers need to reconcile competing MXC availability strategies.

Root-cause cluster
Relationship: partial_overlap
Canonical: #784
Summary: This PR overlaps the MXC SDK 0.7.0 and Windows-build availability work tracked by the open validation issue, but it is an alternate probe-based approach rather than the canonical staged stack.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted Windows proof showing wxc-exec --probe and contained system.run or SandboxPage behavior; redact private paths, endpoints, tokens, and other private data.
  • Make the MXC SDK restore/copy path version-aware before copying wxc-exec.exe.
  • Ask maintainers to choose how this probe-based PR should relate to the open Windows 25H2 validation stack.

Proof guidance:

  • [P1] Needs real behavior proof before merge: Missing: the PR body lists validation counts but does not attach redacted terminal output, logs, screenshot, recording, or a linked artifact showing after-fix wxc-exec --probe plus contained system.run or SandboxPage behavior. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A Windows terminal or desktop proof would materially verify the changed probe and sandbox behavior that unit tests cannot show in this checkout. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: show wxc-exec --probe succeeding on a Windows build current main rejects, then show SandboxPage or system.run using contained MXC execution.

Risk before merge

  • [P1] Existing or persistent build worktrees with @microsoft/mxc-sdk 0.6.1 installed can skip npm ci and copy stale wxc-exec.exe after this PR changes the dependency and generated config shape.
  • [P1] The PR body has validation claims but no inspectable after-fix Windows proof showing wxc-exec --probe and contained system.run or SandboxPage behavior.
  • [P1] The open Windows 25H2 validation issue and overlapping validation/proof PRs propose a different explicit build-table stack, so maintainers need to choose the canonical MXC availability strategy before landing competing branches.

Maintainer options:

  1. Fix Restore Freshness Before Merge (recommended)
    Update the MSBuild/npm restore path so it reruns or fails when the installed @microsoft/mxc-sdk version differs from the requested package version before copying wxc-exec.exe.
  2. Pause For Proof And Direction
    Keep the PR paused until redacted Windows runtime proof is attached and maintainers decide whether this probe-based path or the explicit validation-table stack is canonical.
  3. Accept Fresh-Worktree Assumption
    Maintainers can accept the risk only if release and developer builds are guaranteed to restore from a fresh node_modules before packaging the MXC runtime.

Next step before merge

  • [P1] Contributor proof and maintainer direction on the overlapping MXC validation stack are required before automation should touch the branch.

Security
Cleared: The diff is security-sensitive because it changes sandbox availability and the MXC runtime dependency, but I found no concrete secret, permission, or supply-chain regression beyond the compatibility and proof blockers called out separately.

Review findings

  • [P2] Make the MXC restore target detect SDK version drift — package.json:7
Review details

Best possible solution:

Land one maintainer-chosen MXC 0.7 availability path with version-aware SDK restore and redacted Windows proof for wxc-exec --probe plus contained system.run or SandboxPage behavior.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: current main rejects every Windows build other than 26300 before consulting the native SDK probe. I did not reproduce the Windows host behavior in this Linux checkout.

Is this the best way to solve the issue?

No as submitted. Probe-based availability is plausible, but the restore path needs version-awareness, live Windows proof is still missing, and maintainers need to reconcile this with the overlapping explicit validation stack.

Full review comments:

  • [P2] Make the MXC restore target detect SDK version drift — package.json:7
    This bumps @microsoft/mxc-sdk to ^0.7.0, but RestoreMxcNodeBridge still runs npm ci only when node_modules/@microsoft/mxc-sdk/package.json is absent. Existing build worktrees with 0.6.1 installed can skip restore and copy a stale wxc-exec.exe while this PR emits the 0.7 processContainer config shape, so compare the installed package version to the requested version or force restore before copying.
    Confidence: 0.87

Overall correctness: patch is incorrect
Overall confidence: 0.87

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2153c7e7d3a1.

Label changes

Label justifications:

  • P2: This is a normal-priority sandbox compatibility improvement with bounded but user-visible upgrade and proof blockers.
  • merge-risk: 🚨 compatibility: Merging the SDK/config update without version-aware restore can leave existing build worktrees using an old MXC binary with the new config shape.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Missing: the PR body lists validation counts but does not attach redacted terminal output, logs, screenshot, recording, or a linked artifact showing after-fix wxc-exec --probe plus contained system.run or SandboxPage behavior. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

What I checked:

Likely related people:

  • bkudiess: Prior merged MXC work introduced the AppContainer sandboxing and direct wxc-exec runtime surfaces that this branch changes. (role: feature owner; confidence: high; commits: 62533e2901bd, cf611d4ab59f; files: package.json, package-lock.json, src/OpenClaw.Shared/Mxc/MxcAvailability.cs)
  • shanselman: Recent MXC history restricted the support gate, added preflight diagnostics, and guarded wxc-exec packaging in the same runtime area. (role: recent area contributor; confidence: high; commits: f52b829a6f3c, 8717e8242944, fa3cf0f164c6; files: src/OpenClaw.Shared/Mxc/MxcAvailability.cs, src/OpenClaw.Shared/Mxc/MxcCommandRunner.cs, src/OpenClaw.Tray.WinUI/OpenClaw.Tray.WinUI.csproj)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jun 17, 2026
Copilot and others added 2 commits June 18, 2026 11:37
…page

Addresses a dual-model (Opus + Codex) adversarial review of the
probe-based availability work.

- Never run the blocking wxc-exec --probe (~15s) while holding a lock.
  GetOrProbeMxcAvailability now starts/joins a single shared in-flight
  probe Task and waits on it OUTSIDE _mxcAvailabilityLock, so concurrent
  system.run calls no longer serialize behind the lock and can't spawn a
  probe storm. The retry window opens only AFTER a probe completes, so a
  15s timeout can't immediately permit a back-to-back re-probe (fixes the
  throttle-collapse where timeout 15s > retry 5s).

- Don't probe inside _capabilitiesLock. BuildSystemRunRunner ran the
  blocking probe while RegisterCapabilities held _capabilitiesLock (the
  "held briefly" comment was no longer true), stalling capability
  registration / reconnect. It now logs from a non-blocking PeekMxcAvailability
  and defers the first real probe to the first system.run (off any lock).

- Don't leave the Sandbox page stuck in "Checking...". RefreshAvailabilityAsync
  now catches an unexpected Probe() fault (synthesizing a probe-errored
  result so Retry shows) and re-renders in a finally on both the happy and
  failure paths.

Not changed (disputed, needs product/contract decision): a completed
non-zero probe exit is still treated as definitive UnsupportedHost.

Validated: build.ps1, Shared (2064), Tray (958).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Drop now-obsolete archaeology (specific build/UBR numbers, 'old gate'
references) and an inaccurate process-lifetime caching note from the
availability/probe comments. No behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​microsoft/​mxc-sdk@​0.6.1 ⏵ 0.7.081100100 +194 +1100

View full report

Treat indeterminate probe failures as retryable unless structured probe JSON explicitly reports an unsupported host. Skip availability probing entirely when the sandbox toggle is off.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@shanselman
shanselman merged commit d86a96c into openclaw:master Jun 21, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants