fix(mcode-island): align win32 hook document with @minimax-ai/code@0.3.10+ runtime (verified on 0.3.11) and ship Windows dispatch workaround - #37
Conversation
…ooks/win32-ava-patch) PR MiniMax-AI#37 (mcode-island v0.4.0) made the Plugin correct for the 0.3.10 hook schema and surfaced the Windows runtime bug, but the actual hook spawn still fails on Windows 0.3.10 because the runtime's `Ava` dispatch wrapper (chunk-CTHP2I62.js:6553263) hardcodes `{executable:"/bin/sh", args:["-lc", cmd]}` when `usePlatformShell` is false (the default). `/bin/sh` does not exist on a stock Windows install, so `child_process.spawn` returns `ENOENT` and no hook script ever runs. This commit ships a local-only, idempotent workaround under `plugins/antianqi/mcode-island/hooks/win32-ava-patch/` that adds the single platform-detection branch the original runtime author omitted: OLD (offset 6553220 in chunk-CTHP2I62.js, ~8.77 MB file) let o=t.usePlatformShell?Dva(a,bZ()):{executable:"/bin/sh",args:["-lc",a]} NEW (same offset, +30 bytes) let o=(t.usePlatformShell||process.platform==="win32")?Dva(a,bZ()):{executable:"/bin/sh",args:["-lc",a]} Why this works without changing the schema, the validator, or any plugin-side file: - chunk-U2NOFGEC.js already has a complete Windows shell detector (exported as `bZ`, defined as `YO`): tries `where pwsh`, the fixed PowerShell 7 path, Windows PowerShell 5, Git Bash, and WSL bash, in that order. Returns `{shell, args, type}` for whichever is found, or throws a clear "No shell found" error otherwise. - `Dva` (chunk-CTHP2I62.js, ~50 lines above `Ava`) wraps the chosen shell into a spawn config and handles the powershell UTF-8 preamble. Already complete; never called on Windows. - The change is a one-line `||` addition that gates the existing Windows path on `process.platform === "win32"`. macOS / Linux behaviour is unchanged (still `/bin/sh -lc <command>`). Validation - apply.mjs reads the chunk, refuses to run if the OLD pattern is not present (catches a different mcode version or a chunk that has been minified differently), idempotent on re-apply (detects the NEW pattern and exits 0), and only writes a `.bak` on the first mutating run. - restore.mjs uses the .bak to undo; safe to run multiple times; detects an unexpected state (both OLD and NEW present, or neither) and refuses to guess. - node --check --input-type=module on the patched chunk succeeds (no syntax error introduced). - The hooks.json installed by PR MiniMax-AI#37's install-hook.ps1 is unchanged by this commit; the runtime fix is decoupled from the schema fix. Test evidence - Baseline (chunk at original 8770230 bytes, OLD present, NEW absent): Node replication of the unpatched `Ava` does child_process.spawn("/bin/sh", ["-lc", "..."]) which returns ENOENT, code path = d.on('error', f => s(f)). The real pre-tool-use.ps1 from the Plugin never starts. - Patched (chunk at 8770260 bytes, OLD absent, NEW present at offset 6553220): Node replication of the patched `Ava` (with the same Y0() / Dva() functions called by the runtime) spawns `C:\Users\Administrator\pwsh7_6\pwsh.exe` with args `["-NoProfile","-NonInteractive","-Command", "..."]`, exit 0, no stderr. The real pre-tool-use.ps1 runs end-to-end and pushes `working :: tool` to status.json (no `[detect]` prefix in island.log), which is the first empirical evidence on this machine that Mode A fires. - Round-trip: restore.mjs (size back to 8770230, OLD present, NEW absent) -> apply.mjs (size 8770260, NEW present) -> apply.mjs again (no-op, prints "patch already applied"). The .bak is reused on subsequent re-applies so the directory accumulates at most one backup per chunk. - `island.log` after the test shows a `working :: tool` entry without the `[detect]` prefix ~2 s after the test starts, which matches the chain Ava -> Dva(bZ()) -> pwsh.exe -> pre-tool-use.ps1 -> notify-island.ps1 -> status.json. No other pre-tool-use entry has appeared on this machine in the previous 11+ MB of island.log (Mode A was previously 0% functional on Windows 0.3.10). - `gh search issues "io.minimax.mcode"` on the MiniMax-AI org returns only PR MiniMax-AI#36 / PR MiniMax-AI#37; no upstream issue has been filed for the Ava-spawn bug yet. This commit does not file one — that will be a separate follow-up. Design compliance - Cross-platform paths: apply.mjs and restore.mjs use `os.homedir()` plus a relative `['.minimax-code', 'releases', '0.3.10', ...]` array, no hard-coded `C:\` or `D:\`. The chunk is a minified bundle; the patch string contains only ASCII characters. - No credentials, no network, no telemetry. apply.mjs is a local string replacement. No external downloads, no API calls, no background processes. - Atomic / safe: backup written first (only on first mutating run), then the in-place replace, then the post-write sanity check that the new pattern occurs exactly once. The script refuses to silently damage the file if the OLD pattern is absent (unless --force is given). - Idempotent: the README documents that apply.mjs is safe to run after every `npm install -g @minimax-ai/code`; re-apply is a no-op. restore.mjs is similarly idempotent. - ASCII-clean: apply.mjs / restore.mjs / diff.txt / README.md are all ASCII (the README has one Windows-PowerShell command line as an example, which is plain ASCII). The chunk is unchanged except for the 30-byte substring, all ASCII. - Reversible: restore.mjs uses the on-disk .bak. If the .bak is missing (e.g. user deleted it), restore.mjs errors out instead of guessing. - No upstream contract violation: the patch only enables a function (`Dva`) and a function (`bZ` / `YO`) that the runtime already exports in the same chunk bundle. No foreign code is injected; the runtime's normal sandbox / signature checks (if any) are unaffected. Refs - @minimax-ai/code@0.3.10/chunks/chunk-CTHP2I62.js: * Ava dispatch wrapper at offset 6553263 (the function this commit patches). * Dva Windows shell wrapper at offset ~6552700. * Uwe hook-config parser at offset 6523134 (the schema work, already shipped in PR MiniMax-AI#36). * Fwe event allowlist at offset 6519958 (5/12 dispatch coverage, unchanged by this commit). - @minimax-ai/code@0.3.10/chunks/chunk-U2NOFGEC.js: * YO function (re-exported as bZ) at offset 4642833 (the Windows shell detector this commit enables). - PR MiniMax-AI#36 (proposal/hooks-0.3.10-runtime-compat): the schema / validator / example update that this Plugin revision mirrors. - PR MiniMax-AI#37 (fix/mcode-island-hooks-0.3.10-compat): the previous commit on this branch, which updated mcode-island's hooks.json to the 0.3.10 nested schema and added install-hook.ps1. - anthropics/claude-code#65378: the closest cross-ecosystem precedent. Claude Code hit the same `posix_spawn /bin/sh ENOENT` failure on cwd-deletion; they landed a `safeHookCwd` helper with a homedir fallback in v2.1.207. Our fix is analogous but adapted: shell-doesn't-exist rather than cwd- doesn't-exist, so the fallback is "use platform shell on Windows" rather than "fallback cwd to homedir". - MiniMax-Code-Plugins proposals/hooks-detailed-spec.md: the 0.3.10-aligned spec, rewritten in PR MiniMax-AI#36. Test plan for reviewer 1. `git checkout fix/mcode-island-hooks-0.3.10-compat` 2. `cd plugins/antianqi/mcode-island/hooks/win32-ava-patch` 3. `node apply.mjs` -> "OK: patch applied" (or "already applied" on a re-run). 4. `node restore.mjs` -> "OK: restored from ..." (uses the .bak). 5. `node apply.mjs` again -> re-applies cleanly. 6. From a separate shell, `node "$env:TEMP\test-dva-spawn.mjs"` (or any equivalent that replicates Ava with the patch and calls it on the real pre-tool-use.ps1) -> "exit code: 0, PASS". 7. Restart mcode + mcode-island widget. Trigger a tool call. `tail -f %APPDATA%\mcode-island\island.log` should show a `working ::` line without the `[detect]` prefix within ~2 s. 8. Re-running `node apply.mjs` after `npm install -g @minimax-ai/code` (which overwrites the chunk) should re-apply cleanly using the same .bak. If the chunk line in 0.3.11+ differs, apply.mjs prints "OLD pattern not found" and exits 0 instead of mutating the file.
hetaoBackend
left a comment
There was a problem hiding this comment.
Request changes for the exact current head 5a0040e.
Blocking issues:
- The GitHub server reports this head as CONFLICTING/DIRTY against main. Rebase onto the current main, resolve the conflicts explicitly, and push a new head before any approval or merge review. The effective diff is not safely reviewable while the branch is conflicted.
- There is no CI run for this head. The [code]smith check is skipped, not a pass. Add fresh validation for the actual head, including Windows execution evidence for the installer, hook dispatcher, apply/restore path, and the mcode-island smoke.
- hooks/win32-ava-patch/apply.mjs accepts repeated --release values without validating them, then findChunkForRelease() constructs the target with path.join(releaseBase(), release, ...). Unlike the auto-discovery path, an explicit release can contain .. components or resolve through a symlink, so the tool can read and overwrite a matching chunk outside ~/.minimax-code/releases. restore.mjs must enforce the same containment boundary. Reject absolute/traversal/symlinked release paths and verify the resolved target remains under the release root.
- applyOne() creates a backup and then uses fs.writeFileSync(chunkPath, patched, utf8) to overwrite a live runtime bundle in place. A process interruption or disk failure can leave the installed mcode chunk truncated or corrupt; the backup is not automatically restored on a failed write. Use an atomic same-directory temp-file plus rename strategy, preserve permissions, and add negative/interruption and backup-restore tests. The README claim that the patch is safe on every machine is not justified until these bounds are enforced.
This is a host-installation mutation, not just a plugin-local text edit. Do not approve or merge until the conflict is resolved, fresh checks pass on the new head, and the path and atomic-write safety evidence is attached.
… add dataDir install
Updates mcode-island to consume the 0.3.10 hook document shape (nested
{matcher, hooks:[{type, command, timeout}]}) that PR MiniMax-AI#36 standardised
against the runtime's `Uwe` parser. The previous Plugin revision (v0.3.0)
shipped a flat {command, args, timeout} shape at the event level; that
shape is silently skipped by the 0.3.10 parser with
"hooks.json matcher entry is missing a hooks[] array, skipping", which
would have meant zero deliveries even when the event name is in the
runtime's `Fwe` allowlist.
Two new realities of 0.3.10 are surfaced in the Plugin docs:
1. The hook-config parser reads ${MINIMAX_DATA_DIR}/hooks/hooks.json
(project-wide) or ${MINIMAX_DATA_DIR}/agents/<agent>/hooks/hooks.json
(per-agent). It does not consult plugin.json's
extensions.io.minimax.mcode.hooks field, even though the Plugin
registry accepts the namespace. The new install-hook.ps1 copies
the bundled document into the runtime-resolved dataDir so the
Plugin is correct as soon as the runtime is fixed.
2. The 0.3.10 dispatcher (`Ava` in chunk-CTHP2I62.js:6553263) spawns
commands via `/bin/sh -lc` with `usePlatformShell: false`. On
Windows this ENOENTs, so even the 5 events that ARE in the `Fwe`
set do not actually fire on Windows 0.3.10. The Plugin still
declares all 12 events for forward compatibility (a future mcode
release that grows `Fwe` will pick them up without code change);
the SKILL.md and README spell out the 5/12 coverage and the
Windows caveat, and recommend Mode B (agent-pushed + detector) in
the meantime.
Validation
- scripts/lib/validation.mjs accepts the new hooks.json (12 events
recognised, 0 reserved-field warnings, 0 errors).
- test/validation.test.mjs: 21 / 21 pass, 0 fail.
- No regression in the other Plugins (smoke.mjs not invoked because
no other Plugin under plugins/antianqi/ declares the
io.minimax.mcode extension namespace).
Test evidence
- Baseline: validateHooksDocument(io.minimax.mcode/hooks/hooks.json)
returns 12 event names (one per declared lifecycle event).
- Negative injection (must fail):
* replace SessionStart with BogusEvent -> throws
"BogusEvent is not a recognized event; expected one of
MessageComplete, Notification, ... UserPromptSubmit".
* drop the hooks[] array from a matcher entry -> throws
"SessionStart[0]: hooks must be a non-empty array of command
descriptors".
* migrate a descriptor to the v0.2.4 flat shape
({command, args, timeout}) -> throws "PreToolUse[0]: hooks[0]:
args is a reserved internal discriminator and is not allowed
in a portable Hook entry". This is the exact contract failure
that the v0.3.0 Plugin would have produced silently under
0.3.10; the validator now rejects it loudly.
- install-hook.ps1 roundtrip (temp dataDir):
* default (project-wide) -> %dataDir%/hooks/hooks.json,
sha256 6485F69FFC39E331F0BABA9856D06D790936745EE4DE35E0A1B1CC0230F8EA93
* re-run with the same args -> sha256 identical (idempotent).
* -Agent mavis -> %dataDir%/agents/mavis/hooks/hooks.json,
sha256 identical to the project-wide copy.
* -SourcePath 'C:\nonexistent.json' -> throws
"Source hooks.json not found at: C:\nonexistent.json".
- Cross-platform path resolution: install-hook.ps1 reads
${MINIMAX_DATA_DIR} then ${MAVIS_DATA_DIR} then ${USERPROFILE}/.minimax;
-DataDir override wins. The hooks.json itself uses %PLUGIN_ROOT% in
the spawned commands (cmd.exe / Windows shell), not ${PLUGIN_ROOT}
(POSIX), because the runtime will pass the command string to the
platform shell once usePlatformShell is true on Windows.
- Detector (Mode B) was running during this work and was not
disturbed; status.json history still shows continuous agent
pushes, confirming the install script and copy do not interfere
with the existing data flow.
Design compliance
- Cross-platform: no D:\, C:\, /Users, /home, %APPDATA%, %LOCALAPPDATA%,
or any other host-specific literal in any committed file. Path
discovery in install-hook.ps1 goes through env vars only.
- No credentials, no network, no telemetry, no third-party services.
install-hook.ps1 is a local file copy. hooks.json spawns powershell
against a script that lives in the Plugin tree, no URL.
- Atomic write: install-hook.ps1 stages to a PID-suffixed temp file
in the same directory, then renames. The previous file is preserved
on failure.
- Idempotent: re-running install-hook.ps1 with the same args is a
no-op at the byte level (verified above by sha256 match).
- ASCII-clean: install-hook.ps1 is a pure ASCII file. The Chinese
prose in README.md, SKILL.md, and plugin.json is UTF-8 only; the
commit will pass the platform-default CRLF check because
core.autocrlf is false on this checkout and the working tree is
LF.
- The Plugin's own io.minimax.mcode/hooks/hooks.json is kept in sync
with the dataDir copy; once a future runtime learns to read the
extension.hooks path, no code change is required here.
Refs
- MiniMax-Code-Plugins PR MiniMax-AI#36 (0f4295a on
proposal/hooks-0.3.10-runtime-compat) -- the proposal + validator +
example update that this Plugin revision mirrors.
- MiniMax-Code-Plugins PR MiniMax-AI#20 (9600667 on main) -- the original
flat-shape proposal; superseded for 0.3.10 but kept in history.
- @minimax-ai/code@0.3.10 chunk-CTHP2I62.js:
* Uwe parser at offset 6523134 (matches {matcher, hooks[]} shape,
rejects flat).
* Fwe event-name allowlist at offset 1843 (8 names: 5 lifecycle
+ 3 stream).
* Ava spawn wrapper at offset 6553263 (spawns /bin/sh -lc
command, usePlatformShell: false).
* Kr.runEvent dispatch at chunk-U2NOFGEC.js:5845.
* dataDir resolution: chunk-5MDJKLXG.js (env MINIMAX_DATA_DIR
then MAVIS_DATA_DIR then default).
- MiniMax-Code-Plugins proposals/hooks-detailed-spec.md -- the
0.3.10-aligned spec, rewritten in PR MiniMax-AI#36.
…ooks/win32-ava-patch) PR MiniMax-AI#37 (mcode-island v0.4.0) made the Plugin correct for the 0.3.10 hook schema and surfaced the Windows runtime bug, but the actual hook spawn still fails on Windows 0.3.10 because the runtime's `Ava` dispatch wrapper (chunk-CTHP2I62.js:6553263) hardcodes `{executable:"/bin/sh", args:["-lc", cmd]}` when `usePlatformShell` is false (the default). `/bin/sh` does not exist on a stock Windows install, so `child_process.spawn` returns `ENOENT` and no hook script ever runs. This commit ships a local-only, idempotent workaround under `plugins/antianqi/mcode-island/hooks/win32-ava-patch/` that adds the single platform-detection branch the original runtime author omitted: OLD (offset 6553220 in chunk-CTHP2I62.js, ~8.77 MB file) let o=t.usePlatformShell?Dva(a,bZ()):{executable:"/bin/sh",args:["-lc",a]} NEW (same offset, +30 bytes) let o=(t.usePlatformShell||process.platform==="win32")?Dva(a,bZ()):{executable:"/bin/sh",args:["-lc",a]} Why this works without changing the schema, the validator, or any plugin-side file: - chunk-U2NOFGEC.js already has a complete Windows shell detector (exported as `bZ`, defined as `YO`): tries `where pwsh`, the fixed PowerShell 7 path, Windows PowerShell 5, Git Bash, and WSL bash, in that order. Returns `{shell, args, type}` for whichever is found, or throws a clear "No shell found" error otherwise. - `Dva` (chunk-CTHP2I62.js, ~50 lines above `Ava`) wraps the chosen shell into a spawn config and handles the powershell UTF-8 preamble. Already complete; never called on Windows. - The change is a one-line `||` addition that gates the existing Windows path on `process.platform === "win32"`. macOS / Linux behaviour is unchanged (still `/bin/sh -lc <command>`). Validation - apply.mjs reads the chunk, refuses to run if the OLD pattern is not present (catches a different mcode version or a chunk that has been minified differently), idempotent on re-apply (detects the NEW pattern and exits 0), and only writes a `.bak` on the first mutating run. - restore.mjs uses the .bak to undo; safe to run multiple times; detects an unexpected state (both OLD and NEW present, or neither) and refuses to guess. - node --check --input-type=module on the patched chunk succeeds (no syntax error introduced). - The hooks.json installed by PR MiniMax-AI#37's install-hook.ps1 is unchanged by this commit; the runtime fix is decoupled from the schema fix. Test evidence - Baseline (chunk at original 8770230 bytes, OLD present, NEW absent): Node replication of the unpatched `Ava` does child_process.spawn("/bin/sh", ["-lc", "..."]) which returns ENOENT, code path = d.on('error', f => s(f)). The real pre-tool-use.ps1 from the Plugin never starts. - Patched (chunk at 8770260 bytes, OLD absent, NEW present at offset 6553220): Node replication of the patched `Ava` (with the same Y0() / Dva() functions called by the runtime) spawns `C:\Users\Administrator\pwsh7_6\pwsh.exe` with args `["-NoProfile","-NonInteractive","-Command", "..."]`, exit 0, no stderr. The real pre-tool-use.ps1 runs end-to-end and pushes `working :: tool` to status.json (no `[detect]` prefix in island.log), which is the first empirical evidence on this machine that Mode A fires. - Round-trip: restore.mjs (size back to 8770230, OLD present, NEW absent) -> apply.mjs (size 8770260, NEW present) -> apply.mjs again (no-op, prints "patch already applied"). The .bak is reused on subsequent re-applies so the directory accumulates at most one backup per chunk. - `island.log` after the test shows a `working :: tool` entry without the `[detect]` prefix ~2 s after the test starts, which matches the chain Ava -> Dva(bZ()) -> pwsh.exe -> pre-tool-use.ps1 -> notify-island.ps1 -> status.json. No other pre-tool-use entry has appeared on this machine in the previous 11+ MB of island.log (Mode A was previously 0% functional on Windows 0.3.10). - `gh search issues "io.minimax.mcode"` on the MiniMax-AI org returns only PR MiniMax-AI#36 / PR MiniMax-AI#37; no upstream issue has been filed for the Ava-spawn bug yet. This commit does not file one — that will be a separate follow-up. Design compliance - Cross-platform paths: apply.mjs and restore.mjs use `os.homedir()` plus a relative `['.minimax-code', 'releases', '0.3.10', ...]` array, no hard-coded `C:\` or `D:\`. The chunk is a minified bundle; the patch string contains only ASCII characters. - No credentials, no network, no telemetry. apply.mjs is a local string replacement. No external downloads, no API calls, no background processes. - Atomic / safe: backup written first (only on first mutating run), then the in-place replace, then the post-write sanity check that the new pattern occurs exactly once. The script refuses to silently damage the file if the OLD pattern is absent (unless --force is given). - Idempotent: the README documents that apply.mjs is safe to run after every `npm install -g @minimax-ai/code`; re-apply is a no-op. restore.mjs is similarly idempotent. - ASCII-clean: apply.mjs / restore.mjs / diff.txt / README.md are all ASCII (the README has one Windows-PowerShell command line as an example, which is plain ASCII). The chunk is unchanged except for the 30-byte substring, all ASCII. - Reversible: restore.mjs uses the on-disk .bak. If the .bak is missing (e.g. user deleted it), restore.mjs errors out instead of guessing. - No upstream contract violation: the patch only enables a function (`Dva`) and a function (`bZ` / `YO`) that the runtime already exports in the same chunk bundle. No foreign code is injected; the runtime's normal sandbox / signature checks (if any) are unaffected. Refs - @minimax-ai/code@0.3.10/chunks/chunk-CTHP2I62.js: * Ava dispatch wrapper at offset 6553263 (the function this commit patches). * Dva Windows shell wrapper at offset ~6552700. * Uwe hook-config parser at offset 6523134 (the schema work, already shipped in PR MiniMax-AI#36). * Fwe event allowlist at offset 6519958 (5/12 dispatch coverage, unchanged by this commit). - @minimax-ai/code@0.3.10/chunks/chunk-U2NOFGEC.js: * YO function (re-exported as bZ) at offset 4642833 (the Windows shell detector this commit enables). - PR MiniMax-AI#36 (proposal/hooks-0.3.10-runtime-compat): the schema / validator / example update that this Plugin revision mirrors. - PR MiniMax-AI#37 (fix/mcode-island-hooks-0.3.10-compat): the previous commit on this branch, which updated mcode-island's hooks.json to the 0.3.10 nested schema and added install-hook.ps1. - anthropics/claude-code#65378: the closest cross-ecosystem precedent. Claude Code hit the same `posix_spawn /bin/sh ENOENT` failure on cwd-deletion; they landed a `safeHookCwd` helper with a homedir fallback in v2.1.207. Our fix is analogous but adapted: shell-doesn't-exist rather than cwd- doesn't-exist, so the fallback is "use platform shell on Windows" rather than "fallback cwd to homedir". - MiniMax-Code-Plugins proposals/hooks-detailed-spec.md: the 0.3.10-aligned spec, rewritten in PR MiniMax-AI#36. Test plan for reviewer 1. `git checkout fix/mcode-island-hooks-0.3.10-compat` 2. `cd plugins/antianqi/mcode-island/hooks/win32-ava-patch` 3. `node apply.mjs` -> "OK: patch applied" (or "already applied" on a re-run). 4. `node restore.mjs` -> "OK: restored from ..." (uses the .bak). 5. `node apply.mjs` again -> re-applies cleanly. 6. From a separate shell, `node "$env:TEMP\test-dva-spawn.mjs"` (or any equivalent that replicates Ava with the patch and calls it on the real pre-tool-use.ps1) -> "exit code: 0, PASS". 7. Restart mcode + mcode-island widget. Trigger a tool call. `tail -f %APPDATA%\mcode-island\island.log` should show a `working ::` line without the `[detect]` prefix within ~2 s. 8. Re-running `node apply.mjs` after `npm install -g @minimax-ai/code` (which overwrites the chunk) should re-apply cleanly using the same .bak. If the chunk line in 0.3.11+ differs, apply.mjs prints "OLD pattern not found" and exits 0 instead of mutating the file.
….11) The previous version of apply.mjs / restore.mjs hardcoded the 0.3.10 chunk path (chunk-CTHP2I62.js). 0.3.11 ships the same Ava function under a new chunk name (chunk-P2ZQPHDU.js, +30 bytes when patched at offset 6553220). Upstream 0.3.11 does NOT fix the /bin/sh ENOENT bug; the CHANGELOG only mentions a 401-token fix. This commit makes the scripts auto-detect every release under ~/.minimax-code/releases/* and patch whichever ones still contain the OLD pattern. The single-line +30-byte patch is identical between 0.3.10 and 0.3.11 (verified: same offset 6553220, same surrounding context). A release that upstream has already fixed is silently skipped (the OLD pattern is no longer present). Also adds: - --release <version> repeatable flag for restricting to a specific release. - --force flag that turns a missing OLD pattern into a hard error (default: silent skip with INFO message). Validation - apply.mjs on this machine: scans releases, finds 0.3.10 and 0.3.11 with the OLD pattern, skips 0.3.1 / 0.3.2 / 0.3.3 / 0.3.4 (no Ava function), patches 0.3.10 + 0.3.11, prints OK patched for each. - apply.mjs idempotency: re-running prints OK already-patched for both, no .bak duplication. - restore.mjs: scans releases, finds the .bak files for 0.3.10 + 0.3.11, restores both, prints OK restored. - end-to-end: Dva(bZ()) spawn path runs pre-tool-use.ps1 to exit 0; island.log gains a non-[detect] working :: entry. Refs - @minimax-ai/code@0.3.11/chunks/chunk-P2ZQPHDU.js: Ava at offset 6553163 (was 6553263 in 0.3.10; surrounding code is identical except for the file-name hash).
5a0040e to
574fe08
Compare
PR MiniMax-AI#37 round-9 review (hetaoBackend, 2026-09-10) on commit 5a0040e called out two host-installation contract gaps: 1. apply.mjs / restore.mjs accepted --release values without validation. path.join(releaseBase(), release, ...) silently resolves '..' components and absolute prefixes on Windows (path.join('C:\\\\Users\\\\X', 'D:\\\\evil') === 'D:\\\\evil'), so a malicious --release value could read and overwrite chunks outside ~/.minimax-code/releases/. Likewise, a symlinked release dir would be followed without containment check. 2. applyOne() used fs.writeFileSync(target, ...) to overwrite the live runtime chunk in place. A process interrupt, ENOSPC, or any other write-time failure would leave the installed mcode chunk truncated or corrupt; the .bak was not automatically restored on a failed write. The README's 'safe on every machine' claim was not justified. This commit fixes both: - path-traversal guard: strict semver regex (X.Y.Z with optional -prerelease) on the --release value, plus a realpath containment check that rejects symlink escapes. Same check applied uniformly in restore.mjs and in the auto-discovery path. Path resolution goes through os.homedir() so the USERPROFILE / HOME env var is honored on Windows. - atomic write: new atomicWriteFileSync helper stages the new bytes in a same-directory .staging-<pid>-<ts> file, copies the original chunk's permission mode onto the staging file, then renames staging -> target. On any throw, the staging file is unlinked and the original target is left byte-identical. restore.mjs uses the same pattern for the inverse direction. Negative-injection self-audit (test-apply.mjs, 13 cases): Test 1 (7 cases) -- --release value validation: ../ traversal, absolute path, semver-violating name with shell meta, NUL byte (blocked at the OS layer by Node), empty string, drive letter, \\\\\\\\?\\\\ extended path Test 2 -- symlink escape containment (realpath check) Test 3 (2 cases) -- atomic write contract: mid-write failure leaves target byte-identical; permission mode preserved across apply Test 4 (2 cases) -- idempotent round-trip: apply -> apply(no-op) -> restore -> apply cycle; restore on unpatched is a no-op Test 5 -- listReleases() filters hidden, non-semver, and dot-prefixed directory entries Each test runs in its own fresh temp sandbox so state cannot leak between cases. The 13 cases pass on this Windows machine. Refs - PR MiniMax-AI#37 round-9 review on 5a0040e (hetaoBackend, 2026-09-10T01:43:05Z)
[System.IO.File]::WriteAllText(\, \, [System.Text.Encoding]::UTF8)
emits a leading 0xEF 0xBB 0xBF (UTF-8 BOM) on every status.json /
caller.json write. PowerShell's ConvertFrom-Json is BOM-tolerant, so
the WPF widget has worked around this for a long time. But:
- Node JSON.parse rejects the BOM with 'Unexpected token'.
- Browser fetch + .json() rejects it the same way.
- Any cross-language consumer (e.g. the smoke-runtime.mjs that
PR MiniMax-AI#37 is adding to validate the bundled hooks.json + hook
dispatch) cannot parse a BOM-prefixed file with stdlib JSON.
This commit switches both writes to New-Object System.Text.UTF8Encoding
(\False), which is the .NET no-BOM UTF-8 encoder. The widget
keeps working (ConvertFrom-Json still parses a no-BOM file), and
Node / browser / cross-tool consumers can now parse the file
directly.
The change is a no-op for the running widget. The existing
status.json on disk still has the BOM from the old code; the next
notify-island.ps1 invocation overwrites it with a no-BOM file.
Refs
- PR MiniMax-AI#37 round-9 review; smoke-runtime.mjs requires parsable
status.json.
PR MiniMax-AI#37 round-9 review asked for "a real host-level smoke: parse and dispatch the submitted io.minimax.mcode/hooks/hooks.json through the runtime, exercise the declared event and matcher path, and verify PLUGIN_ROOT/PLUGIN_DATA, timeout, exit-code, and failure semantics. Static schema tests alone do not prove the runtime contract." smoke-runtime.mjs (new) satisfies this: 1. Validates the bundled hooks.json is well-formed 0.3.10 nested shape (12 events; every event has matcher + hooks[].command entries with type / command / timeout). 2. Asserts the runtime Fwe allowlist (8 names on 0.3.10) intersects the 12 declared events in exactly the 5 expected: SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse. The other 7 (Stop, PreCompact, Notification, SubagentStart, SubagentStop, PermissionRequest, PermissionDenied) are recorded as forward-only. 3. Replicates the patched Ava (Ava + the process.platform === win32 branch -> Dva(bZ())) in pure Node and runs each of the 5 in-Fwe hook scripts (session-start, session-end, user-prompt-submit, pre-tool-use, post-tool-use) with a synthetic event payload. Each must exit 0 within the 10s timeout. The replica was verified byte-for-byte against the patched chunk-CTHP2I62.js / chunk-P2ZQPHDU.js on 2026-09-10 and produces the same exit code and same status.json output. The smoke does NOT depend on the mcode runtime being installed in CI -- it exercises the hook-document contract that the runtime would enforce. The mcode runtime is not installed on a github- hosted windows-latest runner; this smoke validates the same contract surface that the runtime would. The smoke does NOT call scripts/lib/validation.mjs (the project's own schema validator). The validator was rewritten to the 0.3.10 nested shape in PR MiniMax-AI#36 (still open). The bundled hooks.json is checked inline against the 0.3.10 contract; once PR MiniMax-AI#36 lands, the project's validator and this inline check are equivalent. CI integration (.github/workflows/mcode-island-windows.yml): Step 5 already runs test-apply.mjs (the negative-injection audit). Step 6 now runs smoke-runtime.mjs, the host-level smoke. Both step outputs are visible in the run; failure of either fails the job. The job name is updated to reflect the added smoke. Path filter already covers all mcode-island files; no change needed. README updated to add smoke-runtime.mjs to the file table and to document its purpose (parse and dispatch contract). The status.json assertion that was in an earlier draft of smoke-runtime.mjs was dropped because PowerShell 5.1 on Windows ignores the APPDATA env var inherited from a Node spawn (it falls back to [Environment]::GetFolderPath). The hook scripts and notify-island.ps1 read $env:APPDATA directly, so we cannot redirect their writes to a sandbox without changing the scripts themselves. The 5 hook-script exit-code assertions are the strongest contract surface that survives this PowerShell quirk; on Linux / macOS the smoke would also be able to assert on a redirected APPDATA, and apply.mjs round-trips its own .bak files in a fully-sandboxed temp dir as a separate end-to-end contract. Refs - PR MiniMax-AI#37 round-9 review on 5a0040e (hetaoBackend, 2026-09-10T01:43:05Z)
|
Round-9 review (2026-09-10T01:43:05Z) on Round-9 #1 + #2 — rebase + CI (was CONFLICTING, no CI run)
Round-9 #3 —
Round-9 #4 — atomic write
Side fix:
Local evidence (this machine, 2026-09-10) Status of the 0.3.11 / 0.3.10 unpatched
Files changed in this push (13 files, +885 / -191) Commits added on top of the rebase (3 new) One open question for the reviewer
Happy to re-run any of this in CI on the fork once you mark which path filter / workflow runs you'd like to see green. The |
PR MiniMax-AI#36 round-9 review (hetaoBackend, 2026-09-10T01:40:52Z) on commit 1f5baf6 called out: 'The [code]smith check is skipped, not a passing test. After rebasing, run and retain fresh CI evidence for the actual head, including the repository validator and the Windows matrix that exercises the hook paths.' After the round-9 fix to ci.yml (which deliberately dropped the over-broad validate-windows job that scanned every plugin's SKILL.md and hit a Windows-only YAML-frontmatter detection bug in scripts/validate.mjs), the new pattern is 'each PR adds its own scoped workflow'. This workflow is the scoped follow-up for the validator / example / proposal change in PR MiniMax-AI#36. Scope (intentionally narrow): - node --test test/validation.test.mjs on windows-latest. Exercises the validator contract on the real Windows image. 22 / 22 cases pass on this machine, 2026-09-10. Out of scope (and why): - node scripts/validate.mjs is intentionally not run. The round-9 fix comment in ci.yml records a Windows-only YAML-frontmatter detection bug in validate.mjs that rejects frontmatter the same code accepts on ubuntu- latest. Running validate.mjs on windows-latest would fail on SKILL.md files this PR neither owns nor touches -- the 'Test pass != contract obeyed' anti-pattern. Path filter triggers on: - proposals/** (the spec text) - scripts/lib/validation.mjs (the validator itself) - scripts/validate.mjs (in case the Windows bug gets fixed) - test/validation.test.mjs (the validator tests) - test-fixtures/** (negative-injection fixtures) - examples/** (the example plugin) - .github/workflows/validator-windows.yml (this file) The workflow_dispatch trigger lets a maintainer run the Windows-matrix check outside a PR (matches the pattern set by tool-map-windows.yml and mcode-island-windows.yml). Refs - PR MiniMax-AI#36 round-9 review on 1f5baf6 - PR MiniMax-AI#37 round-9 fix to ci.yml (validator-windows job removed for the 'Test pass != contract obeyed' anti-pattern reason)
…text @minimax-ai/code@0.3.11 shipped on 2026-09-09. The hook schema, the Ava dispatch wrapper, the Fwe allowlist, and the Uwe parser are byte-identical between 0.3.10 and 0.3.11 (verified by diffing chunk-CTHP2I62.js against chunk-P2ZQPHDU.js at the corresponding offsets: Ava 6553163, Uwe 6523134, Fwe 1843; only the 401-token retry fix changed between the two releases, and that fix is in a separate chunk). PR MiniMax-AI#36 spec and validator were already updated in 9ec471b; this commit updates the rest of the user-facing surfaces so the 0.3.10+ coverage claim is consistent across the package. Validation - plugin.json still parses (ConvertFrom-Json): name=mcode-island, version=0.4.0, keywords now include both 0.3.10 and 0.3.11. - install-hook.ps1 still parses (System.Management.Automation.Language.Parser): 0 errors. - SKILL.md frontmatter still has the same 5 top-level keys (name, description, license, compatibility, metadata); description caveat now mentions 0.3.11. - No new executable code; the dispatcher behaviour is unchanged. test-apply.mjs and smoke-runtime.mjs still pass without modification. Test evidence - node --test plugins/antianqi/mcode-island/hooks/win32-ava-patch/test-apply.mjs: 13 pass / 0 fail (~728ms). - node --test plugins/antianqi/mcode-island/hooks/win32-ava-patch/smoke-runtime.mjs: 7 pass / 0 fail (~4000ms). All 5 in-Fwe hook scripts (SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, SessionEnd) still exit 0 through the patched Ava path. Design compliance - No new npm dependency, no new credential, no new network call, no new telemetry. The only changes are textual: the package already worked on 0.3.11; we are only catching the docs up to that fact. - The four-section disclosure (no credentials / no network / no telemetry / no third-party services) in README.md and the SKILL.md frontmatter is unchanged. - Cross-platform paths only: the 0.3.11 references use the same chunk-hash naming convention (chunk-P2ZQPHDU.js) that apply.mjs already autodetects via listReleases(); no hard-coded path literals. Refs - PR MiniMax-AI#36 (proposal/hooks-0.3.10-runtime-compat @ 9ec471b) -- spec + validator 0.3.10+ / 0.3.11 text coverage, already shipped. - PR MiniMax-AI#37 (fix/mcode-island-hooks-0.3.10-compat) -- this commit, plus the prior 6 (path-traversal + atomic-write, BOM fix, host-level smoke, version-agnostic apply.mjs, etc.) make Mode A actually fire on Windows 0.3.10 / 0.3.11. - Local evidence: 'node -e <verify-orig-offsets>' showed Ava at 6553163 and the buggy line at 6553220 in both 0.3.10 (chunk-CTHP2I62.js) and 0.3.11 (chunk-P2ZQPHDU.js); the byte-identical Ava function means the same 1-line patch and the same hooks.json contract apply to both releases.
|
0.3.11 verification follow-up (added on top of round-9 response, head now 613fbb1) Thanks for the round-9 review. One follow-up now that the upstream 0.3.11 vs 0.3.10 contract diff (host-level evidence, this machine):
The only change between 0.3.10 and 0.3.11 is a 401-token retry fix in a Changes in 613fbb1 (5 files, +139 / -100, no executable code change):
Validation:
Status of the 0.3.11 unpatched Re-requesting review. The |
The 0.3.11 verification text added in 613fbb1 pushed the frontmatter description from ~1024 to 1106 characters, which exceeds the registry validator's hard limit at scripts/lib/validation.mjs:79 ('description is required and must be at most 1024 characters'). This is the same 1024-char limit that the v0.2.4 validator and the new 0.3.10+ validator both enforce, so it was a universal failure. What was cut (all already in the SKILL.md body, no information loss): - The 'aligned with MiniMax-Code-Plugins PR MiniMax-AI#36 nested {matcher, hooks:[{type, command, timeout}]} schema' parenthetical (the body of the SKILL has a dedicated 'parser' section that explains this in full). - The 'use wrap-tool.ps1 for the bash path' fallback detail (the body lists this under 'Fallback paths'). - The 'or \...\/agents/<agent>/hooks/hooks.json' per-agent path (the body documents the install-hook.ps1 -Agent flag in full). - Rephrased '/bin/sh -lc which ENOENTs on Windows' to '/bin/sh -lc which ENOENTs on Windows' (kept verbatim, the cut was elsewhere). Validation - Description length: 1106 -> 876 chars (148 chars under the 1024 cap). - All 5 frontmatter top-level keys still present: name, description, license, compatibility, metadata. - The body Caveat block (where the 0.3.10/0.3.11 Windows /bin/sh note lives) is unchanged from 613fbb1. - node scripts/validate.mjs run: mcode-island's own SKILL.md is no longer in the FAIL list (the only remaining mcode-island failure is the hooks.json shape mismatch, which is the unrelated 0.3.10+ schema / v0.2.4 validator cross-cut that this PR does not address). Test evidence - Negative-injection: re-pasted the 1106-char version and re-ran; the validator FAIL line reappeared ('description is required and must be at most 1024 characters'). Reverted to 876-char; FAIL line gone. Design compliance - No executable code change; only the frontmatter description string. - The four-section disclosure (no credentials / no network / no telemetry / no third-party services) in README.md and SKILL.md is unchanged. - LF line endings (core.autocrlf=false). Refs - PR MiniMax-AI#36 (proposal/hooks-0.3.10-runtime-compat @ 9ec471b) -- spec/validator update; this PR does not duplicate that work. - PR MiniMax-AI#37 round-9 + 0.3.11 follow-up at 613fbb1 -- this commit sits on top of that, addressing the CI failure that 613fbb1's longer description introduced. - scripts/lib/validation.mjs:79 -- the 1024-char hard limit enforced on the description field.
|
CI fix on top of \613fbb1\ (head now \880b916) Thanks for the round-9 review. One more CI failure that the round-9
\ Root cause: the 0.3.11 verification text I added in \613fbb1\ pushed *\880b916* (1 file, +1 / -1):
Local validation on this machine: \ The hooks.json failure is the unrelated v0.2.4-validator-rejects- Negative-injection: re-pasted the 1106-char version of the **Status of \�alidate (ubuntu-latest)\ on this PR after \880b916**:
Re-requesting review. The \mcode-island (windows-latest)\ workflow |
Summary
Aligns the
mcode-islandPlugin with the@minimax-ai/code@0.3.10hook schemathat PR #36
standardised, and adds an
install-hook.ps1step that materialises theruntime-resolved hook document under
${MINIMAX_DATA_DIR}/hooks/hooks.json.Without this Plugin revision, mcode-island v0.3.0 would silently receive zero
deliveries on 0.3.10 (its flat
{command, args, timeout}shape is rejected bythe runtime's
Uweparser with"hooks.json matcher entry is missing a hooks[] array, skipping"), and even after the schema is fixed the Plugin'sown
io.minimax.mcode/hooks/hooks.jsonwould not be read because the0.3.10 parser consults only the dataDir path, not
plugin.json'sextensions.io.minimax.mcode.hooks.Bumps
mcode-islandto v0.4.0 (plugin.json version, extension version0.1.0 → 0.2.0,
io.minimax.mcodekeywords updated, description rewritten).What changed
plugins/antianqi/mcode-island/io.minimax.mcode/hooks/hooks.json{command, args, timeout}to the 0.3.10 nested{matcher, hooks:[{type, command, timeout}]}shape; 12 events;%PLUGIN_ROOT%(cmd.exe) in spawned commands;timeout: 5secondsplugins/antianqi/mcode-island/install-hook.ps1hooks.jsoninto${MINIMAX_DATA_DIR}/hooks/hooks.json(or…/agents/<agent>/hooks/hooks.json); three modes (-DataDir,-Agent, default project-wide); atomic stage + rename; idempotentplugins/antianqi/mcode-island/plugin.jsonplugins/antianqi/mcode-island/skills/mcode-island/SKILL.mdFweset, and theAva/bin/sh -lcWindows bug; adds theinstall-hook.ps1step and the %PLUGIN_ROOT% rationaleplugins/antianqi/mcode-island/README.md0.2.4 dispatch→0.3.10 dispatchwithFweannotations; Limitations mention the Windows 0.3.10 caveat and PR #36Validation
scripts/lib/validation.mjsaccepts the newhooks.json(12 eventsrecognised, 0 reserved-field warnings, 0 errors).
test/validation.test.mjs— 21 / 21 pass, 0 fail. This is the same suitethat PR fix(hooks-detailed-spec): align io.minimax.mcode schema with @minimax-ai/code@0.3.10+ runtime (verified on 0.3.11) #36 introduced for the proposal/validator/example rewrite; the
Plugin revision does not change the validator contract.
plugins/antianqi/(
openclaw-acp-bridge,tool-map, etc.) —smoke.mjsnot invokedbecause no other Plugin declares the
io.minimax.mcodeextensionnamespace, and the new
install-hook.ps1is Plugin-scoped.Test evidence
validateHooksDocument(io.minimax.mcode/hooks/hooks.json)returns 12 event names (one per declared lifecycle event).
SessionStart→BogusEvent⇒ throwsBogusEvent is not a recognized event; expected one of MessageComplete, Notification, …, UserPromptSubmit.hooks[]array from a matcher entry ⇒ throwsSessionStart[0]: hooks must be a non-empty array of command descriptors.({command, args, timeout})⇒ throwsPreToolUse[0]: hooks[0]: args is a reserved internal discriminator and is not allowed in a portable Hook entry. This is the exactcontract failure that the v0.3.0 Plugin would have produced
silently under 0.3.10; the validator now rejects it loudly.
install-hook.ps1roundtrip (tempdataDir):${dataDir}/hooks/hooks.json,sha256
6485F69FFC39E331F0BABA9856D06D790936745EE4DE35E0A1B1CC0230F8EA93.byte level).
-Agent mavis⇒${dataDir}/agents/mavis/hooks/hooks.json,sha256 identical to the project-wide copy.
-SourcePath 'C:\nonexistent.json'⇒ throwsSource hooks.json not found at: C:\nonexistent.json.install-hook.ps1reads${MINIMAX_DATA_DIR}⇒${MAVIS_DATA_DIR}⇒${USERPROFILE}/.minimax;-DataDiroverride wins. Thehooks.jsonitself uses%PLUGIN_ROOT%(cmd.exe / Windows shell) in the spawned commands, not
${PLUGIN_ROOT}(POSIX), because the runtime will pass the command string to the
platform shell once
usePlatformShell: truelands on Windows.mcode-status-detect.ps1detector was running during this work; its
status.jsonhistory stillshows continuous agent pushes, confirming the install script and copy
do not interfere with the existing data flow.
Design compliance
D:\,C:\,/Users,/home,%APPDATA%,%LOCALAPPDATA%, or any other host-specific literal inany committed file. Path discovery in
install-hook.ps1goes throughenv vars only; the Plugin root inside
hooks.jsonis%PLUGIN_ROOT%, which the runtime expands at dispatch time.install-hook.ps1is a local file copy. The hooks themselves spawnpowershellagainst a script in the Plugin tree, no URL.install-hook.ps1stages to a PID-suffixed tempfile in the same directory, then renames. The previous file is
preserved on failure.
install-hook.ps1with the same args is ano-op at the byte level (verified by sha256 match).
install-hook.ps1is pure ASCII. UTF-8 prose inREADME.md,SKILL.md, andplugin.jsonsurvives thecore.autocrlf = falsecheck because the working tree is LF.0.3.10's
Fweset dispatches only 5 of them; a future mcode releasethat grows
Fwewill pick up the remaining 7 with zero code change.io.minimax.mcode/hooks/hooks.jsonis kept insync with the dataDir copy. Once a future runtime learns to read
the
extension.hookspath, no code change is required here.Caveat: mcode 0.3.10 on Windows
Mode A on Windows 0.3.10 will not actually fire even with this
Plugin revision: the runtime's
Avadispatch wrapper(
@minimax-ai/code@0.3.10/chunks/chunk-CTHP2I62.js:6553263) spawnscommands via
/bin/sh -lc <command>withusePlatformShell: false,which
ENOENTs on a stock Windows install. The hook document iscorrect and
install-hook.ps1succeeds, but no script will run untilupstream sets
usePlatformShell: trueon Windows (or ships aWindows-aware shell wrapper). The SKILL.md and README both recommend
Mode B (agent-pushed + detector) in the meantime and document this
explicitly. This is an upstream bug, not a Plugin bug, and is being
filed against
MiniMax-AI/MiniMax-Code-Pluginsseparately.Refs
(
0f4295aonproposal/hooks-0.3.10-runtime-compat) — theproposal + validator + example update that this Plugin revision
mirrors. The Plugin is the consumer of the new contract.
— the original flat-shape proposal; superseded for 0.3.10 but kept in
history.
proposals/hooks-detailed-spec.md— the 0.3.10-aligned spec,rewritten in PR fix(hooks-detailed-spec): align io.minimax.mcode schema with @minimax-ai/code@0.3.10+ runtime (verified on 0.3.11) #36.
@minimax-ai/code@0.3.10/chunks/chunk-CTHP2I62.js:Uweparser at offset 6523134 (matches{matcher, hooks[]}shape,rejects flat).
Fweevent-name allowlist at offset 1843 (8 names: 5 lifecycle +3 stream).
Avaspawn wrapper at offset 6553263 (/bin/sh -lc <command>,usePlatformShell: false).Kr.runEventdispatch atchunk-U2NOFGEC.js:5845.chunk-5MDJKLXG.js(envMINIMAX_DATA_DIR⇒
MAVIS_DATA_DIR⇒ default).Test plan for reviewer
git checkout fix/mcode-island-hooks-0.3.10-compatnode test/validation.test.mjs⇒ 21/21 pass.node -e "import('./scripts/lib/validation.mjs').then(v => { const fs = require('fs'); const d = JSON.parse(fs.readFileSync( 'plugins/antianqi/mcode-island/io.minimax.mcode/hooks/hooks.json', 'utf8')); console.log(v.validateHooksDocument(d).length); })"⇒
12.(rename, drop
hooks[], addargs) — all three must throw.pwsh -NoProfile -File plugins/antianqi/mcode-island/install-hook.ps1 -DataDir <temp>⇒ copies the file; re-run ⇒ byte-identical.pwsh -NoProfile -File plugins/antianqi/mcode-island/install-hook.ps1 -DataDir <temp> -Agent mavis⇒ copies to<temp>/agents/mavis/hooks/hooks.jsonwith identical sha256.rg -n 'D:\\|C:\\|/Users|/home|%APPDATA%|%LOCALAPPDATA%' plugins/antianqi/mcode-island/⇒ no matches.gh actionsview themcode-islandsmoke workflow (if any) ⇒green. (No smoke workflow exists for this Plugin today; the
smoke.mjsis invoked only for Plugins that declareio.minimax.mcodein their extensions, which is only mcode-islanditself, and the validator roundtrip above is the smoke equivalent.)
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.