diff --git a/packages/cli/src/commands/validate.test.ts b/packages/cli/src/commands/validate.test.ts
index 1cc7ce36d..7353806c4 100644
--- a/packages/cli/src/commands/validate.test.ts
+++ b/packages/cli/src/commands/validate.test.ts
@@ -9,6 +9,25 @@ import {
} from "./validate.js";
import type { ProjectLintResult } from "../utils/lintProject.js";
+// validateInBrowser lazy-loads the producer localize helpers via loadProducer;
+// mock it so these unit tests never resolve @hyperframes/producer's built dist.
+vi.mock("../utils/producer.js", () => ({
+ loadProducer: vi.fn(async () => ({
+ localizeRemoteMediaSources: vi.fn(async (html: string) => ({
+ html,
+ remoteMediaAssets: new Map(),
+ })),
+ localizeRemoteImageSources: vi.fn(async (html: string) => ({
+ html,
+ remoteMediaAssets: new Map(),
+ })),
+ localizeRemoteFontFaces: vi.fn(async (html: string) => ({
+ html,
+ remoteMediaAssets: new Map(),
+ })),
+ })),
+}));
+
// Regression for the validate audio-duration-probe timeout: a slow-loading
// media element's duration was snapshotted once, at a fixed point in time,
// and any element still mid-load was permanently misreported as unreadable.
diff --git a/packages/cli/src/commands/validate.ts b/packages/cli/src/commands/validate.ts
index 9b20f9b97..07b5334ba 100644
--- a/packages/cli/src/commands/validate.ts
+++ b/packages/cli/src/commands/validate.ts
@@ -1,5 +1,6 @@
import { defineCommand } from "citty";
-import { existsSync, readFileSync } from "node:fs";
+import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
+import { tmpdir } from "node:os";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { resolveProject, type ProjectDir } from "../utils/project.js";
@@ -334,6 +335,37 @@ export function extractCompositionErrorsFromLint(
.map((f) => ({ level: "error" as const, text: f.message }));
}
+// Match the render pipeline: localize remote
/