feat(engine): auto-disable streaming-encode on Windows software-GPU compound

Field signal ts=1784131903 (win32/x64, CLI 0.7.58, 156s UI-heavy):
stable ONLY with four flags together — --workers 1 --no-browser-gpu
--low-memory-mode + PRODUCER_ENABLE_STREAMING_ENCODE=false. Since
--no-browser-gpu and --low-memory-mode already imply screenshot
capture, three of the four flags are structurally coupled. Auto-detect
the compound at resolveConfig time and disable streaming-encode on
the caller's behalf; user explicit-set (PRODUCER_ENABLE_STREAMING_ENCODE
or overrides.enableStreamingEncode) always wins.

Composition duration is not known at the config layer, so the wire-up
passes compositionDurationSec:undefined and the helper reduces to the
three-condition compound (platform + softwareGpuForced + workers=1).
The 4-arg helper stays exported for downstream callers that DO know
duration (e.g., renderOrchestrator) and want the >120s guard.

Trade-off documented in code + PR body: false positives possible for
short (~<120s) Windows software-GPU single-worker renders. Mitigation
is the explicit opt-in escape hatch.

Emits a single [hyperframes] log line naming the trigger + how to opt
back in, so operators can tell an auto-disable apart from an explicit
opt-out. Adds streamingEncodeAutoDisabledOnWin32Compound internal
provenance for downstream telemetry.

Stack: PR #2 of 9 (base via/protocol-timeout-discoverability).

Signed-off-by: Via
This commit is contained in:
Via
2026-07-15 22:21:54 +00:00
parent 6944a1c2d0
commit cbf2a2ec69
2 changed files with 322 additions and 0 deletions
+211
View File
@@ -7,6 +7,7 @@ import {
scaleProtocolTimeoutForComposition,
shouldClampToScreenshotForConcreteGpu,
applyConcreteGpuScreenshotClamp,
shouldAutoDisableStreamingEncodeOnWin32Compound,
} from "./config.js";
import type { EngineConfig } from "./config.js";
import { isLowMemorySystem } from "./services/systemMemory.js";
@@ -518,6 +519,216 @@ describe("resolveConfig", () => {
});
});
describe("shouldAutoDisableStreamingEncodeOnWin32Compound (helper)", () => {
// Baseline: field-signal compound — win32 + software-GPU forced + workers=1,
// duration unknown, user hasn't touched the env / overrides.
const compound = {
platform: "win32" as NodeJS.Platform,
softwareGpuForced: true,
workers: 1,
compositionDurationSec: undefined as number | undefined,
userExplicitlySet: false,
};
it("triggers on the field-signal compound (win32 + software-GPU + workers=1)", () => {
expect(shouldAutoDisableStreamingEncodeOnWin32Compound(compound)).toBe(true);
});
it("does NOT trigger on linux or darwin (platform gate)", () => {
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({ ...compound, platform: "linux" }),
).toBe(false);
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({ ...compound, platform: "darwin" }),
).toBe(false);
});
it("does NOT trigger without software-GPU forced (bypass on hardware paths)", () => {
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({ ...compound, softwareGpuForced: false }),
).toBe(false);
});
it("does NOT trigger with parallel workers (workers > 1 has a different failure surface)", () => {
expect(shouldAutoDisableStreamingEncodeOnWin32Compound({ ...compound, workers: 2 })).toBe(
false,
);
expect(shouldAutoDisableStreamingEncodeOnWin32Compound({ ...compound, workers: 4 })).toBe(
false,
);
});
it("does NOT trigger when the user explicitly set enableStreamingEncode (escape hatch)", () => {
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({ ...compound, userExplicitlySet: true }),
).toBe(false);
});
it("does NOT trigger for short (<=120s) compositions when duration is known", () => {
// 120s boundary is off (edge)
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({
...compound,
compositionDurationSec: 120,
}),
).toBe(false);
// 60s — clearly short, off
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({
...compound,
compositionDurationSec: 60,
}),
).toBe(false);
});
it("triggers when duration is known and exceeds 120s (heavy Windows composition)", () => {
// 121s — just past the boundary, on
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({
...compound,
compositionDurationSec: 121,
}),
).toBe(true);
// 156s — matches the field signal, on
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({
...compound,
compositionDurationSec: 156,
}),
).toBe(true);
});
it("triggers when duration is undefined (config-layer wire-up reduces to 3-cond)", () => {
// resolveConfig can't see composition duration at config time; the
// three-condition compound is conservative on its own.
expect(
shouldAutoDisableStreamingEncodeOnWin32Compound({
...compound,
compositionDurationSec: undefined,
}),
).toBe(true);
});
});
describe("enableStreamingEncode (Windows compound auto-disable wire-up)", () => {
const originalPlatform = process.platform;
function setPlatform(platform: NodeJS.Platform) {
Object.defineProperty(process, "platform", { value: platform, configurable: true });
}
afterEach(() => {
Object.defineProperty(process, "platform", { value: originalPlatform, configurable: true });
});
it("auto-disables on win32 + software-GPU + workers=1 + no user opt-in", () => {
setPlatform("win32");
setEnv("PRODUCER_BROWSER_GPU_MODE", "software");
setEnv("PRODUCER_MAX_WORKERS", "1");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(false);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBe(true);
});
it("leaves streaming-encode on when platform is linux", () => {
setPlatform("linux");
setEnv("PRODUCER_BROWSER_GPU_MODE", "software");
setEnv("PRODUCER_MAX_WORKERS", "1");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(true);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBeUndefined();
});
it("leaves streaming-encode on when workers > 1", () => {
setPlatform("win32");
setEnv("PRODUCER_BROWSER_GPU_MODE", "software");
setEnv("PRODUCER_MAX_WORKERS", "4");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(true);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBeUndefined();
});
it("respects explicit env opt-in (PRODUCER_ENABLE_STREAMING_ENCODE=true) on the compound", () => {
setPlatform("win32");
setEnv("PRODUCER_BROWSER_GPU_MODE", "software");
setEnv("PRODUCER_MAX_WORKERS", "1");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
setEnv("PRODUCER_ENABLE_STREAMING_ENCODE", "true");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(true);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBeUndefined();
});
it("respects programmatic override enableStreamingEncode=true on the compound", () => {
setPlatform("win32");
setEnv("PRODUCER_BROWSER_GPU_MODE", "software");
setEnv("PRODUCER_MAX_WORKERS", "1");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig({ enableStreamingEncode: true });
expect(config.enableStreamingEncode).toBe(true);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBeUndefined();
});
it("triggers via disableGpu on win32 + workers=1 (browserGpuMode may still be 'auto')", () => {
// --disable-gpu path: browserGpuMode may not be literal "software" but
// Chrome is still routed to CPU raster. Field-signal compound applies.
setPlatform("win32");
unsetEnv("PRODUCER_BROWSER_GPU_MODE");
setEnv("PRODUCER_DISABLE_GPU", "true");
setEnv("PRODUCER_MAX_WORKERS", "1");
unsetEnv("PRODUCER_LOW_MEMORY_MODE");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(false);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBe(true);
});
it("triggers via lowMemoryMode alone on win32 + workers=1 (screenshot capture implied)", () => {
// --low-memory-mode implies screenshot capture. Compound applies even
// if browserGpuMode is not literal "software" (defense-in-depth: matches
// the OR semantics in `softwareGpuForced`).
setPlatform("win32");
unsetEnv("PRODUCER_BROWSER_GPU_MODE");
unsetEnv("PRODUCER_DISABLE_GPU");
setEnv("PRODUCER_MAX_WORKERS", "1");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(false);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBe(true);
});
it("does not trigger when concurrency is 'auto' (workers not explicitly pinned)", () => {
// Config-layer sees `concurrency === "auto"`, not a number — the
// helper's numeric workers check treats NaN as "unknown, don't trigger".
// Downstream workers may still resolve to 1 via lowMemoryMode, but the
// config-time clamp is deliberately conservative.
setPlatform("win32");
setEnv("PRODUCER_BROWSER_GPU_MODE", "software");
unsetEnv("PRODUCER_MAX_WORKERS");
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");
unsetEnv("PRODUCER_ENABLE_STREAMING_ENCODE");
const config = resolveConfig();
expect(config.enableStreamingEncode).toBe(true);
expect(config.streamingEncodeAutoDisabledOnWin32Compound).toBeUndefined();
});
});
describe("lowMemoryMode", () => {
it("forces on for truthy PRODUCER_LOW_MEMORY_MODE values", () => {
setEnv("PRODUCER_LOW_MEMORY_MODE", "true");