fix(producer): open a fresh segmented session when the probe has risk frames (#6434)

* fix(producer): open a fresh segmented session when the probe has risk frames

Since #6318 the gate-check probe is planned with deFrameFallback: true, so
it can carry deRiskFrames. The segmented stage reuses that probe for its
first session and captures every frame with captureFrameToBuffer, which
cannot hand a risk frame to a screenshot session: the first one throws
"frame needs screenshot capture, which this capture path cannot hand over"
and the segmented route has no drawElement catch, so the render fails.

Close such a probe and open a fresh segmented session instead; those are
created with deFrameFallback: false and keep the whole-render screenshot
fallback.

— Via

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(producer): name the risk-frame probe condition instead of commenting it

The comment ratchet does not allow a file's comment share to rise.

— Via

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-10-26 21:07:19 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 1df003dfb7
commit e47fdad7d0
2 changed files with 36 additions and 0 deletions
@@ -315,6 +315,37 @@ describe("runCaptureSegmentedStage", () => {
});
});
it("does not capture on a probe that left frames to a screenshot session", async () => {
closeCaptureSession.mockClear();
const probeSession = {
...fakeStageInput({ totalFrames: 1 }).probeSession,
captureMode: "drawelement" as const,
workerEncodeEnabled: true,
deRiskFrames: new Set([2]),
};
const capturedOn = new Set<unknown>();
const captureFrame = mock(async (session: unknown) => {
capturedOn.add(session);
return { buffer: Buffer.alloc(1) };
});
const result = await runCaptureSegmentedStage({
...fakeStageInput({ totalFrames: 6 }),
probeSession: probeSession as never,
segmentFrames: 3,
segmentDir: join(fixtureRoot, "risk-probe"),
deps: {
spawnEncoder: mock(async () => okEncoder()),
captureFrame,
concat: mock(async () => ({ success: true as const })),
closeSession: mock(async () => {}),
removeFile: () => {},
},
});
expect(result.success).toBe(true);
expect(capturedOn.has(probeSession)).toBe(false);
expect(closeCaptureSession.mock.calls.map((c) => c[0])).toContain(probeSession);
});
it("skips completed segments and still concats all of them in order", async () => {
const stableDir = join(fixtureRoot, "stable");
const spawned: string[] = [];
@@ -291,6 +291,11 @@ function defaultSessionFactory(input: CaptureSegmentedStageInput): SessionFactor
let probeSession = input.probeSession;
return {
create: async () => {
const probeCannotCaptureEveryFrame = Boolean(probeSession?.deRiskFrames?.size);
if (probeSession && probeCannotCaptureEveryFrame) {
await closeCaptureSession(probeSession).catch(() => {});
probeSession = null;
}
const session = probeSession ?? (await openSegmentedSession(input));
if (probeSession) {
openSegmentedSessionReuse(input, probeSession);