fix(wasm): stop appending WABT remediation to unrelated runtime-root failures (#2084)

inspect_wasm_artifact's configuration-phase error handler assumed every
non-OwnedCommandFailure thrown before the artifact phase was about WABT
tool/directory resolution, and unconditionally appended "Supply WABT 1.0.42
via absolute REA_WABT_BIN_DIRECTORY; REA does not install tools." to the
reason. WabtArtifactProvider.inspect() also allocates its PrivateRuntimeRoot
during the configuration phase, so a PrivateRuntimeRootUnavailableError (the
Windows native-authority capability, unrelated to WABT) got the same false
remediation glued onto its own already-correct message, misdirecting anyone
troubleshooting a correctly-configured WABT install toward re-checking WABT
instead of the real blocker.

Classify PrivateRuntimeRootUnavailableError before the generic
configuration-phase branch, matching the existing convention already used
in JavaScriptAnalysisWorker.ts and SourceMapCommand.ts: surface it as its
own AnalysisCapabilityUnavailableError with no userMessage override, letting
its own message stand.

Verified against a real WABT 1.0.42 Windows release (hash-checked against
GitHub release metadata) and a real compiled .wasm module: before the fix,
`reason` read "REA Windows native controls are unavailable: ENOENT: ...
Supply WABT 1.0.42 ..." even with a fully correct REA_WABT_BIN_DIRECTORY;
after, `reason` reports only the real cause.
This commit is contained in:
Hill Patel 2026-10-13 02:26:02 +05:30 committed by GitHub
parent 7b15762d09
commit ea2f94d4de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 1 deletions

View File

@ -3,7 +3,10 @@ import { join } from "node:path";
import { expect, it } from "vitest";
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
import { WabtArtifactProvider } from "./WabtArtifactProvider.js";
import { PrivateRuntimeRoot } from "../process/PrivateRuntimeRoot.js";
import {
PrivateRuntimeRoot,
PrivateRuntimeRootUnavailableError,
} from "../process/PrivateRuntimeRoot.js";
import { spawnOwnedProviderProcess } from "../process/ProviderProcess.js";
import { OwnedCommandFailure } from "../process/OwnedCommand.js";
@ -36,6 +39,41 @@ it("returns actionable unavailable without creating a workspace when tools are a
},
});
});
it("reports an unavailable private runtime root without a misleading WABT remediation", async () => {
const toolRoot = await createTestTempDirectory("rea-wabt-tool-root-");
for (const tool of ["wasm-validate", "wasm-objdump", "wasm2wat"])
await writeFile(
join(toolRoot, tool + (process.platform === "win32" ? ".exe" : "")),
"source-owned executable seam",
{ mode: 0o700 },
);
const provider = new WabtArtifactProvider(
{ REA_WABT_BIN_DIRECTORY: toolRoot },
undefined,
() => {
throw new PrivateRuntimeRootUnavailableError(
"REA Windows native controls are unavailable: probe failure",
);
},
);
expect(
await provider.inspect({
path: "/module.wasm",
glue_paths: [],
candidate_paths: [],
}),
).toMatchObject({
ok: false,
error: {
_tag: "AnalysisCapabilityUnavailableError",
userMessage: undefined,
message: expect.stringContaining(
"REA Windows native controls are unavailable",
),
},
});
});
it.each([
"success",
"invalid",

View File

@ -11,6 +11,7 @@ import {
} from "../domain/analysisErrorCore.js";
import { ProviderCleanupError } from "../domain/providerCleanupError.js";
import { OwnedCommandFailure } from "../process/OwnedCommand.js";
import { PrivateRuntimeRootUnavailableError } from "../process/PrivateRuntimeRoot.js";
import { WABT_LIMITS, WABT_PROVIDER_IDENTITY } from "./WabtRelease.js";
/** Preserve lifecycle failures and diagnostic bytes instead of returning partial success. */
export const wabtFailure = (
@ -70,6 +71,13 @@ export const wabtFailure = (
);
return new AnalysisOutputError("inspect_wasm_artifact", reason, options);
}
if (cause instanceof PrivateRuntimeRootUnavailableError)
return new AnalysisCapabilityUnavailableError(
WABT_PROVIDER_IDENTITY.id,
"inspect_wasm_artifact",
reason,
{ cause },
);
if (phase === "configuration")
return new AnalysisCapabilityUnavailableError(
WABT_PROVIDER_IDENTITY.id,