first commit

This commit is contained in:
douboer
2026-03-21 18:57:10 +08:00
commit c49aa1a5e9
570 changed files with 107167 additions and 0 deletions

View File

@@ -0,0 +1,292 @@
import { describe, expect, it } from "vitest";
const {
resolveTerminalStdoutOverlayDecision,
resolveTerminalStdoutRenderDecision,
shouldDeferTerminalStdoutRender
} = require("./terminalStdoutRenderPolicy.js");
describe("terminalStdoutRenderPolicy", () => {
it("小 backlog 不会延后视图提交", () => {
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 4096,
pendingReplayBytes: 1024,
nextSlicesSinceLastRender: 1,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toBe(false);
});
it("中等 backlog 会先累计到阈值再提交", () => {
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 24 * 1024,
pendingReplayBytes: 3 * 1024,
nextSlicesSinceLastRender: 3,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toBe(true);
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 24 * 1024,
pendingReplayBytes: 8 * 1024,
nextSlicesSinceLastRender: 3,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toBe(false);
});
it("大 backlog 会使用更高阈值,避免频繁整包 setData", () => {
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 512 * 1024,
pendingReplayBytes: 16 * 1024,
nextSlicesSinceLastRender: 12,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toBe(true);
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 512 * 1024,
pendingReplayBytes: 16 * 1024,
nextSlicesSinceLastRender: 32,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toBe(false);
});
it("用户输入或终端响应存在时必须立即提交", () => {
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 512 * 1024,
pendingReplayBytes: 1024,
nextSlicesSinceLastRender: 1,
pendingResponseCount: 1,
yieldedToUserInput: false
})
).toBe(false);
expect(
shouldDeferTerminalStdoutRender({
remainingBytes: 512 * 1024,
pendingReplayBytes: 1024,
nextSlicesSinceLastRender: 1,
pendingResponseCount: 0,
yieldedToUserInput: true
})
).toBe(false);
});
it("会给出本轮提交或延后的决策原因,便于诊断 render 频率", () => {
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 512 * 1024,
pendingReplayBytes: 1024,
nextSlicesSinceLastRender: 1,
pendingResponseCount: 0,
yieldedToUserInput: true
})
).toMatchObject({
defer: false,
reason: "user_input",
policy: "interactive"
});
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 24 * 1024,
pendingReplayBytes: 3 * 1024,
nextSlicesSinceLastRender: 3,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toMatchObject({
defer: true,
reason: "defer_backlog",
policy: "medium_backlog"
});
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 24 * 1024,
pendingReplayBytes: 8 * 1024,
nextSlicesSinceLastRender: 3,
pendingResponseCount: 0,
yieldedToUserInput: false
})
).toMatchObject({
defer: false,
reason: "pending_bytes_threshold",
policy: "medium_backlog"
});
});
it("render 冷却期间即使进入尾段,也会继续延后视图提交", () => {
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 4096,
pendingReplayBytes: 2048,
nextSlicesSinceLastRender: 2,
pendingResponseCount: 0,
yieldedToUserInput: false,
timeSinceLastRenderMs: 80,
taskDone: false
})
).toMatchObject({
defer: true,
reason: "render_cooldown",
policy: "medium_backlog"
});
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 4096,
pendingReplayBytes: 2048,
nextSlicesSinceLastRender: 2,
pendingResponseCount: 0,
yieldedToUserInput: false,
timeSinceLastRenderMs: 280,
taskDone: false
})
).toMatchObject({
defer: false,
reason: "remaining_below_threshold",
policy: "medium_backlog"
});
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 0,
pendingReplayBytes: 1024,
nextSlicesSinceLastRender: 2,
pendingResponseCount: 0,
yieldedToUserInput: false,
timeSinceLastRenderMs: 20,
taskDone: true
})
).toMatchObject({
defer: false,
reason: "task_complete"
});
});
it("高 backlog 时会进入更激进的降级模式,优先丢弃中间帧", () => {
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 4096,
pendingReplayBytes: 4096,
nextSlicesSinceLastRender: 4,
pendingResponseCount: 0,
yieldedToUserInput: false,
timeSinceLastRenderMs: 600,
taskDone: false,
totalRawBytes: 80 * 1024,
pendingStdoutBytes: 48 * 1024,
pendingStdoutSamples: 160,
schedulerWaitMs: 2400,
activeStdoutAgeMs: 1800
})
).toMatchObject({
defer: true,
reason: "defer_critical_backlog",
policy: "critical_backlog"
});
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 4096,
pendingReplayBytes: 28 * 1024,
nextSlicesSinceLastRender: 4,
pendingResponseCount: 0,
yieldedToUserInput: false,
timeSinceLastRenderMs: 600,
taskDone: false,
totalRawBytes: 80 * 1024,
pendingStdoutBytes: 48 * 1024,
pendingStdoutSamples: 160,
schedulerWaitMs: 2400,
activeStdoutAgeMs: 1800
})
).toMatchObject({
defer: false,
reason: "pending_bytes_threshold",
policy: "critical_backlog"
});
expect(
resolveTerminalStdoutRenderDecision({
remainingBytes: 4096,
pendingReplayBytes: 4096,
nextSlicesSinceLastRender: 24,
pendingResponseCount: 0,
yieldedToUserInput: false,
timeSinceLastRenderMs: 600,
taskDone: false,
totalRawBytes: 80 * 1024,
pendingStdoutBytes: 48 * 1024,
pendingStdoutSamples: 160,
schedulerWaitMs: 2400,
activeStdoutAgeMs: 1800
})
).toMatchObject({
defer: false,
reason: "slice_threshold",
policy: "critical_backlog"
});
});
it("stdout 持续输出时会对 overlay 做节流,但最终一帧仍会同步", () => {
expect(
resolveTerminalStdoutOverlayDecision({
isFinalRender: false,
yieldedToUserInput: false,
overlayPassCount: 0,
timeSinceLastOverlayMs: 0
})
).toMatchObject({
sync: true,
reason: "first_render"
});
expect(
resolveTerminalStdoutOverlayDecision({
isFinalRender: false,
yieldedToUserInput: false,
overlayPassCount: 2,
timeSinceLastOverlayMs: 80
})
).toMatchObject({
sync: false,
reason: "overlay_throttled"
});
expect(
resolveTerminalStdoutOverlayDecision({
isFinalRender: false,
yieldedToUserInput: false,
overlayPassCount: 2,
timeSinceLastOverlayMs: 260
})
).toMatchObject({
sync: true,
reason: "overlay_cooldown_elapsed"
});
expect(
resolveTerminalStdoutOverlayDecision({
isFinalRender: true,
yieldedToUserInput: false,
overlayPassCount: 2,
timeSinceLastOverlayMs: 80
})
).toMatchObject({
sync: true,
reason: "task_complete"
});
});
});